mybatis学习系列三(部分)

Posted cslj2013

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis学习系列三(部分)相关的知识,希望对你有一定的参考价值。

1 forearch_oracle下批量保存(47)

oracle批量插入

   不支持values(),(),()方式

 

1、多个insert放在begin-end里面

   begin

   insert into myemployeee(id,last_name,email,gender,dept_id) values

   (myemployeee_seq.nextval,#{emp.lastName,jdbcType=VARCHAR},#{emp.email,jdbcType=VARCHAR},

   insert into myemployeee(id,last_name,email,gender,dept_id) values

   (myemployeee_seq.nextval,#{emp.lastName,jdbcType=VARCHAR},#{emp.email,jdbcType=VARCHAR},

   end;

   #{emp.gender,jdbcType=VARCHAR},#{emp.deptId,jdbcType=INTEGER})

 2、利用中间表

   insert into employeee(id,last_name,email)

   select employeee_seq.nextval,lastName,email from (

    select \'test_a_01\' lastName,\'test_a_e1\' email from dual

    union

    select \'test_a_02\' lastName,\'test_a_e2\' email from dual

    union

    select \'test_a_03\' lastName,\'test_a_e3\' email from dual

方式一:

<!-- oracle第一种方式 -->

   <foreach collection="emps" item="emp" open="begin" close="end;">

   insert into myemployeee(id,last_name,email,gender,dept_id)

   values

   (myemployeee_seq.nextval,#{emp.lastName,jdbcType=VARCHAR},#{emp.email,jdbcType=VARCHAR},

   #{emp.gender,jdbcType=VARCHAR},#{emp.deptId,jdbcType=INTEGER})

   </foreach>

 

方式二:

<!-- oracle第二种方式 -->

   insert into myemployeee(id,last_name,email,gender,dept_id)

   select employeee_seq.nextval,lastName,email,gender,deptId from

   <foreach collection="emps" item="emp" open="(" close=")" separator="union">

   select #{emp.lastName,jdbcType=VARCHAR} lastName,#{emp.email,jdbcType=VARCHAR} email,

   #{emp.gender,jdbcType=VARCHAR} gender,#{emp.deptId,jdbcType=VARCHAR} deptId

    from dual

   </foreach>

 

 

2 动态sql-内置参数_parameter_databaseId(48)

不只是方法传递过来的参数可以被判断,取值

Mybatis还有2个默认内置参数:

_parameter:代表整个参数

单个参数:_parameter即这个参数

多个参数:参数会被封装为一个map,_parameter代表该map

_databaseId:如果配置了DatabaseIdProvider标签,_databaseId代表当前数据库别名(如oracle)

 

 

 <!-- 内置参数_databaseId和 _parameter

   selectEmployeeByInnerParameter(Employee employee);

  -->

  <select id="selectEmployeeByInnerParameter" resultType="com.mybatis.bean.Employee">

   <if test="_databaseId == \'oralce\' ">

   select * from tbl_employeee

   <!-- <if test="_parameter !=null">

   where last_name= #{_parameter.lastName}

   </if> -->

   <if test="_parameter !=null">

   where last_name= #{lastName}

   </if>

   </if>

   <if test="_databaseId == \'mysql\' ">

   select * from myemployeee 

   <if test="_parameter !=null">

   where last_name=#{_parameter.lastName}

   </if>

   </if>

  </select>

 

3 动态sql-bind绑定(49)

<if test="_databaseId == \'mysql\' ">

   select * from myemployeee 

   <!-- like 查询

   方式一:$ 不安全

   where last_name like \'%${lastName}%\'

   方式二:# CONCAT

   where last_name like CONCAT(\'%\',#{lastName},\'%\')

   方式三:bind,将值绑定到一个变量中,方便后来引用

   <bind name="_lastName" value="\'%\'+lastName+\'%\'"/>

   <if test="_parameter !=null">

   where last_name like #{_lastName}

   </if>

    -->

   <bind name="_lastName" value="\'%\'+lastName+\'%\'"/>

   <if test="_parameter !=null">

   where last_name like #{_lastName}

   </if>

   </if>

 

 

4 动态sql-sql抽取可重用sql片段(50)

 

1)定义sql片段

<sql id="queryColumn">

   id,last_name,email,gender,dept_id

  </sql>

 

2)使用

select

   <include refid="queryColumn"></include>

    from myemployeee

 

 

include中自定义属性及值,sql标签内即可使用

注意:只能使用$,不能使用#

select

   <include refid="queryColumn">

   <!-- 自定义属性及值 -->

   <property name="testColumn" value="test"/>

   </include>

    from myemployeee 

 

<sql id="queryColumn">

   id,last_name,email,gender,dept_id,${testColumn}

  </sql>

 

5 缓存-一级缓存(51-53)

一级缓存:默认开启,sqlsession级别缓存(也称为本地缓存),查询的结果存放在map中

二级缓存:手动开启和配置,基于namespace级别

 

1)测试一级缓存

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

 

List<Employee> emps2=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为true

实际只执行了一次sql语句,后面的查询从一级缓存获取

 

一级缓存失效情况:

1、sqlsession不同

2、Sqlsession相同,查询条件不同(需要执行新sql)

3、sqlsession相同,2次查询间执行了增删改操作(影响当前数据)

4、sqlsession相同,手动清除了一级缓存

 

 

 

 

1、sqlsession不同

 

//一级缓存测试失效(非同一个sqlsession执行2sql

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

 

SqlSession session2 = sqlSessionFactory.openSession();//手动提交

EmployeeMapper mapper2=session2.getMapper(EmployeeMapper.class);

List<Employee> emps2=mapper2.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为false

 

2、sqlsession相同,查询条件不同

//一级缓存测试失效(情况2:同一个sqlsession,不同查询条件)

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

 

List<Employee> emps2=mapper.selectEmployeeByIds(Arrays.asList(1,2,3));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为false

 

3、sqlsession相同,2次查询间执行了增删改操作(影响当前数据)

//一级缓存测试失效(情况3:sqlsession相同,2次查询间执行了增删改操作(影响当前数据))

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

//更新操作

int updateSize=mapper.updateEmp(new Employee(3,"test333","test3333@com.cm","女",1));

 

List<Employee> emps2=mapper.selectEmployeeByIds(Arrays.asList(1,2,3));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为false

 

4、sqlsession相同,手动清除了一级缓存

 

//一级缓存测试失效(情况4:同一个sqlsession,清除了一级缓存)

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

session.clearCache();

 

List<Employee> emps2=mapper.selectEmployeeByIds(Arrays.asList(1,2,3));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为false

 

 

6 缓存-二级缓存(54-55)

二级缓存(全局缓存),基于namespace级别缓存

工作机制:

1、一个会话查询一条数据,数据会被放在当前会话的一级缓存中。

2、会话关闭,一级缓存中的数据会被保存到二级缓存中。

3、sqlsession==employmapper==>employee

Deptmapper===>dept

不同namespace查出数据会放在自己对应的缓存map中

查询的数据默认先放在一级缓存中,只有会话提交或关闭后,一级缓存中的数据会转移到二级缓存中

 

使用:

1)开启二级缓存配置

默认开启,也可在mybatis-config.xml配置文件中设置

 

<!-- 开启二级缓存,默认开启 -->

   <setting name="cacheEnabled" value="true"/>

 

2)xml配置使用(namespace级别)

