MyBatis(详)

1. 简介

特性

  • 支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
  • 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  • 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java
    Objects,普通的Java对象)映射成数据库中的记录
  • 是一个 半自动的ORM(Object Relation Mapping)框架

和其它持久化层技术对比

  • JDBC
    • SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate 和 JPA
    • 操作简便,开发效率高
    • 程序中的长难复杂 SQL 需要绕过框架
    • 内部自动生产的 SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • MyBatis
    • 轻量级,性能出色
    • SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于HIbernate,但是完全能够接受

2. 搭建

1. 依赖

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

2. 核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

3. 映射文件

<?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="org.mybatis.example.BlogMapper">
  <insert id="insertUser">
    insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')
  </select>
</mapper>

3. mapper接口

public interface UserMapper {
  int insertUser();
}

4. 测试

//读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//创建SqlSessionFactoryBuilder对象 
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象 
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务 
//SqlSession sqlSession = sqlSessionFactory.openSession(); 
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交 
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//通过代理模式创建UserMapper接口的代理实现类对象 
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配 映射文件中的SQL标签,并执行标签中的SQL语句 
int result = userMapper.insertUser(); 
//sqlSession.commit(); 
System.out.println("结果:"+result);
  • SqlSession 代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
  • SqlSessionFactory “生产” SqlSession的 “工厂”

3. 核心配置文件详解

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--MyBatis核心配置文件中,标签的顺序: 
    	properties?,settings?,typeAliases?,typeHandlers?, objectFactory?,
    	objectWrapperFactory?,reflectorFactory?, 
    	plugins?,environments?,databaseIdProvider?,mappers? 
    -->
    <!--引入properties文件-->
    <properties resource="jdbc.properties" />
    <!--设置类型别名-->
    <typeAliases>
        <!--typeAlias:设置某个类型的别名 
        	属性:
        		type:设置需要设置别名的类型 
        		alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名 且不区分大小写 
        -->
        <!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>-->
        <!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写-->
        <package name="com.atguigu.mybatis.pojo"/>
    </typeAliases>
    <!--environments:配置多个连接数据库的环境 
    	属性:
    		default:设置默认使用的环境的id 
    -->
    <environments default="development">
        <!--environment:配置某个具体的环境 
        	属性:
        		id:表示连接数据库的环境的唯一标识,不能重复 
        -->
        <environment id="development">
            <!--transactionManager:设置事务管理方式 
            	属性:
            		type="JDBC|MANAGED" 
	            		JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
	            		MANAGED:被管理,例如Spring 
	        -->
            <transactionManager type="JDBC"/>
            <!--dataSource:配置数据源 
            	属性:
            		type:设置数据源的类型 type="POOLED|UNPOOLED|JNDI" 
	            		POOLED:表示使用数据库连接池缓存数据库连接 
	            		UNPOOLED:表示不使用数据库连接池 
	            		JNDI:表示使用上下文中的数据源 
            -->
            <dataSource type="POOLED">
                <!--设置连接数据库的驱动-->
                <property name="driver" value="${jdbc.driver}"/>
                <!--设置连接数据库的连接地址-->
                <property name="url" value="${jdbc.url}"/>
                <!--设置连接数据库的用户名-->
                <property name="username" value="${jdbc.username}"/>
                <!--设置连接数据库的密码-->
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssmserverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <!--<mapper resource="mappers/UserMapper.xml"/>-->
        <!--以包为单位引入映射文件 
        	要求: 
        		1、mapper接口所在的包要和映射文件所在的包一致 
        		2、mapper接口要和映射文件的名字一致 
        -->
        <package name="com.atguigu.mybatis.mapper"/>
    </mappers>

4. 增删改查

<!--int insertUser();-->
<insert id="insertUser"> 
	insert into t_user values(null,'admin','123456',23,'男') 
</insert>

<!--int deleteUser();-->
<delete id="deleteUser"> 
	delete from t_user where id = 7 
</delete>

<!--int updateUser();-->
<update id="updateUser"> 
	update t_user set username='ybc',password='123' where id = 6 
</update>

<!--User getUserById();-->
<select id="getUserById" resultType="com.atguigu.mybatis.bean.User"> 
	select * from t_user where id = 2 
</select>

