Mybatis
Mybatis
一、引言
web应用架构: 单体架构, 垂直架构, 分布式架构
垂直架构分层:
数据层: 负责处理数据库操作.
包名: dao
底层技术: jdbc
代表框架: mybatis, hibernate
业务逻辑层: 负责业务流程处理和代码增强
包名: service
底层技术: 无
代表框架: spring
展现层: 负责业务控制和视图
包名: action, controller
底层技术: servlet
代表框架: springmvc, struts2
二、初始Mybatis
概念:
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录。
MyBatis 本是apache的一个开源项目ibatis, 2010年这个项目由apache 迁移到了google code,并且改名为MyBatis 。
2013年11月迁移到Github .
Mybatis官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html
GitHub :
作用:
· Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .
· 传统的jdbc操作 , 有很多重复代码块 .比如 : 数据取出时的封装 , 数据库的建立连接等等, 通过框架可以减少重复代码,提高开发效率 .
· MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射
· 所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!技术没有高低之分,只有使用这个技术的人有高低之别
优点:
·简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
·灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
· 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
· 提供xml标签,支持编写动态sql。
· 最重要的一点,使用的人多!公司需要!
三、使用
0. 环境准备:
1) sql
2) jar包
3) mybatis配置文件(3个主要内容)
1. 编写与数据表对应的实体类.
2. 编写数据接口.
包名: dao
接口命名: 实体类名+Mapper, 实体类名+Dao. 例: UserMapper
3. 编写数据接口映射文件. (重要)
文件位置: resources下的dao文件夹中. 该文件路径要求与数据接口所在包一致
命名: 数据接口名.xml
引用: 每有一个数据接口映射文件, 都需要在mybatis配置文件中进行引用
数据接口映射文件的作用: 在mybatis代码运行时, 会将数据接口映射文件解析成对应数据接口的实现类.
接口映射文件的内容:4大sql标签, 结果映射标签
四、动态SQL
动态SQL: 通过mapper映射文件提供的标签, 达到根据参数具体情况决定最终执行的sql语句的目的
常用的标签:
1. <if test="">判断结果为true时, 向整个sql中添加的内容</if>
根据test属性中的判断结果, 决定是否添加指定的sql内容.
2. <set></set>
用于取代set关键字. 自动去除赋值语句中多余的","
如果最终set标签中, 没有任何一条赋值语句, 则set标签不会被翻译成set关键字
3. <where></where>
用于取代where关键字.
自动去除条件语句中多余的"and"或"or"
如果, 最终where标签中, 没有任何一条条件语句, 则where抱歉不会被翻译成where关键字
4. <bind name="参数名" value="新的值">
5. <choose>
<when test=""></when>
<when test=""></when>
....
<otherwise></otherwise>
</choose>
6. <foreach collection="需要遍历的集合或数组" item="临时变量" separator="循环内容之间的分隔符"
open="循环开始前的内容" close="循环结束后的内容"></foreach>
五、关联查询
关联查询: 多对多
主表1: 一
中间表: 多
主表2: 一
多对多的使用步骤:
1. 在实体类
i. 在主表对应实体类中添加成员变量.
成员变量的数据类型: List
泛型类型: 另一个主表对应的实体类型
ii. get/set方法
2. 接口映射文件
i. 在结果集映射中, 添加collection标签
ii. 设置collection标签的property属性. 属性值是实体类中的代表另一个主表的成员变量的变量名
iii.设置collection标签的column属性. 属性值是主键字段名. 表示执行关联查询时, 携带到查询语句中的参数
iv. 设置collection标签的select属性. 属性值是用于查询另一个主表数据的查询语句的id
v. 编写用于查询另一个主表对象集合的查询语句, id与collection标签的select属性值一致.
resultMap属性引用的结果集映射id需要额外声明
vi. 添加新的结果集映射, id需要被 v. 的查询语句引用
关联查询 多对一:
前提: 两张数据表之间具有事实上的引用关系
使用的标签: collection, association
标签使用的位置: 在结果集映射的末尾声明
多: 引用的一方, 外键所在的表, 子表
一: 被引用的一方, 主表
使用步骤:
1. association的使用步骤: (多对一)
1) 在实体类中:
i. 添加属性
数据类型: 一方的实体类型
ii. 添加get/set方法
2) 在数据接口映射文件中:
i. 在结果集映射中, 添加association标签
ii. 设置association标签的property属性. 属性值是实体类中的代表一方的成员变量的变量名
iii.设置association标签的column属性. 属性值是外键字段名. 表示执行关联查询时, 携带到查询语句中的参数
iv. 设置association标签的select属性. 属性值是用于查询一方数据的查询语句的id
v. 编写用于查询一方对象的查询语句, id与association标签的select属性值一致.
resultMap属性引用的结果集映射id需要额外声明
vi. 添加新的结果集映射, id需要被 v. 的查询语句引用
2. collection的使用步骤: (一对多)
1) 在实体类中:
i. 添加属性
数据类型: List
泛型: 多方的实体类型
ii. 添加get/set方法
2) 在数据接口映射文件中:
i. 在结果集映射中, 添加collection标签
ii. 设置collection标签的property属性. 属性值是实体类中的代表多方的成员变量的变量名
iii.设置collection标签的column属性. 属性值是主键字段名. 表示执行关联查询时, 携带到查询语句中的参数
iv. 设置collection标签的select属性. 属性值是用于查询多方数据的查询语句的id
v. 编写用于查询多方对象集合的查询语句, id与collection标签的select属性值一致.
resultMap属性引用的结果集映射id需要额外声明
vi. 添加新的结果集映射, id需要被 v. 的查询语句引用
六、缓存
6.1 简介
1、什么是缓存 [ Cache ]?
· 存在内存中的临时数据。
· 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2、为什么使用缓存?
· 减少和数据库的交互次数,减少系统开销,提高系统效率。
3、什么样的数据能使用缓存?
· 经常查询并且不经常改变的数据。
6.2 Mybatis缓存
· MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
· MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
§ 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
§ 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
§ 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
6.3一级缓存
一级缓存也叫本地缓存:
· 与数据库同一次会话期间查询到的数据会放在本地缓存中。
· 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
测试
1、在mybatis中加入日志,方便测试结果
2、编写接口方法
//根据id查询用户
User queryUserById(
3、接口对应的Mapper文件
<select id="queryUserById" resultType="user">
select * from user where id = #{id}
</select>
4、测试
5、结果分析
一级缓存失效的四种情况
一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求!
1、sqlSession不同
观察结果:发现发送了两条SQL语句!
结论:每个**sqlSession中的缓存相互独立**
2、sqlSession相同,查询条件不同
观察结果:发现发送了两条SQL语句!很正常的理解
结论:当前缓存中,不存在这个数据
3、sqlSession相同,两次查询之间执行了增删改操作!
增加方法
//修改用户 int updateUser(Map map);
编写SQL
<update id="updateUser" parameterType="map">
update user set name = #{name} where id = #{id}
</update>
测试
观察结果:查询在中间执行了增删改操作后,重新执行了
结论:因为增删改操作可能会对当前数据产生影响
4、sqlSession相同,手动清除一级缓存
一级缓存就是一个map
10.4 二级缓存
· 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
· 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
· 工作机制
§ 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
§ 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
§ 新的会话查询信息,就可以从二级缓存中获取内容;
§ 不同的mapper查出的数据会放在自己对应的缓存(map)中;
使用步骤
1、开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
<cache/>
官方示例=>查看官方文档 <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
3、代码测试
· 所有的实体类先实现序列化接口
· 测试代码
结论
· 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
· 查出的数据都会被默认先放在一级缓存中
· 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
缓存原理图

浙公网安备 33010602011771号