mybatis源码阅读-高级用法
Posted 意犹未尽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis源码阅读-高级用法相关的知识,希望对你有一定的参考价值。
新建学生表和学生证表
--学生表 CREATE TABLE student( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT \'id\', `name` VARCHAR(20) NOT NULL COMMENT \'姓名\', `age` INT NOT NULL COMMENT \'年龄\', sex INT NOT NULL COMMENT \'性别 1 男 0 女\', cid INT NOT NULL COMMENT \'班级id\', cardId INT COMMENT \'学生证id\' ) --学生证表 CREATE TABLE Card ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT \'id\', number INT NOT NULL COMMENT \'学生证id\', studentId INT NOT NULL COMMENT \'学生id\' )
动态标签
include&sql
实现sql复用
<sql id="columns"> id,name,age </sql> <!--useCache 表示使用缓存 --> <select id="selectOne" parameterType="string" flushCache="false" useCache="true" resultMap="studentAndClassMap"> select <include refid="columns"/> from student <!--模拟if标签 --> <if test="id !=null and id!=\'\'"> where id=#{id} </if> </select>
where&if
<select id="selectOne" parameterType="string" flushCache="false" useCache="true" resultMap="studentAndClassMap"> select <include refid="columns"/> from student <where> <if test="id !=null and id!=\'\'"> and id=#{id} </if>
<if test="name !=null and name!=\'\'">
and name=#{name}
</if> </where> </select>
where标签里面有if标签成立 则自动在sql后面拼接where 同时去除多余的and
choose, when, otherwise
<select id="find" parameterType="map" resultType="student"> select * from student <!-- if else if else --> <where> <choose> <when test="sex != null"> and sex=#{sex} </when> <when test="name != null and name != \'\'"> and name like concat(\'%\',#{name},\'%\') </when> <!-- <otherwise> ... </otherwise> --> </choose> </where> </select>
trim, set
select * from user <trim prefix="WHERE" prefixoverride="AND |OR"> <if test="name != null and name.length()>0"> AND name=#{name}</if> <if test="gender != null and gender.length()>0"> AND gender=#{gender}</if> </trim>
满足条件拼接 where 同时去掉前面多余的and或者or
update user <trim prefix="set" suffixoverride="," suffix=" where id = #{id} "> <if test="name != null and name.length()>0"> name=#{name} , </if> <if test="gender != null and gender.length()>0"> gender=#{gender} , </if> </trim>
满足条件拼接set 同时去掉后面多余的, 再拼接 suffix
update user <set> <if test="name != null and name.length()>0"> name=#{name} , </if> <if test="gender != null and gender.length()>0"> gender=#{gender} , </if> </set>
满足条件拼接set 同时去掉多余的,
一对多级联
1.学生mapper增加一个根据班级获取学生
<select id="findByClassesId" parameterType="int" resultType="student"> select * from student where cid=#{id} </select>
public List<Student> findByStudent(Student params);
2.在classes类增加一个学生集合
public class Classes implements Serializable{
....
private List<Student> students;
}
2.classesMapper增加自定义resultMap
<resultMap id="classVoMap" type="com.liqiang.vo.ClassesVo"> <id property="id" column="id" /> <result property="name" column="name" /> <collection property="students" column="id" select="com.liqiang.mapper.StudentMapper.findByClassesId"></collection> </resultMap>
select为调用指定mapperStatement(可以理解是指定key的标签namespace+id)
column 为将哪个列作为参数传递
students 返回结果赋值的属性
可以设置 fetchType="eager(默认值 不按层级加载)|lazy" 就是有有很多级的时候 是否一下把所有级加载出来
3.在需要使用resultMap的地方指定resultMap 如根据id获得class
<select id="findById" parameterType="Integer" resultMap="classVoMap"> select * from classes where id=#{id} </select>
多对一, 一对一级联
1.学生表增加classes
public class Student implements Serializable{
.... private Classes classes;
}
2.学生表增加自定义resultMap
<resultMap id="studentAndClassMap" type="student" >
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="cid" column="cid" />
<association property="classes" column="cid"
select="com.liqiang.mapper.ClassesMapper.findById"></association>
</resultMap>
3.在需要级联的地方resultMap改为这个
<!--useCache 表示使用缓存 --> <select id="selectOne" parameterType="string" flushCache="false" useCache="true" resultMap="studentAndClassMap"> select * from student <!--模拟if标签 --> <if test="id !=null and id!=\'\'"> where id=#{id} </if> </select>
跟多对一一样 只是标签改为association
可以通过Sesstio全局设置级联是否延迟加载
<settings> <setting name="lazyLoadingEnabled" value="true"></setting><!--开启级联延迟加载--> <!--不按层级延迟加载 根据get 来加载 可以在collection 或者association 加上属性覆盖全局 fetchType="eager(默认值 不按层级)|lazy"--> <setting name="aggressiveLazyLoading" value="false"></setting> </settings>
层级加载的意思 就是 比如学生级联班级,班级又有学校级联 当延迟加载情况getClass时是否也级联加载学校,或者非延迟加载 所有的都加载出来
resultMap或者ParameterMap继承
<resultMap id="studentMap" type="studentVo"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="cid" column="cid" /> <association property="card" column="id" select="com.liqiang.mapper.CardMapper.findByStudentId"></association> </resultMap> <resultMap id="studentAndClassMap" type="student" > <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="cid" column="cid" /> <association property="classes" column="cid" select="com.liqiang.mapper.ClassesMapper.findById"></association> </resultMap>
如我定义了2个Resultmap 一个需要class级联 一个只需要学生证级联,是否发现前面几个属性几乎是copy的
我们可以这样
<resultMap id="simpleType" type="student"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="cid" column="cid" /> </resultMap> <resultMap id="studentMap" type="student" extends="simpleType"> <association property="card" column="id" select="com.liqiang.mapper.CardMapper.findByStudentId"></association> </resultMap> <resultMap id="studentAndClassMap" type="student" extends="simpleType" > <association property="classes" column="cid" select="com.liqiang.mapper.ClassesMapper.findById"></association> </resultMap>
使用extends="simpleType" 继承
Mybatis对枚举支持
1.添加一个性别枚举
public enum SexEnum { MALE(1, "男"), FEMAL(0, "女"); private int id; private String name; private SexEnum(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.将学生性别改为枚举类型
public class Student implements Serializable{
.... private SexEnum sex; }
3.resultMap的TypeHandle处理器改为mybatis提供的枚举处理器
<resultMap id="studentMap" type="studentVo"> .... <result property="sex" column="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
自定义TypeHandle
实现TypeHandle接口就好了。然后像上面一样typeHandle改为自己指定的,因为mybatis默认提供个TypeHandle基本够用了。找不到例子 测试
自定义缓存
分布式 或者集群我们缓存都是存在redis或者其他nosql上面,redis缓存默认是存在当前服务器内存,
这种时候我们需要自定义缓存
public class MyCache implements org.apache.ibatis.cache.Cache{ private String id; /** *读的时候其他线程可以读 *读的时候其他线程不能写 *写的时候其他线程不能写 *写的时候不能读 * getData(){ * try{ * readWriteLock.readLock(); 读锁 * }catch(execption e){ * * }finally{ * readWriteLock.readLock().unlock(); * } * } * * setData(){ * * try{ * readWriteLock.writerLock(); 写锁 * }catch(execption e){ * * }finally{ * readWriteLock.writerLock().unlock(); * } * } * 外部代理类会在get 和put 方法 加上读写锁 */ private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//读写锁 public MyCache(String id){ System.out.println(id);//对应的mapper全名称标示 this.id=id; } private static Map<Object, Object> cacheManager=new HashMap<Object, Object>();//模拟redis //获取缓存编号 public String getId() { // TODO Auto-generated method stub return id; } //缓存数据 public void putObject(Object key, Object value) { System.out.println("缓存对象 key为:"+key.toString()); // TODO Auto-generated method stub cacheManager.put(key, value); } //获取缓存 public Object getObject(Object key) { // TODO Auto-generated method stub System.out.println("获取对象 key为:"+key.toString()); return cacheManager.get(key); } //删除缓存 public Object removeObject(Object key) { return cacheManager.remove(key); } //清空缓存 public void clear() { cacheManager.clear(); } //获取缓存对象大小 public int getSize() { // TODO Auto-generated method stub return cacheManager.size(); } //获取缓存读写锁 public ReadWriteLock getReadWriteLock() { // TODO Auto-generated method stub return readWriteLock; } }
实现Cache 接口
在需要Mapper缓存的Mapper.xml配置
<!-- eviction 回收策略 LRU:最近最少使用 FIFO:先进先出 SOFT 软引用 WEAK 移除最长时间不使用的对象 flushInterVal:刷新时间间隔 毫秒。不配置 执行inser update delete 才会刷新 type :自定义缓存需要实现 org.apache.ibatis.cache.Cache --> <cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true" type="com.liqiang.tool.MyCache"></cache>
在需要更新缓存的地方
<!--flushCache 是否刷新缓存 --> <update id="update" parameterType="student" flushCache="true"> update student set name=#{name},sex=#{sex} where id=#{id} </update>
打上flushCache="true"
mybatis缓存的粒度不是很细。一刷新缓存整个表就刷新了。比如id为1的数据修改 你想只更新这个缓存,mybatis是更新整个表
以上是关于mybatis源码阅读-高级用法的主要内容,如果未能解决你的问题,请参考以下文章