Mybatis学习

作为个人笔记使用,不太适合参考,哈哈,打扰了

这里我主要对比一下JDBC同样是对数据库的处理,为什么Mybatis会变得如此的手欢迎,一定是这个框架,给我们带来了,十分便利的地方,所以这个东西会变得流行起来!

最近比较丧,总感觉缺点什么东西,静静的看着时光流逝的感觉,我特别悲伤,所以打算写一点,学习的过程,也是自己慢慢成长的过程!

这些可能更加像,我自己的个人笔记,或则说是日志动态!

下面开始我简单的理论学习!

1. mybatis的介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

mybatis是一个优秀的持久层的框架,它对jdbc的操作数据库过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理如加载启动,创建Connection,创建statement,结果集封装等操作。

2.使用JDBC存在的问题和mybatis的解决

1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。

2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

 

3.mybatis架构

4.架构说明

1、 mybatis配置

SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

5.#{ } 和 ${ }

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

6.mybatis 和 hibernate的区别

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

7 sqlMapConfig.xml 配置文件

7.1 配置内容

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

 

1 课程计划

  1. 输入映射和输出映射
    1. 输入参数映射
    2. 返回值映射
  2. 动态sql
    1. If where foreach sql片段
  3. 多表关联查询
    1. 一对一关联
    2. 一对多关联
  4. mybatis的缓存
    1. 延迟加载
    2. 一级缓存
    3. 二级缓存
    4. 整个第三方的缓存技术

5. mybatis整合 spring

6.  mybatis的逆向工程搭建

2 输入映射和输出映射

2.1 parameterType(输入映射)

2.1.1 参数简单类型

parameterType="int"

2.1.2 参数java对象

parameterType="com.whhp.mybatis.pojo.User"

2.1.3 传递java包装对象(重点)

2.1.3.1 UserVo

private User user;

 

public User getUser() {

return user;

}

 

public void setUser(User user) {

this.user = user;

}

2.1.3.2 sql语句编写

Sql 语句 select * from user where username like ‘%李%’

2.1.3.3 Mapper文件

<!-- java包装对象演示  通过用户名称进行模糊查询 -->

<select id="selectUserByUserVo" parameterType="userVo" resultType="user" >

select * from user where username like '%${user.username}%'

</select>

评价:这个区参数没有采用 #{ }的方式进行取值,而且有一种EL表达式的感觉

2.1.3.4 测试

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = new User();

user.setUsername("张");

UserVo vo = new UserVo();

vo.setUser(user);

List<User> users = userMapper.selectUserByUserVo(vo);

System.out.println(users.size());

2.2 resultType (输出映射)

2.2.1 输出简单类型

Mapper.xml

<select id="selectCountUser" resultType="int">

select count(*) from user

</select>

测试类

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

int count = userMapper.selectCountUser();

System.out.println(count);

2.2.2 输出java对象

resultType="user"

2.2.3 输出 list集合

List<User> selectUserByUserVo(UserVo vo);

2.3 resultMap

resultType可以指定java对象查询结果映射为javaBean,但需要javaBean的属性名和sql查询的列名一致才可以映射成功,如果sql查询返回的列名和javaBean的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还需要将查询结果映射到javaBean对象。

resultMap可以实现将查询结果映射为负责类型的javaBean,可以实现一对一和一对多。

我感觉这个很重要

2.3.1 编写Mapper.xml

<!-- 数据库和javaBean的属性映射 -->

<resultMap type="product" id="productBaseResultMap">

<id property="id" column="id" />

<result property="userId" column="user_id" />

<result property="productName" column="product_name" />

<result property="createtime" column="createtime" />

<result property="description" column="description" />

</resultMap>

 

<!-- 查询商品列表 -->

<select id="getProducts" resultMap="productBaseResultMap">

select * from product

</select>

这个property是 javaBean的名称  column 是和数据库对应的

2.3.2 测试

SqlSession sqlSession = sqlSessionFactory.openSession();

ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);

List<Product> products = productMapper.getProducts();