Mapper中配置使用二级缓存

<cache></cache>

 

<!-- mapper中配置二级缓存

eviction:回收策略,LRU,FIFO,SOFT,WEAK;默认LRU

flushInterval:缓存刷新间隔(默认不清空),定位秒

readOnly:是否只读,true/false,默认false

true:mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据,

mybatis为了加快获取速度,会直接将数据在缓存中的引用返回,不安全,速度快

false:非只读,mybatis可能认为数据可能会被修改,mybatis会利用序列化&反序列化技术克隆数据,安全,速度慢

 -->

<cache eviction="" flushInterval="" readOnly=""></cache>

 

 

3)POJO需要实现序列化接口

 

 

测试样例:

1)mapper中配置

<cache></cache>

2)测试类

//二级缓存测试

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(new Employee(null,"addemps1","addemps1@qq.com","男",1));

System.out.println(emps.toString());

session.close();

 

SqlSession session2 = sqlSessionFactory.openSession();//手动提交

EmployeeMapper mapper2=session2.getMapper(EmployeeMapper.class);

List<Employee> emps2=mapper2.selectEmployeeByIds(Arrays.asList(1,2,3));

System.out.println(emps2.toString());

System.out.println(emps2==emps); //为false

session2.close();

 

3)报错

[com.mybatis.bean.Employee@2473b9ce, com.mybatis.bean.Employee@60438a68, com.mybatis.bean.Employee@140e5a13, com.mybatis.bean.Employee@3439f68d]

Exception in thread "main" org.apache.ibatis.cache.CacheException: Error serializing object.  Cause: java.io.NotSerializableException: com.mybatis.bean.Employee

at org.apache.ibatis.cache.decorators.SerializedCache.serialize(SerializedCache.java:102)

 

Employee没有序列化,实现Serializable接口后

 

再报错:

false

Exception in thread "main" org.apache.ibatis.cache.CacheException: Error serializing object.  Cause: java.io.NotSerializableException: com.mybatis.bean.MyDept

 

MyDept没有序列化,实现Serializable接口

 

 

4)输出结果

[com.mybatis.bean.Employee@2473b9ce, com.mybatis.bean.Employee@60438a68, com.mybatis.bean.Employee@140e5a13, com.mybatis.bean.Employee@3439f68d]

[com.mybatis.bean.Employee@29ba4338, com.mybatis.bean.Employee_$$_jvst385_0@7bb58ca3]

false

 

False是因为通过序列化拷贝的数据。

如果不配置<cache>,则会发送2sql请求;

 

 

7 缓存-二级缓存的设置(56)

1)setting配置中

<!-- 开启二级缓存,默认开启 -->

   <setting name="cacheEnabled" value="false"/>

 

关闭二级缓存,但一级缓存未关闭;设置的是二级缓存

2)每个select标签都有useCache=true,默认为truefalse为关闭;设置的是二级缓存。

3)每个增删改包含标签:flushcache=true;默认为true;清空缓存(一级和二级缓存都清空

4sqlsession.clearCache();清空一级缓存

5localcachescope:本地缓存(本地会话)范围,一级缓存

 

 

8缓存-原理图示(57 )

 

 

9缓存-第三方缓存整合原理&ehcache适配器(58-59)

引入ehcache-core缓存jar包,还有其他缓存包,可参考mybatis github网站

以上是关于mybatis学习系列三(部分)的主要内容,如果未能解决你的问题,请参考以下文章

mybatis增删改查

MyBatis学习总结-MyBatis快速入门的系列教程

MyBatis学习记录

学习MyBatis必知必会~准备工作:了解框架三层架构ORM思想

mybatis学习系列四--mybatis generator逆向工程

Mybatis学习系列 –– 入门简介