目录
Mybatis 基础概念
Mybatis 开放方式演进
Mybatis 框架核心要点
关联查询
延迟加载(懒加载)
动态 SQL
Mybatis 缓存
Mybatis 逆向工程
PageHelper 分页插件
注解开发
Mybatis 基础概念
Mybatis 是一个持久层框架
它对 JDBC 操作数据库进行封装, 让我们更关注 SQL 本身, 而不需要花费精力去处理例如注册驱动, 创建 connection, 创建 statement, 手动设置参数, 结果集检索等 jdbc 繁杂的过程代码. 下面是 Mybatis 的架构图
Mybatis 又是如何解决 JDBC 中存在的问题呢?
1, 创建数据库连接相关操作, 存在硬编码
a) 解决方案: 通过 Mybatis 全局配置文件, 对数据库连接进行配置
2, statement 相关操作, 存在硬编码
a) 解决方案: 通过 Mapper 映射文件, 对 statement 相关处理进行配置.
3, 频繁开启数据库连接, 会降低数据库处理性能.
a) 解决方案: 通过 Mybatis 全局配置文件, 配置连接池.
Mybatis 开放方式演进
Mybatis 框架核心要点
关联查询
所谓的关联查询就是一对一和一对多以及多对多的应用, 例如下面的例子
一对一 : 例如在获取订单的时候需要获取该订单所属的用户信息
解决思路 : 使用 ResultMap 或者 ResultType 自定义一个 POJO 进行结果映射
一对多 : 例如在获取用户信息的时候需要获取该用户的所有订单信息
解决思路 : 自定义一个 POJO 使用(只能使用)ResultMap 进行结果映射
延迟加载(懒加载)
关于延迟加载
MyBatis 中的延迟加载, 也称为懒加载, 是指在进行关联查询时, 按照设置延迟规则推迟对关联对象的 select 查询. 延迟加载可以有效的减少数据库压力.
Mybatis 的延迟加载, 需要通过 resultMap 标签中的 association 和 collection 子标签才能演示成功.
Mybatis 的延迟加载, 也被称为是嵌套查询, 对应的还有嵌套结果的概念, 可以参考一对多关联的案例.
注意: MyBatis 的延迟加载只是对关联对象的查询有延迟设置, 对于主加载对象都是直接执行查询语句的.
延迟加载分类
MyBatis 根据对关联对象查询的 select 语句的执行时机, 分为三种类型: 直接加载, 侵入式加载与深度延迟加载
直接加载: 执行完对主加载对象的 select 语句, 马上执行对关联对象的 select 查询.
侵入式延迟: 执行对主加载对象的查询时, 不会执行对关联对象的查询. 但当要访问主加载对象的详情时, 就会马上执行关联对象的 select 查询. 即对关联对象的查询执行, 侵入到了主加载对象的详情访问中. 也可以这样理解: 将关联对象的详情侵入到了主加载对象的详情中, 即将关联对象的详情作为主加载对象的详情的一部分出现了.
深度延迟: 执行对主加载对象的查询时, 不会执行对关联对象的查询. 访问主加载对象的详情时也不会执行关联对象的 select 查询. 只有当真正访问关联对象的详情时, 才会执行对关联对象的 select 查询.
延迟加载策略需要在 Mybatis 的全局配置文件中, 通过标签进行设置.
如何使用
直接加载 通过对全局参数: lazyLoadingEnabled 进行设置, 默认就是 false.
- <settings>
- <!-- 延迟加载总开关 -->
- <setting name="lazyLoadingEnabled" value="false"/>
- </settings>
侵入式加载
- <settings>
- <!-- 延迟加载总开关 -->
- <setting name="lazyLoadingEnabled" value="true"/>
- <!-- 侵入式延迟加载开关 -->
- <setting name="aggressiveLazyLoading" value="true"/>
- </settings>
深度延迟加载
- <settings>
- <!-- 延迟加载总开关 -->
- <setting name="lazyLoadingEnabled" value="true"/>
- <!-- 侵入式延迟加载开关 -->
- <setting name="aggressiveLazyLoading" value="false"/>
- </settings>
动态 SQL
动态 SQL 的思想: 就是使用不同的动态 SQL 标签去完成 SQL 字符串的拼接处理.
解决的问题 :
在映射文件中, 会编写很多有重叠部分的 SQL 语句, 比如 SELECT 语句和 WHERE 语句等这些重叠语句, 该如何处理
如果页面传递过来一个参数, 但是 SQL 语句中的条件有多个, 此时会发生问题.
主要标签
if 标签 where 标签 sql 片段 foreach 标签
Mybatis 缓存
Mybatis 提供查询缓存, 如果缓存中有数据就不用从数据库中获取, 用于减轻数据压力, 提高系统性能.
Mybatis 的查询缓存总共有两级, 我们称之为一级缓存和二级缓存, 如图:
• 一级缓存是 SqlSession 级别的缓存. 在操作数据库时需要构造 sqlSession 对象, 在对象中有一个数据结构 (HashMap) 用于存储缓存数据. 不同的 sqlSession 之间的缓存数据区域 (HashMap) 是互相不影响的.
• 二级缓存是 Mapper(namespace)级别的缓存. 多个 SqlSession 去操作同一个 Mapper 的 sql 语句, 多个 SqlSession 可以共用二级缓存, 二级缓存是跨 SqlSession 的.
一级缓存原理图
第一次发起查询用户 id 为 1 的用户信息, 先去找缓存中是否有 id 为 1 的用户信息, 如果没有, 从数据库查询用户信息, 将查询到的用户信息存储到一级缓存中.
如果中间 sqlSession 去执行 commit 操作(执行插入, 更新, 删除), 清空 SqlSession 中的一级缓存, 这样做的目的为了让缓存中存储的是最新的信息, 避免脏读.
第二次发起查询用户 id 为 1 的用户信息, 先去找缓存中是否有 id 为 1 的用户信息, 缓存中有, 直接从缓存中获取用户信息.
二级缓存原理图
第一次调用 mapper 下的 SQL 去查询用户信息. 查询到的信息会存到该 mapper 对应的二级缓存区域内.
第二次调用相同 namespace 下的 mapper 映射文件中相同的 SQL 去查询用户信息. 会去对应的二级缓存内取结果.
如果调用相同 namespace 下的 mapper 映射文件中的增删改 SQL, 并执行了 commit 操作. 此时会清空该 namespace 下的二级缓存.
如何开启二级缓存(默认关闭)
在核心配置文件 SqlMapConfig.xml 中加入以下内容(开启二级缓存总开关):
<!-- 开启二级缓存总开关 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>
在 UserMapper 映射文件中, 加入以下内容, 开启二级缓存:
<!-- 开启本 mapper 下的 namespace 的二级缓存, 默认使用的是 mybatis 提供的 PerpetualCache --> <cache> </cache>
说明 : 由于二级缓存的数据不一定都是存储到内存中, 它的存储介质多种多样, 比如说存储到文件系统中, 所以需要给缓存的对象执行序列化. 如果该类存在父类, 那么父类也要实现序列化.(既查询结果对象要实现序列化接口)
Mybatis 逆向工程
由于 Mybatis 是半自动化的 ORM 框架, 所以仍然有很多事情需要我们去做
例如 : 编写与数据库表对应的实体, 编写 Mapper 接口, 编写 Mapper 配置文件
所谓的 Mybatis 逆向工程仅仅是一个项目所以只需要在下面配置中填写好自己数据库的相关信息, 运行 main 方法既可以为我们生成 POJO 类, Mapper 接口, Mapper 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="testTables" targetRuntime="MyBatis3"> <commentGenerator> <!-- 是否去除自动生成的注释 true: 是 : false: 否 --> <property name="suppressAllComments" value="true" /> </commentGenerator> <!-- 数据库连接的信息: 驱动类, 连接地址, 用户名, 密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root"> </jdbcConnection> <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" userId="yycg" password="yycg"> </jdbcConnection> --> <!-- 默认 false, 把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer, 为 true 时把 JDBC DECIMAL 和 NUMERIC 类型解析为 java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetProject: 生成 PO 类的位置 --> <javaModelGenerator targetPackage="com.kkb.ms.po" targetProject=".\src"> <!-- enableSubPackages: 是否让 schema 作为包的后缀 --> <property name="enableSubPackages" value="false" /> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- targetProject:mapper 映射文件生成的位置 --> <sqlMapGenerator targetPackage="com.kkb.ms.mapper" targetProject=".\src"> <!-- enableSubPackages: 是否让 schema 作为包的后缀 --> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage:mapper 接口生成的位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.kkb.ms.mapper" targetProject=".\src"> <!-- enableSubPackages: 是否让 schema 作为包的后缀 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!-- 指定数据库表 --> <table schema=""tableName="user"></table> <table schema=""tableName="order"></table> </context> </generatorConfiguration>
注意 : 每次执行逆向工程代码之前, 先删除原来已经生成的 mapper xml 文件再进行生成. mapper.xml 文件的内容不是被覆盖而是进行内容追加, 会导致 mybatis 解析失败. po 类及 mapper.java 文件的内容是直接覆盖没有此问题.
PageHelper 分页插件
如果你也在用 Mybatis, 建议尝试该分页插件, 这个一定是最方便使用的分页插件.
使用方法如下
首先增加依赖
<dependency> <groupId>com.GitHub.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.6</version> </dependency>
配置 PageHelper
• Mybatis 全局配置文件
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- config params as the following --> <property name="helperDialect" value="mysql"/> </plugin> </plugins>
• Spring 配置文件
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- other configuration --> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!-- config params as the following --> <value> helperDialect=MySQL </value> </property> </bean> </array> </property> </bean>
在项目中使用 PageHelper
// 获取第 1 页, 10 条内容, 默认查询总数 count PageHelper.startPage(1, 10); List<Country> list = countryMapper.selectAll(); // 用 PageInfo 对结果进行包装 PageInfo page = new PageInfo(list); // 测试 PageInfo 全部属性 //PageInfo 包含了非常全面的分页属性 assertEquals(1, page.getPageNum()); assertEquals(10, page.getPageSize());
注意事项
需要分页的查询语句, 必须是处于 PageHelper.startPage(1, 10); 后面的第一条语句.
如果查询语句是使用 resultMap 进行的嵌套结果映射, 则无法使用 PageHelper 进行分页.
Mybatis 插件介绍
参考地址: https://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html
StatementHandler ParameterHandler ResultSetHandler
注解开发
使用注解开发, 我们不再需要 xml 配置文件
常用注解说明
增删改查 - 静态 SQL
@Insert: 相当于标签, 实现新增
@Update: 相当于标签, 实现更新
@Delete: 相当于标签, 实现删除
@Select: 相当于标签, 实现查询
多表关联
• @Results: 相当于 < resultMap > 标签, 需要和 @Result 注解一起使用.
• @Result: 相当于 < result > 和 < id > 标签, 实现结果集中某一列的数据映射
* column 数据库的列名
* property 需要装配的属性名
* one 需要使用的 @One 注解(@Result(one=@One()))
* many 需要使用的 @Many 注解(@Result(many=@many()))
• @One: 相当于 < association > 标签, 实现一对一关系映射
• @Many: 相当于 < collection > 标签, 实现一对多关系映射
• @One 和 @Many 注解的属性:
* select 属性: 代表将要执行的 sql 语句
* fetchType 属性: 代表加载方式, 一般如果要延迟加载都设置为 LAZY 的值
• 使用格式:
1. @Results({@Result(),@Result()})或 @Results(@Result())
2. @Result(column="",property="",one=@One(select=""))
辅助注解
@Options: 相当于标签属性的设置
@Param: 如果你的映射器的方法需要多个参数, 这个注解可以被应用于映射器的方法参数来给每个参数一个名字.
其他注解
@CacheNamespace: 相当于标签, 实现二级缓存.
属性: implemetation,eviction,flushInterval,size,readWrite,blocking 和 properties
来源: https://www.cnblogs.com/jimisun/p/10212018.html