MyBatis

MyBatis

ORM

Object Relational Mapping 对象关系映射

原理:把Java中的对象(的属性)和数据库中的表(列)进行关联映射,简化了JDBC的增删改查操作

主流的ORM框架: MyBatis Hibernate

实体类与SQL语句之间建立映射关系

Mybatis

是Apache下的一个开源项目,前身是ibatis
,是一个半自动化的ORM的框架,基于SQL,简单易学

MyBatis 的搭建

  1. 新建动态web项目,导入jar包

  2. 在项目下新建资源目录resource,创建db.properties文件

  3. 在resource下创建mybatis的xml配置文件,

    • mybatis-3-config.dtd
      dtd文档类型声明:规定了mybatis的配置文件,里面必须包含哪些标签,标签必须有哪些属性.
  4. 封装mybatis操作数据库的工具类

    mybatis的工作原理:

    1. 通过mybatis封装的流读取mybatis的配置文件

    2. 创建SQLSessionFactoryBuilder对象

      • 生命周期:局部变量级别

      • 作用:创建SQLSessionFactory

    3. 通过步骤2得到SQLSessionFactory

      • 生命周期:和程序一致,只要程序运行SQLSessionFactory就存在

      • 作用:创建访问数据库的session

    4. 通过SQLSessionFactory得到session对象

      • 作用:通过session来完成数据库的增删改查操作
      • 生命周期:当session的关闭方法调用后,session消失.
      • [说明]在session关闭之前可以进行多次SQL操作,session是线程级别
    5. 创建实体类

      • 别名注解 属性名最好和列名一致
    6. 编写dao

      1. mybatis基于接口编程

      2. mybatis基于SQL

        编写实体类和表映射的文件

        在映射文件中,通过namespace把映射文件和接口关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.test.dao.UserDao">