System.out.println(products.size());

3 动态sql

通过mybatis提供的各种标签方法实现动态拼接sql

3.1 if和where

需求:实现通过id或者username查询用户信息

3.1.1 mapper.xml的编写

<select id="selectByIdAndUsername" parameterType="user" resultType="user" >

  select * from user

  <where>

  <if test="id !=null and id !=''">

  id = #{id}

  </if>

  <if test="username !=null and username!=''">

  and username like '%${username}%'

  </if>

  </where>

 </select>

其实后面的用逆向工程编写的代码有很多这样的东西

3.1.2 测试代码的编写

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = new User();

// user.setId(1);

user.setUsername("张");

List<User> users = userMapper.selectByIdAndUsername(user);

System.out.println(users.size());

3.2 foreach

3.2.1 通过指定的ID进行查询用户

Sql语句的编写:

Select * from user where id in(1,2,3);

Mapper.xml的编写:

<select id="queryUserByIds" parameterType="userVo" resultType="user">

  select * from  user

  <where>

  <!--

  collection:可以取值 array list map

  item:当前对象

  index:当前角标

   -->

  <foreach collection="ids" item="id" open="and id in(" close=")" separator="," >

  #{id}

  </foreach>

  </where>

 </select>

传入进进来的参数是一个包装类型的userVo,里面可能有ids这样的集合信息,我们用foreach 遍历

测试类

/**

 * 通过指定的Id进行查询

 */

@Test

public void queryUserByIds() {

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

List ids = new ArrayList();

ids.add("1");

ids.add("2");

ids.add("3");

UserVo vo = new UserVo();

vo.setIds(ids);

List<User> users = userMapper.queryUserByIds(vo);

System.out.println(users.size());

}

3.2.2 通过id批量删除

传统方式在java代码中循环调用

Delete from user where id = ?

Mapper.xml的编写

<delete id="batchDeleteUserByIds" parameterType="Long[]">

  delete from user

  <where>

  <foreach collection="array" item="id" open="and id in(" close=")" separator="," >

  #{id}

  </foreach>

  </where>

 </delete>

测试代码

public void batchDeleteUserByIds() {

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

Long[] ids = new Long[]{7l,28l};

userMapper.batchDeleteUserByIds(ids);

//提交事物

sqlSession.commit();

sqlSession.close();

}

这个后买的l表示的是Long类型的!

3.3 sql片段

Sql中可以将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

<!-- 抽取sql片段 -->

<sql id="fields">

id,username,sex,birthday,address

</sql>

 

<select id="findUserById" parameterType="int" resultType="User" >

select <include refid="fields"/> from user where id = #{id}

</select>

4 关联查询

4.1 一对一查询

一件商品只能属于一个用户。

使用sql查询商品所属的用户信息

select p.*,u.username from product p left join user u on p.user_id = u.id;

4.1.1 在product里面添加user对象

private User user;

 

public User getUser() {

return user;

 

public void setUser(User user) {

this.user = user;

}

这个只是一个demo 我觉得这个商品可以属于很多人

List<User> users = new HashLiset<User>();

这里是这样加属性

private List<User> users;

get/set

4.1.2 编写mapper.xml文件

<!-- 数据库和javaBean的属性映射 -->

<resultMap type="product" id="productBaseResultMap">

<id property="id" column="id" />

<result property="userId" column="user_id" />

<result property="productName" column="product_name" />

<result property="createtime" column="createtime" />

<result property="description" column="description" />

<!-- 添加一对一对应关系 -->

<association property="user" javaType="user" >

<id property="id" column="user_id" />

<result property="username" column="username" />

<result property="sex" column="sex" />

<result property="birthday" column="birthday" />

<result property="address" column="address" />

</association>

</resultMap>

 

<!-- 查询商品列表 -->

<select id="getProducts" resultMap="productBaseResultMap">

select p.*,u.* from product p left join user u on p.user_id = u.id

</select>

4.1.3 测试方法

SqlSession sqlSession = sqlSessionFactory.openSession();

ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);

