一、缓存
一级缓存
默认开启。
一级缓存也称之为sesssion级别的缓存, 也就是说在一次回话中执行相同的查询时,会首先查询缓存, 如果缓存没有数据,则直接查询数据库,并且个给缓存放一份,如果有就直接查询缓存。
所有的增删改操作都会清空缓存。
还有一些操作也会清空缓存:
①手动清理缓存 ② 提交了事务 ③管理链接,并且开启了新的连接
session级别的缓存:在一个sqlSession的一个事务中,多次查询相同的数据,会被缓存。
二级缓存
二级缓存又叫sessionFactory级别的缓存。
可以在两个session(事务)之间共享数据。
二级缓存是默认不开启的,需要手动开启。
我们可以在映射文件中开启二级缓存:
eviction:清除缓存的策略,一般都是配置FIFO。
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。flushInterval :设置刷新时间,以毫秒单位,如果不设置就会不刷新。 size:应用数目。默认是1024。 readOnly:是否只读。
@Test
public void testCache2(){
SqlSession sqlSession = factory.openSession();
Student st = sqlSession.selectOne("com.st.mapper.StudentMapper.queryByStudentId",1L);
System.out.println(st.getStudentName());
sqlSession.clearCache();//清空
//关闭连接
sqlSession.close();
//重新打开一个sqlSession, 两个sqlSession之间不能共享一级缓存的内容,但是可以共享二级缓存的内容
sqlSession = factory.openSession();
Student st1 = sqlSession.selectOne("com.st.mapper.StudentMapper.queryByStudentId",1L);
System.out.println(st1.getStudentName());
//没有结束,就没有提交,也没有回滚
}
二、动态sql
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦
if标签
案例:多条件组合查询
根据学生的姓名和性别组合查询。
以前的做法: 在程序中使用java完成逻辑判断。当然还有 “where 1 = 1”
MyBatis的动态sql:
<!-- 动态sql -->
<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<select id="queryByNameAndGender" parameterType="student" resultMap="student">
select * from student where 1 = 1
<!-- test里面判断时,直接写属性名称 -->
<if test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</if>
<if test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</if>
</select>
测试:
@Test
public void testSql_if(){
Student student = new Student();
student.setStuGender(1);
student.setStudentName("三");
SqlSession sqlSession = factory.openSession();
List<Student> sts = sqlSession.selectList("com.st.mapper.StudentMapper.queryByNameAndGender",student);
for (Student st : sts){
System.out.println(st);
}
}
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
案例:
查询学生,只按照一个条件查询,但是可以传入多个,如果某一个可以使用,则不再使用别的
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<select id="queryByNameAndGender1" parameterType="student" resultMap="stuResultMapping">
select * from student where 1 = 1
<!-- test里面判断时,直接写属性名称 -->
<choose>
<when test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</when>
<when test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</when>
<otherwise>
<!-- 这里可以有其他的条件 -->
</otherwise>
</choose>
</select>
多重的if else ,当一个条件满足之后,就不会在判断其他条件了。
测试:还是if的测试程序。
trim、where、set
where
处理where语句块的, 有了where标签,我们就不用使用“where 1 =1 ”。标签会自动判断,去掉多余的and。
案例:
<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<!-- where标签 -->
<select id="queryByNameAndGender2" parameterType="student" resultMap="stuResultMapping">
select * from student
<!-- 自动添加where语句块,并且删除多余的 “and” -->
<where>
<!-- test里面判断时,直接写属性名称 -->
<if test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</if>
<if test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</if>
</where>
</select>
set
处理update语句中的set部分。添加set字样,删除多余的“,”
案例:
<!-- set标签 -->
<update id="updateStudent" parameterType="student">
update student
<set>
<if test="studentName!=null and studentName!=''">
stuName=#{studentName},
</if>
<if test="loginPass!=null and loginPass!=''">
longinPass=#{loginPass},
</if>
<if test="stuGender!=null and stuGender!=-1">
stuGender=#{stuGender}
</if>
</set>
where stuId=#{stuId}
</update>
trim
和where等价的trim:
<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<!-- 和where等价的trim -->
<select id="queryByNameAndGender3" parameterType="student" resultMap="stuResultMapping">
select * from student
<!-- prefiex:最前面添加一个where字样 -->
<!-- prefixOverrides:取出前面多余的(and或者or)字样 -->
<trim prefix="where" prefixOverrides="and | or">
<!-- test里面判断时,直接写属性名称 -->
<if test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</if>
<if test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</if>
</trim>
</select>
和set等价的trim:
<!-- set标签 -->
<update id="updateStudent1" parameterType="student">
update student
<!-- prefix:添加set字样 suffixOverrides:删除多余的后缀(“,”) -->
<trim prefix="set" suffixOverrides=",">
<if test="studentName!=null and studentName!=''">
stuName=#{studentName},
</if>
<if test="loginPass!=null and loginPass!=''">
longinPass=#{loginPass},
</if>
<if test="stuGender!=null and stuGender!=-1">
stuGender=#{stuGender}
</if>
</trim>
where stuId=#{stuId}
</update>
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
_foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
提示** 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
查询指定班级编号的学生信息:
<!-- foreach标签 -->
<select id="queryStudentByClassIds" resultMap="stuResultMapping">
select * from student where classId in
<foreach collection="list" index="index" item="cid" separator="," open="(" close=")">
#{cid}
</foreach>
</select>
@Test
public void testSql_foreach(){
List<Long> cids=new ArrayList<Long>(Arrays.asList(new Long []{1L,3L,4L,5L}));
SqlSession sqlSession = factory.openSession();
List<Student> sts = sqlSession.selectList("com.st.mapper.StudentMapper.queryStudentByClassIds",cids);
for (Student st : sts){
System.out.println(st);
}
}