参考代码:mybatis框架代码及注解进阶
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties还可以配置一些属性名和属性值
在properties元素体内定义的属性首先被读取
然后会读取resource或url中加载的属性,它会覆盖已读取的同名属性
最后读取parameterType中传递的属性,会覆盖已读取的同名属性
advice:不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中
在properties文件中顶一顶属性名一定要有一定的特殊性,如xxxxx.xxx.xxx
mybatis框架在运行时可以调整一些运行参数
如:开启二级缓存,开启延迟加载
全局参数将会影响mybatis的运行行为
在mapper.xml中,定义有很多statement,statement需要parameterType指定输入参数类型,需要resultType指定输出结果的映射类型
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
mybatis支持自定义别名
单个别名的定义
批量定义别名
mybatis中通过typeHandler完成jdbc类型和java类型的转换
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义。
单个的映射文件的加载
通过mapper接口加载
输出映射:
resultType:
使用resultType进行映射,只有查询出的列名和pojo中的属性名一致,才能映射成功
如果查询出来的列名和pojo中的属性名都不一致,则没创建pojo对象
如果查询出来的列名和pojo中的属性名有一个一致,就会创建pojo对象
输出简单类型:
查询出的结果集只有一行且一列,可以用简单类型进行输出映射。
输出pojo对象和pojo列表:
不管输出的pojo是单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定类型是一只的
在mapper.java指定的方法返回值类型不一样:
输出单个pojo,返回pojo
输出掉个pojo,返回list
resultMap:
如果查询出来的列名和pojo中的属性不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系
select id id_,username username_ FROM user
1.定义resultMap
2.使用resultMap作为statement的输出映射
小结:使用resultType,输出的列名必须与属性名一致
如果不一致,则需要使用resultMap
resultType和resultMap的应用:
用户账号,用户名称,用户性别,商品名称,商品价格
企业开发中常见明细列表,用户购买商品明细列表
使用resultType将上面查询映射到pojo进行输出
用户账号,用户名称,购买商品数量,商品明细(鼠标上移显示)
使用resultMap将用户购买的商品明细列表映射到user对象中
总结:
使用resultMap是针对那些对查询结果有特殊要求的功能。
resultType和resultMap在一对一,一对多,多对多中的实现与作用:
一对一:
实现方式:
resultType:resultType为根据需要而创建出的pojo类型,其中包含所要查询的所有属性。
resultMap:返回值为resultMap,自定义resultMap
<resultMap id="OrdersUserResultMap" type="mybatis.po.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
......
<association property="user" javaType="mybatis.po.User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
.......
</association>
</resultMap>
其中column为唯一标识,property为其在对应类型中的对应属性。
<association> 用于映射关联查询单个对象的信息
一对多实现方式:
resultType:返回的pojo较复杂,不建议使用
resultMap:返回值为resultMap,自定义resultMap
<resultMap id="OrdersAndOrderDetailResultMap" type="mybatis.po.Orders" extends="OrdersUserResultMap">
<collection property="orderdetails" ofType="mybatis.po.Orderdetail">
<id column="orderdetail_id" property="id"/>
<id column="items_id" property="itemsId"/>
</collection>
</resultMap>
其中extends表示继承其他resultMap,可以简化代码,
<id>表示唯一标识,同时也表示主键,主键用<id>标签有助于映射
除去主键的其他属性可以写在<result>标签中,也可使用<id>标签。
多对多实现方式:
resultType:不建议使用
resultMap:返回值为resultMap,自定义resultMap
<resultMap id="UserAndItemsResultMap" type="mybatis.po.User">
<id column="user_id" property="id"/>
<result ......
<collection property="ordersList" ofType="mybatis.po.Orders">
<id column="id" property="id"/>
<result ......
<collection property="orderdetails" ofType="mybatis.po.Orderdetail">
<id column="orderdetail_id" property="id"/>
<result ......
<association property="items" javaType="mybatis.po.Items">
<id column="items_id" property="id"/>
<result ......
</association>
</collection>
</collection>
</resultMap>
其中collection用于一对多的映射关系
association用于一对一的映射关系
resultMap可以实现高级映射,association和collection具备延迟加载的功能。
需求:如果查询订单并且关联用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。
把对用户信息的按需查询称为延迟加载。
延迟加载:先从单表查询,需要时再从关联表去关联查询,提高数据库性能,因为实现单表要比关联查询多张表速度要快
SELECT
orders.*,
( SELECT username FROM USER WHERE orders.user_id = USER.id ) username,
( SELECT sex FROM USER WHERE orders.user_id = USER.id ) sex
FROM
orders
实现:写两个mapper(sql子查询)
1.只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载下边的statement(关联查询用户信息)
2.查询用户信息
通过上面查询到的订单信息中user_id去关联查询用户信息
上面先执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来
id:sql片段的唯一标识
经验:是基于单表来定义sql片段,使sql片段的可重用性更高
在sql片段中不要包含where
作用:如果缓存有数据库就不用访问数据库,提高系统的性能。
一级缓存:sqlSession级别的缓存
在操作数据库时需要构造session对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。
不同的sqlSession之间的缓存数据区域(HashMap)互补影响
二级缓存:mapper级别的缓存
多个sqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存。
原理:
<!-- 延迟加载配置 -->
<settings>
<!-- 延迟加载开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 是否积极的加载,设为false不会自动加载,在需要时时候手动加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
首先开启mybatis的二级缓存
sqlsession1查询用户1的信息,查询到的用户信息会保存到二级缓存中
sqlsession2查询用户1的信息,会先到二级缓存中查找,再从数据库中查找
与一级缓存的区别,二级缓存的范围更大,多个sqlSession共享一个二级缓存
每一个namespace有一个二级缓存。
1.开启
需要在sqlMapConfig.xml和mapper.xml中都要开启二级缓存。
sqlMapConfig.xml中
mapper.xml中
2.调用pojo类实现序列化接口
//实现序列化接口,为了将数据执行反序列化,因为二级缓存数据存储介质多种多样,不一定在内存。
public class User implements Serializable {
private int id;
private String username;
private int sex;
private Date birthday;
private String address;
3.测试
useCache配置
即使开启了缓存,调用的数据也不会保存进缓存
在statement中设置useCache = false 可以禁用语句缓存,即每次查询都会发出sal请求,
默认情况下是true,即该sql使用二级缓存。
总结:
一般执行完commit操作都需要刷新缓存,flushCache=true 这样可以避免脏读。
刷新间隔flushInterval 一般设置为30,60分钟,24小时,根据需求而定
缓存大小size
应用场景:
对于访问多的查询请求并且用户对查询结果使用性不高,
业务场景:如耗时的统计分析sql,电话账单查询sql等。
局限性:
mybatis 二级缓存对细粒度的数据级别的缓存实现不好,
(细粒度数据的更改,只更改大量级数据中的极小部分数据)
不使用分布缓存,缓存的数据在各个服务器单独存储。
不便于系统开发
分布式缓存框架redis,memached,ehcache,
对缓存数据进行集中管理。
如果是单个应用或者对缓存访问要求很高的应用,用ehcache。
如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。
整合方法
mybatis提供了一个cache接口,如果实现自己的缓存逻辑,实现cache接口开发即可。
implement cache
加入ehcache包
使用ehcache,要添加ehcache包
ehcache-core.jar
mybatis-ehcache.jar
整合ehcache
在classpath下面添加ehcache的配置文件ehcache.xml