List<Product> products = productMapper.getProducts();

System.out.println(products.size());

4.2 一对多查询

一个用户可以购买多件商品

查询用户所对应的商品信息sql语句:

select u.*,p.* from user u left join product p on u.id=p.user_id;

4.2.1 在user里面添加product集合

private List<Product> products;

 

public List<Product> getProducts() {

return products;

}

 

public void setProducts(List<Product> products) {

this.products = products;

}

4.2.2 编写mapper.xml文件

<resultMap type="user" id="userProductResultMap">

<id property="id" column="id" />

<result property="username" column="username" />

<result property="sex" column="sex" />

<result property="birthday" column="birthday" />

<result property="address" column="address" />

 

<!-- 定义一对多关联映射 -->

<collection property="products" ofType="product">

<id property="id" column="pid" />

<result property="productName" column="product_name" />

<result property="createtime" column="createtime" />

<result property="description" column="description" />

</collection>

 

</resultMap>

 

 

<!-- 查询所有用户信息 -->

<select id="getUsers" resultMap="userProductResultMap">

select u.*,p.* from user u left join product p on u.id=p.user_id;

</select>

4.2.3 测试方法

public void getUsers() {

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

List<User> users = userMapper.getUsers();

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

}

4.3 延迟加载

需要查询关联信息时,使用mybatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息等用户获取时再加载。

在查询所有用户的时候,不加载用户关联的商品数据,只有在使用商品的属性的时候,才进行加载去数据库进行查询。

4.3.1 开启延迟加载

设置项

描述

允许值

默认值

lazyLoadingEnabled

全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

true | false

false

aggressiveLazyLoading

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

true | false

true

 

<!-- 全局配置参数 -->

<settings>

<!-- 延迟加载总开关 -->

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

<!-- 设置按需加载 -->

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

</settings

4.3.2 sqlMapCofing配置

<settings>

<!-- 延迟加载总开关 -->

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

<!-- 设置按需加载 -->

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

</settings>

4.3.3 mapper.xml文件配置

UserMapper.xml

<resultMap type="user" id="userProductlazyLoad">

<id property="id" column="id" />

<result property="username" column="username" />

<result property="sex" column="sex" />

<result property="birthday" column="birthday" />

<result property="address" column="address" />

 

<!-- 加载商品表数据 -->

<collection property="products" ofType="product" select="com.whhp.mybatis.mapper.ProductMapper.queryProduct" column="id" >

<id property="id" column="pid" />

<result property="productName" column="product_name" />

<result property="createtime" column="createtime" />

<result property="description" column="description" />

</collection>

</resultMap>

 

<!-- 延迟加载 -->

<select id="getUserslazyLoad" resultMap="userProductlazyLoad">

select <include refid="fields" /> from user

</select>

Product.xml

<resultMap type="product" id="BaseResultMap">

<id property="id" column="pid" />

<result property="userId" column="user_id" />

<result property="productName" column="product_name" />

<result property="createtime" column="createtime" />

<result property="description" column="description" />

</resultMap>

 

 

<!-- 通过ID查询product -->

<!-- 查询商品数据-->

<select id="queryProduct" parameterType="int" resultMap="BaseResultMap" >

select * from product where user_id = #{id}

</select>

4.3.4 测试类

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

List<User> users = userMapper.getUserslazyLoad();

User user = users.get(0);

List<Product> products = user.getProducts();

System.out.println(products.size());

5 查询缓存

5.1 一级缓存和二级缓存的范围

Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。

Mybatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。

5.2 一级缓存

测试代码

public void SelectUserByIdWithLevel1Cache() {

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

 

//第一次查询

User user1 = userMapper.findUserById(1);

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

 

//第二次查询

User user2 = userMapper.findUserById(1);

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

sqlSession.close();

}

如果在sqlsession中执行了更新数据库的操作缓存会清空。

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

 

//第一次查询

User user1 = userMapper.findUserById(1);

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

 

//更新操作

User user = new User();