<!– 接口中的每一个方法,在此映射方法中都要有与之关联的SQL语句 –>
<!– id:对应接口中的方法名
parameterType:方法的参数类型
对应insert update delete的返回值默认是int类型,无需设置
–>
<insert id="addUser" parameterType="User">
<!– 编写SQL语句 –>
insert into smbms_user(userCode,userName,userPassword)
values
(#{userCode},#{userName},#{userPassword});
</insert>
<update id="updateUser" parameterType="User">
update smbms_user
set userCode=#{userCode},
userName=#{userName},
userPassword=#{userPassword}
where id = #{id};
</update>
<delete id="deleteUser" parameterType="User">
delete from smbms_user
where id = #{id};
</delete>
<!– 查询方法必须设置返回值类型 resultType –>
<select id="selectCount" resultType="int">
select count(id) from smbms_user;
</select>
<!– 默认情况下,表中的列名和对象的属性名会自动进行同名映射 –>
<select id="selectAll" resultType="User">
select * from smbms_user;
</select>
</mapper>

  1. 当实体类的属性名和表中的列名相同时,自动进行同名映射

    select节点需要设置返回值类型 resultType

  2. 当查询出的列和实体类的属性不相同时(名字不同,类型不同–>对象,对象集合),需要自定义resultMap

    1. 主键列:id标签;property:实体类的属性名;column:select与剧中的列名
    2. 非主键列:result标签;property;column;
  3. 实体类:

    ​ (1)User类中的角色: UserRole–一对一关系

    1. SQL语句一定是多表连接查询
    2. 一对一映射: <association property=”userRole2”
      JavaType=”UserRole” resultMap=”UserRoleMap” ></association>
    3. mybatis在查询的时候,查询smbms_user表的12条记录会创建12个user对象,同时为每个user对象创建一个对应的UserRole对象

    ​ (2)收货地址: List<Address> 一对多关系

    1. <collection property=”addresses” ofType=”Address”
      resultMap=”addressMap”></collection>
    2. mybatis在查询时,,查询smbms_user表的12条记录会创建12个user对象,同时为每个user对象创建一个List集合,集合里存放到是Address对象
    3. 当进行多表连接查询时,同名列最好命名别名,然后再resultMap映射时,使用别名
  4. 方法的参数是多个时的解决方案:

    1. 优先使用实体类存放多个参数
    2. 如果实体类中没有参数的属性,使用Map集合
    3. 使用 @Param注解 声明多个参数

MyBatis下的动态SQL编程

表达式获取方法的参数值,获取对象里的属性值 #{形参名/参数对象的属性名}

${形参名/参数对象的属性名}

  • 区别:
    1. #{} 先 预编译SQL语句,然后取值、赋值
      ${} 先取值、赋值 然后进行SQL语句的编译

    2. #{}
      在赋值时会判断值的类型,对字符串值自动添加’’,安全、防止SQL注入

      select * from smbms_user where userName =#{userName}
      select * from smbms_user where userName ='张华' ${} 只是进行赋值,需要自行加''  不安全
      
1
2
3
4
5
6
<where>
  <if test="userName!=null">
      and username like CONCAT("%",#{userName},"%"),
 </if>
</where>
-- 如果where,if里面有内容,才会加上where,if;

参数类型是数组或List集合,使用foreach迭代数组

1
2
3
4
5
6
7
8
9
<!--  迭代标签遍历数组 collection的值:array参数是数组,list参数是集合  -->
<select id="getAllUsersBy9" resultType="User">
 select id,userCode,userName,userPassword,address 
    from smbms_user 
    where userRole in
    <foreach collection="array" item="aryRole" open="(" close=")" separator=",">
       #{aryRole}
  </foreach> 
</select>
1
2
3
4
5
<!--配置自定义信息-->
   <settings>
       <!--   在控制台打印出sql     -->
       <setting name="logImpl"         value="STDOUT_LOGGING"></setting>
   </settings>

懒加载

1
2
3
4
5
6
7
8
9
10
<settings>
        <!--   打印出sql     -->
        <setting name="logImpl" value="STDOUT_LOGGING"></setting>

    &lt;!--    设置允许延迟加载    --&gt;
    &lt;setting name=&quot;lazyLoadingEnabled&quot; value=&quot;true&quot;&gt;&lt;/setting&gt;
    &lt;!--    true:允许
            false:默认值,不进行懒加载--&gt;
    &lt;setting name=&quot;aggressiveLazyLoading&quot; value=&quot;false&quot;&gt;&lt;/setting&gt;
&lt;/settings&gt;</code></pre></td>

需要导包

mybatis的缓存机制

  • 特点:
    • 提高了应用的效率
    • 缓存的数据容易过时
  • 场合:
    • 数据量较大
    • 缓存中数据的更新问题;如:当有添加操作时,缓存中的数据失效

mybatis中提供了二级缓存机制:

  • 一级缓存:session

    • 只在一个sqlSession中有效
    • 当提交事务(insert,update,delete)后,session中缓存的数据会清空
  • 二级缓存:

    • 在配置文件中启用二级缓存

      • 1
        <setting name="cacheEnabled" value="true"/>
    • 在对应的mapper.xml文件中启用二级缓存

      • 1
        <cache></cache>
    • 实体类实现可序列化的接口

    • 在mapper文件的某个方法中可以设置不使用二级缓存

      userCache=”false”

    • 当二级缓存启动后

      • 所有的select语句的查询结果都会被缓存
      • 当执行了insert,update,delete时,会清空对应的缓存
      • 缓存会使LRU(最近最少使用)算法收回数据

使用注解实现增删改查

  1. @select

  2. @update

  3. @delete

  4. @insert

  5. @Parameter

  6. 在配置文件中配置文件位置

    1
    <mapper class="cn.test.dao.UserDao2"/>

PageHelper

mybatis的分页插件,需要导包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void testPageHelper{
    int pageNum=0;
    int pageSize=2;
    Map<String,Object> param = new HashMap<>();
    param.put("name","小明");
    //PageHelper对紧随它之后的第一条语句起作用
    PageHelper.startPage(pageNum,pageSize,"id desc");//开始分页
    List<User> groupList = sqlSession.selectList("selectAllUsers",param);
    PageInfo<User> pageInfo = new PageInfo<>(groupList,5);//页码导航
    System.out.println("当前页码:"+pageInfo.getPageNum());
    System.out.println("每页:"+pageInfo.getPageSize());
    System.out.println("总数据:"+pageInfo.getTotal());
    System.out.println("总页数:"+pageInfo.getPages());
   System.out.println("页码导航:"+Arrays.toString(pageInfo.getNavigatepageNums()));
}
  • 在一个Mapper中引用另一个Mapper的ResultMap:

    1
    ResultMap='otherMapper.UserMap'
  • 在一个Mapper中引用另一个Mapper的sql语句

    1
    2
    3
    4
    <resultMap id='UserMap' type='User'>
        <id property='id' column='id'></id>
        <collection property='stuid' select='stuMapper.getAllStu' column='id'</collection>
    </resultMap>

    👆↑用的比较少