高级知识
1、订单商品数据模型分析
2、高级结果集映射(一对一、一对多、多对多)
3、mybatis延迟加载
4、mybatis查询缓存(一级缓存、二级缓存)
5、mybatis和spring整合
6、mybatis逆向工程
1 订单商品数据模型
1.1 数据模型分析思路
1、每张表记录的数据内容
分模块对每张表记录的内容进行熟悉,相当于学习系统需求(功能)的过程
2、每张表重要的字段
非空字段、外键字段
3、数据库级别表与表之间的关系
外键关系
4、表与表之间的业务关系
在分析表与表之间的业务关系时一定要建立在某个业务意义基础之上分析
1.2 数据模型分析
用户表:user
记录了购买商品的用户信息
订单表:orders
记录了用户所创建的订单(购买商品的订单)
订单明细表:orderdetail
记录了订单的详细信息,即购买商品的信息
商品表:items
记录了商品信息
2 一对一查询
2.1 需求
查询订单信息,关联查询创建订单的用户信息
2.2 resultType
2.2.1 sql语句
确定查询的主表:订单表
确定查询的关联表:用户表
2.2.2 pojo
将上面sql查询的结果映射到pojo中,pojo必须包括所有查询列名
原始的Orders.java不能映射全部字段,需要创建新的pojo
创建一个pojo继承包括查询字段较多的po类
2.2.3 mapper.xml
2.2.4 mapper.java
2.3 resultMap
2.3.1 sql语句
同resultType
2.3.2 使用resultMap映射思路
使用resultMap将查询结果中的订单信息映射到orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中
2.3.3 mapper.xml
2.3.3.1 定义resultMap
2.3.3.2 定义statement
2.3.4 mapper.java
2.4 小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射
如果没有查询结果的特殊要求,建议使用resultType
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射到pojo的属性中
resultMap可以实现延迟加载,resultType无法实现延迟加载
3 一对多查询
3.1 需求
查询订单及订单明细的信息
3.2 sql语句
3.3 分析
使用resultType将上边的查询结果映射到pojo中,订单信息的就会重复
要求:对orders映射不能出现重复记录
在Orders.java中添加List<OrderDetail> orderDetails属性
最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中
映射成的orders记录数为两条(orders信息不重复)
3.4 在orders中添加list订单明细属性
3.5 mapper.xml
3.5.1 resultMap定义
3.5.2 statement定义
3.6 mapper.java
3.7 小结
mybatis使用resultMap的connection对关联查询的多条记录映射到一个list集合属性中
如果使用resultType实现,将订单明细映射到orders的orderdetails中,需要自己处理,使用双重循环,去掉重复记录,将订单明细放到orderdetails中
4 多对多查询
4.1 需求
查询用户及用户购买商品信息
4.2 sql语句
查询主表:用户表
关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,关联表:orders、orderdetail、items
4.3 映射思路
将用户信息映射到user中
在User类中添加订单列表属性List<Orders> ordersList,将用户创建的订单映射到ordersList
在Orders中添加订单明细列表属性List<OrderDetail> orderdetails ,将订单的明细映射到orderdetails
在OrderDetail中添加Items属性,将订单明细所对应的商品映射到items
4.4 mapper.xml
4.4.1 resultMap定义
4.4.2 statement定义
4.5 mapper.java
4.6 总结
使用resultMap是针对那些对查询结果映射有特殊要求的功能,比如特殊要求映射成list中包括多个list
5 resultType和resultMap总结
6 延迟加载
6.1 什么是延迟加载
resultMap可以实现高级映射(使用association、collection实现一对一和一对多映射),association和collection具备延迟加载功能
需求:
如果查询订单并且关联查询用户信息,如果先查询订单信息即可满足需求,当我们需要查询用户信息时再查询用户信息,把对用户信息的按需去查询就是延迟加载
延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度快
6.2 使用association实现延迟加载
6.2.1 需求
查询订单并且关联查询用户信息
6.2.2 mapper.xml
需要定义两个mapper的方法对应的statement
1、只查询订单信息
在查询订单的statement中使用association去延迟加载下边的statement(关联查询用户信息)
2、关联查询用户信息
通过上边查询到的订单信息中user_id去关联查询用户信息
6.2.3 mapper.java
6.2.4 测试
6.2.4.1 测试思路
6.2.4.2 延迟加载配置
<!-- 全局配置参数,需要时再设置 -->
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载,即按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
6.2.5总结
使用延迟加载方法,先去查询简单的sql(最好是单表,也可以关联查询),再去按需要加载关联查询的其他信息
7 查询缓存
7.1 什么是查询缓存
mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能
mybatis提供了一级缓存和二级缓存
一级缓存是sqlSession级别的缓存 ,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据
不同sqlSession之间的缓存数据区域是互不影响的
二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的
7.2 一级缓存
7.2.1 一级缓存工作原理
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息,得到用户信息后,将用户信息存入一级缓存中
如果sqlSession去执行commit操作(执行增删改),清空sqlSession中的一级缓存,为了让缓存中存储的是最新的信息,避免脏读
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息
7.2.2 一级缓存测试
mybatis默认支持一级缓存,不需要在配置文件进行配置
7.2.3 一级缓存应用
7.3 二级缓存
7.3.1 原理
首先开启mybatis的二级缓存
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中
如果sqlSession3去执行相同mapper下sql,执行commit提交,清空该mapper下二级缓存区域的数据
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据
二级缓存和一级缓存区别:二级缓存的范围更大,读个sqlSession共享一个mapper的二级缓存区域
每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中
7.3.2 开启二级缓存
mybatis的二级缓存是mapper范围级别,除了在SqlMapConfi.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
在UserMapper.xml中开启二级缓存
7.3.3 pojo类实现序列化接口
为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定在内存
7.3.4 测试
7.3.5 禁用二级缓存
7.3.6 刷新缓存
7.4 mybatis整合ehcache
ehcache是一个分布式缓存框架
7.4.1 分布式缓存
系统为了提高并发、性能,一般对系统进行分布式部署(集群部署方式)
不使用分布式缓存,缓存的数据在各自服务器单独存储,不方便系统开发,所以要使用分布式缓存对缓存数据进行集中管理
mybatis无法实现分布式缓存,需要和其他分布式缓存框架进行整合
7.4.2 整合方法
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache 接口的实现类
mybatis默认实现cache类是:PerpetualCache
7.4.3 加入ehcache架包
7.4.4 整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型
7.4.5 加入ehcache配置文件
在classpath下配置ehcache.xml
7.5 二级缓存应用场景
7.6 二级缓存局限性
8 spring和mybatis整合
8.1 整合思路
需要spring通过单例方式管理SqlSessionFactory
spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession(spring和mybatis整合自动完成)
持久层的mapper都需要由spring进行管理
8.2 整合环境
创建一个新的java工程
架包:
mybatis 3.2.7 的jar包
spring 3.2.0 的jar包
mybatis和spring整合包:早期ibatis和spring整合是由spring官方提供,mybatis和spring整合有mybatis提供
mybatis-spring-1.2.2.jar
8.3 sqlSessionFactory
在applicationContext.xml配置sqlSessionFactory 和数据源
sqlSessionFactory在mybatis和spring整合包下
8.4 原始dao开发(和spring整合)
8.4.1 User.xml
在SqlMapConfig.xml中加载User.xml
8.4.2 dao
dao接口实现类中需要注入SqlSessionFactory,通过spring注入
这里spring声明配置方式,配置dao的bean
让UserDaoImpl实现类继承SqlSessionDaoSupport
8.4.3 配置dao
在applicationContext.xml中配置dao
8.4.4 测试
8.5 mapper代理开发
8.5.1 mapper.xml和mapper.java
8.5.2 通过MapperFactoryBean创建代理对象
此方法问题:
需要针对每个mapper进行配置,比较麻烦
8.5.3 通过MapperScannerConfigurer进行mapper扫描
8.5.4 测试