user.setId(1);

user.setUsername("嘿嘿");

user.setAddress("武汉宏鹏");

user.setBirthday(new Date());

user.setSex("2");

userMapper.updateUser(user);

 

//第二次查询

User user2 = userMapper.findUserById(1);

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

sqlSession.close();

5.3 二级缓存

二级缓存区域是根据mapper的namespace划分的,相同namespace的mapper查询数据放在同一个区域, 每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。sqlSession执行insert、update、delete等操作commit提交后会清空缓存区域。

5.3.1 开启二级缓存

在核心配置文件SqlMapConfig.xml中加入

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

 

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

要在你的Mapper映射文件中添加一行:  <cache /> ,表示此mapper开启二级缓存。

<!-- 开启二级缓存 -->

<cache/>

5.3.2 javaBean实现序列化接口

public class User implements Serializable

5.3.3 测试二级缓存

public void SelectUserByIdWithLevel2Cache() {

SqlSession sqlSession1 = sqlSessionFactory.openSession();

UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

User user1 = userMapper1.findUserById(1);

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

sqlSession1.close();

 

 

SqlSession sqlSession2 = sqlSessionFactory.openSession();

UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

User user2 = userMapper2.findUserById(1);

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

sqlSession2.close();

}

5.3.4 更新操作

SqlSession sqlSession1 = sqlSessionFactory.openSession();

UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

User user1 = userMapper1.findUserById(1);

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

sqlSession1.close();

 

 

SqlSession sqlSession3 = sqlSessionFactory.openSession();

UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);

//更新操作

User user = new User();

user.setId(1);

user.setUsername("嘿嘿3");

user.setAddress("武汉宏鹏1");

user.setBirthday(new Date());

user.setSex("1");

userMapper3.updateUser(user);

sqlSession3.commit();

sqlSession3.close();

 

 

SqlSession sqlSession2 = sqlSessionFactory.openSession();

UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

User user2 = userMapper2.findUserById(1);

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

sqlSession2.close();

5.3.5 指定statement关闭二级缓存

<select id="findUserById" parameterType="int" resultType="User" useCache="false" >

select

<include refid="fields" />

from user where id = #{id}

</select>

5.3.6 Cache详解

flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。

readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

如下例子:

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:

  1. LRU – 最近最少使用的:移除最长时间不被使用的对象。
  2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

5.4 Mybatis集成EhCache

5.4.1 修改mapper文件

修改mapper.xml文件,在cache中指定EhcacheCache

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

5.4.2 Ehcache的配置文件

<?xml version="1.0" encoding="UTF-8"?>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

<diskStore path="c:\ehcache" />

<defaultCache 

maxElementsInMemory="1000" 

maxElementsOnDisk="10000000"

eternal="false" 

overflowToDisk="true" 

timeToIdleSeconds="120"

timeToLiveSeconds="120" 

diskExpiryThreadIntervalSeconds="120"

memoryStoreEvictionPolicy="LRU">

</defaultCache>

</ehcache>

属性说明:

l diskStore:指定数据在磁盘中的存储位置。

l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略

以下属性是必须的:

l maxElementsInMemory - 在内存中缓存的element的最大数目 

l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大

l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSecondstimeToLiveSeconds判断

l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上

以下属性是可选的:

l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大

l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大

diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.

l diskPersistent - VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false

l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作

l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)

5.4.3 代码测试

SqlSession sqlSession1 = sqlSessionFactory.openSession();

UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

User user1 = userMapper1.findUserById(1);

System.out.println(user1);

sqlSession1.close();

 

SqlSession sqlSession2 = sqlSessionFactory.openSession();

UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

User user2 = userMapper2.findUserById(1);

System.out.println(user2);

sqlSession2.close();

5.4.4 修改局部配置参数

<cache type="org.mybatis.caches.ehcache.EhcacheCache">

<property name="timeToIdleSeconds" value="600"/>

<property name="timeToLiveSeconds" value="600"/>

</cache>

5.5应用场景和局限性

