1.mybatis延迟加载策略
什么是延迟加载?
延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗
时间,所以可能造成用户等待时间变长,造成用户体验下降。
开启懒加载
<settings>
<!-- 开启全局懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
association延迟加载
1.在IScoreDao接口中增加
List<Score> findAllScoreWithStudentLazy();
2.在IScoreDao.xml 中增加
<!-- 定义封装StudentScore和user的resultMap -->
<resultMap id="findAllScoreWithStudentLazyMap" type="Score">
<id property="scoreid" column="scoreid"></id>
<result property="coursename" column="coursename"></result>
<result property="score" column="score"></result>
<!-- 一对一的关系映射:配置封装Student的内容-->
<association property="student" javaType="Student"
select="com.yyf.dao.IStudentDao.findStudentById" column="studentid" ***fetchType="lazy***>
</association>
</resultMap>
<select id="findAllScoreWithStudentLazy" resultMap="findAllScoreWithStudentLazyMap">
select * from score_tb;
</select>
select:为我们调用其他映射的id
column:为传递的参数
javaType:为查询到的java 数据类型
fetchType:是否使用懒加载,如果不设置与全局设置保持一致
3测试
IScoreDao scoreDao = sqlSession.getMapper(IScoreDao.class);
List<Score> scoreList = scoreDao.findAllScoreWithStudentLazy();
for (Score score:scoreList){
// 不调用学生相关信息,不请求查数据库
System.out.println("score:"+score.getScore());
// 调用学生信息,发起二次请求查询学生相关的数据库
//System.out.println("student:"+score.getStudent());
}
注意
默认情况mybatis开延迟加载只要调用toString()方法包括Object的object的都会触发懒加载可以通过设置一下解决
<!--解决 懒加载时 打印对象toString 触发 懒加载
lazyLoadTriggerMethods:指定哪个对象的方法触发一次延迟加载。默认值:equals,clone,hashCode,toString
-->
<setting name="lazyLoadTriggerMethods" value="false"/>
2.mybatis的缓存
缓存
暂时的存放常用小批量数据
特点:换窜数据不可靠(可能会丢失),存放热点数据(经常使用的数据)
优点:缓存大部分存在内存中,查询速度快
mybatis缓存
一级缓存:基于sqlSession,
二级缓存基于namespace,同一个namespace下所有数据可以共享
一个mapper xml 用自己的namespace,另外也可以多个mapper(dao接口)共享同一个二级缓存namespace
一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。一旦发生增删改,缓存立即失效
二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
缓存流程图
二级缓存的开启
1.在mybatis开启
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.在mapper 中开启二级缓存
<mapper namespace="com.wgz.dao.IStudentDao">
<!--开启二级缓存-->
<cache >
<property name="eviction" value="LRU" />
<property name="flushInterval" value="60000" />
<property name="size" value="1024" />
<property name="readOnly" value="false" />
</cache>
</mapper>
-
-
eviction
- 缓存回收策略,有这几种回收策略
- LRU - 最近最少回收,移除最长时间不被使用的对象
- FIFO - 先进先出,按照缓存进入的顺序来移除它们
- SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
- WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
默认是 LRU 最近最少回收策略
flushinterval
缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值readOnly
: 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改size
: 缓存存放多少个元素type
: 指定自定义缓存的全类名(实现Cache 接口即可)blocking
: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
3.使用缓存
- useCache=“true” 默认为true
<!--使用resultMap-->
<select id="findStudentById" parameterType="java.lang.Integer" resultType="student" useCache="true">
select * from student_tb where id=#{id}
</select>
注意
- 一级二级缓存调用顺序:先查二级缓存,再查一级缓存,再查数据库;即使在一个sqlSession中,也会先查二级缓存;一个namespace中的查询更是如此;
- 使用二级缓存的实体类必须实现序列化;方便存储
- sqlsession***只有关闭或者提交事务时才会把提交二级缓存,否则二级缓存不生效***
- sqlsession只要发生增删改就会把所有缓存清除,二级缓存只有当前命名空间发生增删改,命名空间的缓存才会清除
使用二级缓存,当一个session发生修改时,另一个session如果缓存过以前的查询结果可能会有脏数据
解决方法第一种.关闭一级缓存,并未查询的session改为自动提交
在spring中也不一定为发生,一般为单例的mapper每次创建新的sqlsession(若开启事务则时同一sqlsession),所以可以避免,不用担心
<!-- 将一级缓存修改为STATEMENT 不使用一级缓存
SESSION 使用一级缓存
-->
<setting name="localCacheScope" value="STATEMENT"/>
第二种:不使用缓存
<select id="findStudentById" parameterType="java.lang.Integer" resultType="com.baidu.entity.Student" useCache="false" >
<include refid="selectAll"></include> where id = #{id}
</select>
3mybatis基于注解的开发
mybatis常用注解
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
基于注解的增删改查
package com.yyf.dao;
import com.yyf.entity.Score;
import com.yyf.entity.Student;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
/**
* @Author: yyf
* @Date: 2020/10/16 19:15
*/
public interface StudentDao1 {
/**
* 查找所有学生
* @return
*/
@Results(id = "studentMap",value = {@Result(id = true,property = "id",column = "id"),
@Result(property = "name",column = "name"),
@Result(property = "age" ,column = "age"),
@Result(property = "sex",column = "sex"),
@Result(property = "height",column = "height")
})
@Select("select * from student_tb")
List<Student> findAllStudent();
/**
* 根据 查询学生
* @param id
* @return
*/
@Select("select * from student_tb where id = #{id}")
@ResultMap(value = "studentMap")
Student findStudentById(int id);
/**
* 更新学生
* @param student
* @return
*/
@Update("update student_tb set name=#{name},age=#{age},height=#{height},sex=#{sex} where id=#{id}")
int updateStudent(Student student);
/**
* 增加学生
* @param student
*/
@Insert(" insert into student_tb (name,age,sex,height)values (#{name},#{age},#{sex},#{height})")
@SelectKey(keyColumn = "id",keyProperty = "id",resultType = Integer.class,before = false,statement = " select last_insert_id()")
int addStudent(Student student);
/*
* 删除学生信息
* */
@Delete("delete from student_tb where id = #{id}")
int deleteStudent(int id);
/*
* 一对一
* */
@Results(id ="findScoreWithStudent",value = {
@Result(id = true,property="scoreid", column= "scoreid"),
@Result(property="coursename" ,column="coursename"),
@Result(property="score", column="score"),
@Result(property="studentid" ,column="studentid"),
@Result(column = "studentid",property = "student",one = @One(select = "com.yyf.dao.StudentDao.findStudentById",fetchType = FetchType.LAZY))
})
@Select("select * from score_tb")
List<Score> findScoreWithStudent();
/*
* 一对多
* */
@Results(id = "findAllStudentWithScoreLazyMap",value = {
@Result(id = true,column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(column = "sex",property = "sex"),
@Result(column = "age",property = "age"),
@Result(column = "height",property = "height"),
@Result(column = "id",property = "scoreList",many = @Many(select = "com.yyf.dao.ScoreDao.findAllScoreByStudentId",fetchType = FetchType.LAZY))// 一对多
})
@Select("select * from student_tb")
List<Student> findAllStudentWithScoreLazy();
}
4.pageHelper分页插件
注意在 environments之前声明
<plugins>
<!-- 让mybatis 加载PageHelper -->
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 使用MySQL方言的分页 -->
<property name="helperDialect" value="mysql"/><!--如果使用mysql,这里value为mysql-->
<property name="pageSizeZero" value="true"/>
</plugin>
</plugins>
使用
// 以前 分页 select * from student_tb limit (pageIndex -1)* pageSize,pageSize
// 现在 1.select * from student_tb ,其他的分页交给插件pageHelper
@Test
public void pageHelpTest(){
// 开启分页 // 查询第一页 每页连个数据
PageHelper.startPage(2,2);
List<Student> studentList = studentDao2.findAllStudent();
for (Student student:studentList){
System.out.println("student:"+student);
}
// 获取所有分页信息
PageInfo<Student> pageInfo = new PageInfo<Student>(studentList);
System.out.println("分页大小"+pageInfo.getPageSize());
System.out.println("总页大小"+pageInfo.getPages());
System.out.println("总条数大小"+pageInfo.getTotal());
}