Mybatis之——延迟加载、缓存、注解开发
延迟加载
什么是延迟加载
实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。此时就是我们所说的延迟加载。
延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
- 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
- 坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
实现延迟加载
这里实现的是用户与账户一对多的延迟查询(一个用户下有多个账户)
当使用Mybatis创建的Dao代理对象获取其属性时
如果我们没有获取该用户的账户属性,那么则不执行查询账户的SQL语句
SQLMapConfig.xml添加配置
1 | <settings> |
User实体类
1 | /** |
映射配置文件:UserDao.xml
1 | <resultMap type="user" id="userMap"> |
标签:用于加载关联的集合对象(某个用户下的所有账户信息集合) - select属性:用于指定查询账户信息的SQL语句
- column属性:指定sql语句的参数来源,上面参数来自于user对象的id属性(user表的is字段),所以这里就写id了
缓存
什么是缓存?
答:存在于内存中的临时数据
为什么使用缓存?
答:减少和数据库的交互次数,提高执行效率
什么样的数据能使用缓存?什么样的数据不能使用缓存
适用与缓存的数据:
- 经常查询并且不经常改变的数据
- 数据的正确与否对最终结果影响不大的数据,比如:商品的库存,商品显示有库存,但下单买时告诉你没库存了,这样对最终的结果影响不大
不适用与缓存的数据:
- 经常改变的数据
- 数据的正确与否对最终结果影响很大的,例如:银行的汇率、股市的价格
Mybatis中的一级缓存和二级缓存
一级缓存
它是指Mybatis中SqlSession对象级别的缓存,它是不需要任何配置默认就有的
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。
该区域的结构是一个Map。
当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
- 一级缓存数据的更变
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close(),clearCache()等方法时,就会清空一级缓存。
二级缓存
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
它的存储原理与一级缓存唯一不相同的地方就是,一级缓存以Map对象形式存储,二级缓存则是以{"id":1, "username":"张三"}
这种数据的形式进行存储
二级缓存配置步骤
1、在 SqlMapConfig.xml 文件开启二级缓存
1 | <settings> |
- ps:因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
2、配置相关的 Mapper 映射文件
1 |
|
标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。 - ps:所以二级缓存也可以叫Mappre级别的缓存,因为他作用在一个Mappre映射上
3、配置 statement(映射文件的select标签) 上面的 useCache 属性
1 | <!-- 根据 id 查询 --> |
- 将 UserDao.xml 映射文件中的
<select>
标签中设置useCache=”true”
代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。 - 注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
二级缓存注意事项
当我们在使用二级缓存时,所有缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。
注解开发
注意事项:如果注解开发和xml文件一起使用了,不管主配置文件有没有调用、调用了哪个,Mybatis都会报错
常用注解
- @Insert:实现新增
- @SelectKey:新增后获取新记录id,然后封装到实体类对象中
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与@Result 一起使用,封装多个结果集
- @ResultMap:实现引用@Results 定义的封装
- @One:实现一对一结果集封装
- @Many:实现一对多结果集封装
- @SelectProvider: 实现动态 SQL 映射
- @CacheNamespace:实现注解二级缓存的使用
映射关系的注解说明
@Results 注解
代替的是标签**
**
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
- @Results({@Result(),@Result()})
- 或@Results(@Result())
@Resutl 注解
代替了 **
标签和 **标签
- id:是否是主键字段
- column:数据库的列名
- property:需要装配的属性名
- one:需要使用的@One 注解(@Result(one=@One)()))
- many:需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了**
**标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
- select:指定用来多表查询的 sqlmapper
- fetchType:会覆盖全局的配置参数 lazyLoadingEnabled,这里是配置延迟加载
- 使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了**
**标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
- 注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义
- 使用格式:
@Result(property="",column="",many=@Many(select=""))
注解开发简单关系映射示例
UserDao接口
1 | /** |
SqlMapConfig.xml主配置文件
1 |
|
注解开发复杂关系映射示例:一对一
需求:
- 加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式实现)
ps:通常一对一关系都采用立即加载,而一对多采用延迟加载(懒加载)
User 实体类及 Account 实体类
1 | /** |
账户(Account)的持久层接口注解配置
1 | /** |
- fetchType=FetchType.LAZY: 开启延迟加载
用户(User)的持久层接口注解配置
1 | /** |
注解开发复杂关系映射示例:一对多
需求:
- 查询用户信息时,也要查询他的账户列表。使用注解方式实现。
分析:
- 一个用户具有多个账户信息,所以形成了用户(User)与账户(Account)之间的一对多关系。
ps:通常一对一关系都采用立即加载,而一对多采用延迟加载(懒加载)
User 实体类加入 List
1 | /** |
用户(User)持久层接口注解配置
1 | /** |
- @Many:相当于
<collection>
的配置 - select 属性:代表将要执行的 sql 语句
- fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
账户(Account)持久层对象注解配置
1 | /** |
基于注解的二级缓存配置
SqlMapConfig.xml主配置文件中开启二级缓存
1 | <!-- 配置二级缓存 --> |
在持久层接口中注解配置二级缓存
1 | /** |