使用场景:

一般用在查询频率高更新频率低的场景。电商网站商品的查询。

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度。

局限性:

mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。

6 mybatis整合spring

6.1 整合思路

  1. SqlSessionFactory对象应该放到spring容器中作为单例存在。
  2. 传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
  3. Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
  4. 数据库的连接以及数据库连接池事务管理都交给spring容器来完成。

6.2 整合需要的jar包

在第二天的资料文件夹里面

6.3 整合步骤

1 mybatis的配置文件sqlmapConfig.xml

2编写Spring的配置文件

3数据库连接及连接池信息db.properties

4 sqlsessionFactory对象,配置到spring容器中

5 mapeer代理对象或者是dao实现类配置到spring容器中。

6.3.1 创建db.properties配置文件

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8

jdbc.username=root

jdbc.password=root

6.3.2 配置SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

 

<typeAliases>

<package name="com.whhp.mybatis.pojo" />

</typeAliases>

 

<mappers>

<package name="com.whhp.mybatis.mapper"/>

</mappers>

</configuration>

6.3.3 配置beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"

xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

 

<!-- 加载配置文件 -->

<context:property-placeholder location="classpath:db.properties" />

<!-- 数据库连接池 -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"

destroy-method="close">

<property name="driverClassName" value="${jdbc.driver}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

<property name="maxActive" value="10" />

<property name="maxIdle" value="5" />

</bean>

<!-- mapper配置 -->

<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<!-- 数据库连接池 -->

<property name="dataSource" ref="dataSource" />

<!-- 加载mybatis的全局配置文件 -->

<property name="configLocation" value="classpath:sqlMapConfig.xml" />

</bean>

 

<!-- 配置包扫描 -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="com.whhp.mybatis.mapper"></property>

</bean>

 

<!-- dao的配置 -->

<bean id="userDao" class="com.whhp.mybatis.dao.impl.UserDaoImpl">

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

 

</beans>

6.4 Dao的开发

二种dao的实现方式:

1、传统dao的开发方式

2、使用扫描包配置mapper代理。(官方推荐的方式)

6.4.1 传统DAO开发

接口+实现类来完成。需要dao实现类需要继承SqlsessionDaoSupport类

6.4.2 配置DAO

<!-- dao的配置 -->

<bean id="userDao" class="com.whhp.mybatis.dao.impl.UserDaoImpl" >

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

6.4.3 测试代码

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {

@Override

public User getUserById(int id) {

SqlSession sqlSession = getSqlSession();

User user = sqlSession.selectOne("findUserById",id);

//释放资源

return user;

}

ApplicationContext applicationContext;

 

@Before

public void init() {

//初始化spring容器

applicationContext = new ClassPathXmlApplicationContext("classpath:spring/beans.xml");

}

 

@Test

public void getUserById() {

UserDao userDao = applicationContext.getBean(UserDao.class);

User user = userDao.getUserById(1);

System.out.println(user);

}

6.5 Mapper代理开发

6.5.1 配置包扫描

方式一:

<!-- 使用mapper代理开发 -->

<bean class="org.mybatis.spring.mapper.MapperFactoryBean" >

<property name="mapperInterface" value="com.whhp.mybatis.mapper.ProductMapper" />

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

方式二:

<!-- 配置包扫描 -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="com.whhp.mybatis.mapper"></property>

</bean>

配置包扫描之后可以去掉

sqlMapConfig.xml 里面的

<mappers>

<package name="com.whhp.mybatis.mapper"/>

</mappers>

6.5.2 测试代码

ApplicationContext applicationContext;

 

@Before

public void init() {

//初始化spring容器

applicationContext = new ClassPathXmlApplicationContext("classpath:spring/beans.xml");

}

 

@Test

public void getUsers() {

ProductMapper productMapper = applicationContext.getBean(ProductMapper.class);

List<Product> products = productMapper.getProducts();

System.out.println(products.size());

 

}

“mybatis主要是做整合框架的,所以在缓存这一块不够专业!”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值