<!--List<User> getUserList();-->
<select id="getUserList" resultType="com.atguigu.mybatis.bean.User"> 
	select * from t_user 
</select>
  • 查询的标签select必须设置属性resultTyperesultMap,用于设置实体类和数据库表的映射关系
  • resultType:自动映射,用于属性名和表中字段名一致的情况
  • resultMap:自定义映射,用于一对多或多对一字段名和属性名不一致的情况

5. 获取参数值的两种方式

${} 和 #{}

  • ${} 的本质就是字符串拼接
    #{} 的本质就是占位符赋值
  • ${} 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号
    #{} 使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号

1. 单个字面量类型的参数

  • 若mapper接口中的方法参数为单个的字面量类型

  • 此时可以使用 ${}#{}任意的名称获取参数的值,注意 ${}需要手动加单引号

    User getUserByUserName(String username);
    
        <select id="getUserByUserName" resultType="user">
            select * from t_user where username = '${username}';
        </select>
    

2. 多个字面量类型的参数

  • 若mapper接口中的方法参数为多个

  • 此时MyBatis会自动将这些参数放在一个map集合中,以**arg0,arg1…**为键,以参数为值;以param1,param2…为键,以参数为值

  • 因此只需要通过${}#{}访问map集合的就可以获取相
    对应的值,注意${}需要手动加单引号

    User getLogin(String username,String password);
    
        <!--User getLogin(String username,String password);-->
        <select id="getLogin" resultType="User">
            select * from t_user where username = #{arg0} and password = #{arg1};
        </select>
    

3. map集合类型的参数

  • 若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中

  • 只需要通过${}#{}访问map集合的就可以获取相对应的值,注意${}需要手动加单引号

    User checkLogin(Map map);
    
        <select id="checkLogin" resultType="user">
            select * from t_user where username = #{username} and password = #{password};
        </select>
    

4. 实体类类型的参数

  • 若mapper接口中的方法参数为实体类对象时

  • 此时可以使用${}#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号

    int insertUser(User user);
    
        <insert id="insertUser">
            insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email});
        </insert>
    

5. 使用@Param标识参数

  • 可以通过@Param注解标识mapper接口中的方法参数

  • 此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以param1,param2…为键,以参数为值

  • 只需要通过${}#{}访问map集合的就可以获取相对应的值,注意${}需要手动加单引号

    User checkLoginByParam(@Param("username") String username,@Param("password") String password);
    
        <select id="checkLoginByParam" resultType="user">
            select * from t_user where username = #{username} and password = #{password};
        </select>
    

6. MyBatis的各种查询功能

1. 查询一个实体类对象

User getUserById(@Param("id") int id);
<select id="getUserById" resultType="User"> 
	select * from t_user where id = #{id} 
</select>

2. 查询一个list集合

List<User> getUserList();
<select id="getUserList" resultType="User"> 
	select * from t_user 
</select>
  • 当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常TooManyResultsException
  • 但是若查询的数据只有一条,可以使用实体类或集合作为返回值

3. 查询单个数据

int getCount();
<select id="getCount" resultType="_integer"> 
	select count(id) from t_user 
</select>

4. 查询一条数据为map集合

Map<String, Object> getUserToMap(@Param("id") int id);
<!--结果: {password=123456, sex=男 , id=1, age=23, username=admin}-->
<select id="getUserToMap" resultType="map"> 
	select * from t_user where id = #{id} 
</select>

5. 查询多条数据为map集合

方式一
List<Map<String, Object>> getAllUserToMap();
<select id="getAllUserToMap" resultType="map"> 
	select * from t_user 
</select>
方式二
@MapKey("id") 
Map<String, Object> getAllUserToMap();
  • @MapKey 设置map集合的键,值是每条数据所对应的 map集合
<!-- { 
		1={password=123456, sex=男, id=1, age=23, username=admin}, 
		2={password=123456, sex=男, id=2, age=23, username=张三}, 
		3={password=123456, sex=男, id=3, age=23, username=张三} }
-->
<select id="getAllUserToMap" resultType="map"> 
	select * from t_user 
</select>

7. 特殊SQL的执行

1. 模糊查询

List<User> testMohu(@Param("mohu") String mohu);
<select id="testMohu" resultType="User">
    <!--select * from t_user where username like '%${mohu}%'-->
    <!--select * from t_user where username like concat('%',#{mohu},'%')--> 
	select * from t_user where username like "%"#{mohu}"%" 
</select>

2. 批量删除

int deleteMore(@Param("ids") String ids);
<delete id="deleteMore"> 
	delete from t_user where id in (${ids}) 
</delete>

3. 动态设置表名

List<User> getAllUser(@Param("tableName") String tableName);
<select id="getAllUser" resultType="User"> 
	select * from ${tableName}
</select>

4. 添加功能获取自增的主键

需求
  • 需求:在插入一条数据后需要获取该条记录的主键
  • 方案
    • 在一个单系统中常见的方法M是设置表中主键为自动递增,每次插入后,mybatis会将自动生成的主键赋值给指定的实体类字段
      • 若数据库支持自动生成主键的字段(比如 MySQLSQL Server),则可以设置useGeneratedKeys=”true”,然后再把keyProperty设置到目标属性上
        (局限性很大、不利于项目后期扩展,实际开发中不推荐使用)

        int insertUser(User user);
        
        <!--int insertUser(User user);-->
        <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> 
        	insert into 
        		t_user 
        	values(
        		null,
        		#{username},
        		#{password},
        		#{age},
        		#{sex}) 
        </insert>
        
        @Service
        public class UserService {
            @Autowired
            private UserMapper userMapper;
        
            public int insertUser(User user) {
                return userMapper.insertUser(user);
            }
        }
        

        useGeneratedKeys设置为true后,mybatis会使用JDBC的getGeneratedkeys方法获取由数据库内部自动生成的主键,并将该值赋值给由keyProperty指定的字段;

      • 对于不支持自增型主键的数据库(例如Oracle),则要先通过序列来模拟自增,每次插入数据前先从序列中拿到自增ID
        (无论是单例项目还是分布式项目都适用)

    • 在分布式系统中,则需要生成全局唯一主键ID

8. 自定义映射resultMap

1. resultMap处理字段和属性的映射关系

<!--resultMap:设置自定义映射 
	属性: 
		id:表示自定义映射的唯一标识 
		type:查询的数据要映射的实体类的类型 
	子标签: 
		id:设置主键的映射关系 
		result:设置普通字段的映射关系
		association:设置多对一的映射关系 
		collection:设置一对多的映射关系 
			属性: 
				property:设置映射关系中实体类中的属性名 
				column:设置映射关系中表中的字段名 
-->
<resultMap id="userMap" type="User">
    <id property="id" column="id"></id>
    <result property="userName" column="user_name"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
</resultMap>

<!--List<User> testMohu(@Param("mohu") String mohu);-->
<select id="testMohu" resultMap="userMap">
    <!--select * from t_user where username like '%${mohu}%'--> 
	select 
		id,
		user_name,
		password,
		age,
		sex 
	from 
		t_user 
	where 
		user_name like concat('%',#{mohu},'%') 
</select>

场景

字段名(_连接)与实体类名(小驼峰)不一致的情况,有以下两种处理方式:

  • 查询的时候,给字段 取别名(as
  • 在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰

    在spring中的配置:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD SQL Map Config 3.0//EN"  
    	"http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<!-- 配置mybatis自动转换为驼峰式命名 -->
    	<settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
    </configuration>
    
    在springboot中的配置:
    mybatis:
      # mapper.xml所在位置
      mapper-locations: 
        - classpath*:mapper/read/*.xml
        - classpath*:mapper/write/*.xml
      # mapper接口所在包
      base-packages:
        - com.yinhai.hipay.**.mapper.read
        - com.yinhai.hipay.**.mapper.write
      # 指定POJO扫描包来让mybatis自动扫描到自定义的POJO
      type-aliases-package: com.example.entity
      configuration:
        # 自动将_类型的字段名转换为驼峰
        map-underscore-to-camel-case: true
        cache-enabled: false
    

2. 多对一映射处理

场景模拟: 查询员工信息以及员工所对应的部门信息。

级联方式处理映射关系

<resultMap id="empDeptMap" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="age" property="age"></result>
    <result column="sex" property="sex"></result>
    <result column="did" property="dept.did"></result>
    <result column="dname" property="dept.dname"></result>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap"> 
	select 
		emp.*,
		dept.* 
	from 
		t_emp emp 
	left join 
		t_dept dept 
	on 
		emp.did = dept.did 
	where 
		emp.eid = #{eid} 
</select>

使用association处理映射关系

<resultMap id="empDeptMap" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="age" property="age"></result>
    <result column="sex" property="sex"></result>
	
    <association property="dept" javaType="Dept">
        <id column="did" property="did"></id>
        <result column="dname" property="dname"></result>
    </association>
	
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap"> 
	select 
		emp.*,
		dept.* 
	from 
		t_emp emp 
	left join 
		t_dept dept 
	on 
		emp.did = dept.did 
	where 
		emp.eid = #{eid} 
</select>

分步查询

查询员工信息

Emp getEmpByStep(@Param("eid") int eid);
<resultMap id="empDeptStepMap" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="age" property="age"></result>
    <result column="sex" property="sex"></result>
    <association 
				 property="dept" 
				 select="com.atguigu.MyBatis.mapper.DeptMapper.getEmpDeptByStep" 
				 column="did">
	</association>
</resultMap>

<select id="getEmpByStep" resultMap="empDeptStepMap"> 
	select 
		* 
	from 
		t_emp 
	where 
		eid = #{eid} 
</select>

根据员工所对应的部门id查询部门信息

Dept getEmpDeptByStep(@Param("did") int did);
<select id="getEmpDeptByStep" resultType="Dept"> 
	select 
		* 
	from 
		t_dept 
	where 
		did = #{did} 
</select>

3. 一对多映射处理

collection

Dept getDeptEmpByDid(@Param("did") int did);
<resultMap id="deptEmpMap" type="Dept">
    <id property="did" column="did"></id>
    <result property="dname" column="dname"></result>
    <!--ofType:设置collection标签所处理的集合属性中存储数据的类型 -->
    <collection property="emps" ofType="Emp">
        <id property="eid" column="eid"></id>
        <result property="ename" column="ename"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
    </collection>
</resultMap>
<!--Dept getDeptEmpByDid(@Param("did") int did);-->
<select id="getDeptEmpByDid" resultMap="deptEmpMap"> 
	select 
		dept.*,
		emp.* 
	from 
		t_dept dept 
	left join 
		t_emp emp 
	on 
		dept.did = emp.did 
	where 
		dept.did = #{did} 
</select>

分步查询

查询部门信息

Dept getDeptByStep(@Param("did") int did);
<resultMap id="deptEmpStep" type="Dept">
    <id property="did" column="did"></id>
    <result property="dname" column="dname"></result>
    <collection 
				property="emps" 
				fetchType="eager" 
				select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" 
				column="did">
	</collection>
</resultMap>
<!--Dept getDeptByStep(@Param("did") int did);-->
<select id="getDeptByStep" resultMap="deptEmpStep"> 
	select 
		* 
	from 
		t_dept 
	where 
		did = #{did} 
</select>

根据部门id查询部门中的所有员工

List<Emp> getEmpListByDid(@Param("did") int did);
<select id="getEmpListByDid" resultType="Emp"> 
	select 
		* 
	from 
		t_emp 
	where 
		did = #{did} 
</select>

分步查询的优点

可以实现延迟加载

  • lazyLoadingEnabled
    延迟加载的全局开关。当开启时,所有关联对象都会延迟加载

  • aggressiveLazyLoading
    当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载

  • spring中的配置

    <configuration>
    	<!-- 全局参数的配置 -->
        <settings>
                <!--打开延迟加载的开关  -->
            <setting name="lazyLoadingEnabled" value="true"/>
                <!--将积极加载改为消极加载及按需加载  -->
            <setting name="aggressiveLazyLoading" value="false"/>
        </settings>
    </configuration>
    
  • springboot中的配置

    mybatis:
     configuration:
      lazyLoadingEnabled: true
      aggressiveLazyLoading: false    
    
  • 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过associationcollection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加载)|eager(立即加载)"

9. 动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了 解决 拼接SQL语句字符串时的痛点问题。

1. if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之 标签中的内容不会执行

<select id="getEmpListByMoreTJ" resultType="Emp"> 
	select * from t_emp where 1=1 
    <if test="ename != '' and ename != null"> 
		and ename = #{ename} 
	</if>
    <if test="age != '' and age != null"> 
		and age = #{age} 
	</if>
    <if test="sex != '' and sex != null"> 
		and sex = #{sex} 
	</if>
</select>

2. where

where和if一般结合使用:

  • 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
  • 若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
<select id="getEmpListByMoreTJ2" resultType="Emp"> select * from t_emp 
    <where>
        <if test="ename != '' and ename != null"> 
			ename = #{ename} 
		</if>
        <if test="age != '' and age != null"> 
			and age = #{age} 
		</if>
        <if test="sex != '' and sex != null"> 
			and sex = #{sex} 
		</if>
    </where>
</select>

3. trim

trim用于去掉或添加标签中的内容

  • prefix:在trim标签中的内容的前面添加某些内
  • prefixOverrides:在trim标签中的内容的前面去掉某些内
  • suffix:在trim标签中的内容的后面添加某些内
  • suffixOverrides:在trim标签中的内容的后面去掉某些内容
<select id="getEmpListByMoreTJ" resultType="Emp"> 
	select * from t_emp 
    <trim prefix="where" suffixOverrides="and">
        <if test="ename != '' and ename != null">
			ename = #{ename} and 
		</if>
        <if test="age != '' and age != null"> 
			age = #{age} and 
		</if>
        <if test="sex != '' and sex != null"> 
			sex = #{sex} 
		</if>
    </trim>
</select>

4. choose、when、otherwise

choose、when、 otherwise相当于if...else if..else

<!--List<Emp> getEmpListByChoose(Emp emp);-->
<select id="getEmpListByChoose" resultType="Emp"> select 
    <include refid="empColumns"></include> from t_emp 
    <where>
        <choose>
            <when test="ename != '' and ename != null"> 
				ename = #{ename} 
			</when>
            <when test="age != '' and age != null"> 
				age = #{age} 
			</when>
            <when test="sex != '' and sex != null"> 
				sex = #{sex} 
			</when>
            <when test="email != '' and email != null"> 
				email = #{email} 
			</when>
        </choose>
    </where>
</select>

5. foreach

<!--int insertMoreEmp(List<Emp> emps);-->
<insert id="insertMoreEmp"> insert into t_emp values 
    <foreach collection="emps" item="emp" separator=","> 
		(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null) 
	</foreach>
</insert>

<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray"> 
	delete from t_emp where 
    <foreach collection="eids" item="eid" separator="or"> 
		eid = #{eid} 
	</foreach>
</delete>

<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray"> 
	delete from t_emp where eid in 
    <foreach collection="eids" item="eid" separator="," open="(" close=")">
		#{eid} 
	</foreach>
</delete>

6. SQL片段

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入。

<sql id="empColumns"> 
	eid,ename,age,sex,did 
</sql> 
select 
	<include refid="empColumns"></include> 
from t_emp

10. MyBatis的缓存

1. MyBatis的一级缓存

一级缓存是SqlSession级别的(默认开启),通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

使一级缓存失效的四种情况:

  • 不同的SqlSession对应不同的一级缓存
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作
  • 同一个SqlSession两次查询期间手动清空了缓存

2. MyBatis的二级缓存

二级缓存是SqlSessionFactory级别(默认开启),通过同一个SqlSessionFactory创建的SqlSession查询的结果会被 缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

二级缓存开启的条件:

  • 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  • 在映射文件中设置标签<cache/>
  • 二级缓存必须在SqlSession关闭或提交之后有效
  • 查询的数据所转换的实体类类型必须实现序列化的接口

使二级缓存失效的情况:

  • 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

3. 二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:

  • eviction 缓存回收策略,默认的是 LRU
    • LRU(Least Recently Used):最近最少使用的——移除最长时间不被使用的对象
    • FIFO(First in First out):先进先出——按对象进入缓存的顺序来移除它们
    • SOFT:软引用——移除基于垃圾回收器状态和软引用规则的对象
    • WEAK:弱引用——更积极地移除基于垃圾收集器状态和弱引用规则的对象
  • flushInterval 刷新间隔,单位毫秒
    • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size 引用数目,正整数
    • 最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly 只读, true/false
    • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势
    • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false

4. MyBatis缓存查询数据

11. 补充



MyBatis整合Ehcache详细介绍


MyBatis的逆向工程


MyBatis分页插件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

364.99°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值