Mybatis 利用剖析和最佳实际
以下是一些 MyBatis 的高级用法或者扩大形式,帮忙咱们更好地应用 MyBatis。
为什么要动静 SQL
防止因为前端传入的查问参数不同,所以导致写很多的 if else, 还须要十分留神 SQL 语句中的 and,空格,逗号和本义的单引号,拼接和调试 sql 十分耗时。
Mybatis 的动静 SQL 就解决了这个问题,其是基于 OGNL 表达式的。
动静标签
if
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state =‘ACTIVE’<if test="title != null">
AND title like #{title}
</if>
</select>
choose(when,otherwise)
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state =‘ACTIVE’<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim(where,set)
个别用来去掉前缀后者或追
<trim prefix="WHERE" prefixOverrides="AND |OR">
...
</trim>
foreach
须要遍历汇合的时候动静生成语句
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
批量操作
咱们在生产的我的项目中会有一些批量操作的场景,比方导入文件批量解决数据的状况(批量新增商户、批量批改商户信息),当数据量十分大,比方超过几万条的时候,在 Java 代码中循环发送 SQL 到数据库执行必定是不事实的,因为这个意味着要跟数据库创立几万次会话,即便咱们应用了数据库连接池技术,对于数据库服务器来说也是不堪重负的。
在 MyBatis 外面是反对批量的操作的,包含批量的插入、更新、删除。咱们能够直 接传入一个 List、Set、Map 或者数组,配合动静 SQL 的标签,MyBatis 会主动帮咱们 生成语法正确的 SQL 语句。
比方咱们来看两个例子,批量插入和批量更新。
批量插入
批量插入的语法是这样的,只有在 values 前面减少插入的值就能够了。
insert into tbl_emp (emp_id, emp_name, gender,email, d_id) values (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?) , (?,?,?,?,?)
在 Mapper 文件外面,咱们应用 foreach 标签拼接 values 局部的语句:
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true">
<selectKey resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into tbl_emp (emp_id, emp_name, gender,email, d_id)
values
<foreach collection="list" item="emps" index="index" separator=",">
(#{emps.empId},#{emps.empName},#{emps.gender},#{emps.email},#{emps.dId} )
</foreach>
</insert>
Java 代码外面,间接传入一个 List 类型的参数。
咱们来测试一下。效率要比循环发送 SQL 执行要高得多。最要害的中央就在于缩小了跟数据库交互的次数,并且防止了开启和完结事务的工夫耗费。
@Test
public void testBatchInsert() {List<Employee> list = new ArrayList<Employee>();
long start = System.currentTimeMillis();
int count = 100000;
// max_allowed_packet 默认 4M,所以超过长度会报错
for (int i = 0; i < count; i++) {
String gender = i % 2 == 0 ? "M" : "F";
Integer did = i % 2 == 0 ? 1 : 2;
Employee emp = new Employee(null, "TestName" + i, gender, "pony@baidu.com", did);
list.add(emp);
}
employeeMapper.batchInsert(list);
long end = System.currentTimeMillis();
System.out.println("批量插入" + count + "条,耗时:" + (end - start) + "毫秒");
}
批量更新
<!-- 批量更新 -->
<!-- 留神 separator 和 open -->
<update id="updateBatch">
update tbl_emp set
emp_name =
<foreach collection="list" item="emps" index="index" separator="" open="case emp_id"close="end">
when #{emps.empId} then #{emps.empName}
</foreach>
,gender =
<foreach collection="list" item="emps" index="index" separator="" open="case emp_id"close="end">
when #{emps.empId} then #{emps.gender}
</foreach>
,email =
<foreach collection="list" item="emps" index="index" separator="" open="case emp_id"close="end">
when #{emps.empId} then #{emps.email}
</foreach>
where emp_id in
<foreach collection="list" item="emps" index="index" separator="," open="(" close=")">
#{emps.empId}
</foreach>
</update>
批量删除也是相似的
Batch Executor
当然 MyBatis 的动静标签的批量操作也是存在肯定的毛病的,比方数据量特地大的 时候,拼接进去的 SQL 语句过大。
MySQL 的服务端对于接管的数据包有大小限度,max_allowed_packet
默认是 4M,须要批改默认配置才能够解决这个问题。
Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (7188967 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.
在咱们的全局配置文件中,能够配置默认的 Executor 的类型。其中有一种 BatchExecutor。
<setting name="defaultExecutorType" value="BATCH"
也能够在创立会话的时候指定执行器类型
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
BatchExecutor 底层是对 JDBC ps.addBatch()的封装,原理是攒一批 SQL 当前再发
还有一个可能对你来说是新见到的参数,就是 ExecutorType
。这个枚举类型定义了三个值:
ExecutorType.SIMPLE
:这个执行器类型不做非凡的事件。它为每个语句的执行创立一个新的预处理语句。ExecutorType.REUSE
:这个执行器类型会复用预处理语句。ExecutorType.BATCH
:这个执行器会批量执行所有更新语句,如果 SELECT 在它们两头执行,必要时请把它们辨别开来以保障行为的易读性。
JDBC BatchExecutor 应用
public void testJdbcBatch() throws IOException {
Connection conn = null;
PreparedStatement ps = null;
try {Long start = System.currentTimeMillis();
// 关上连贯
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true", "root", "123456");
ps = conn.prepareStatement("INSERT into blog values (?, ?, ?)");
for (int i = 1000; i < 101000; i++) {Blog blog = new Blog();
ps.setInt(1, i);
ps.setString(2, String.valueOf(i)+"");
ps.setInt(3, 1001);
//ExecuteType=BATCH 就是对于这个 ps 的封装,批量插入 500w 的数据,用这个性能会失去很大改善 <br>
ps.addBatch();}
ps.executeBatch();
// conn.commit();
ps.close();
conn.close();
Long end = System.currentTimeMillis();
System.out.println("cost:"+(end -start) +"ms");
} catch (SQLException se) {se.printStackTrace();
} catch (Exception e) {e.printStackTrace();
} finally {
try {if (ps != null) ps.close();} catch (SQLException se2) { }
try {if (conn != null) conn.close();} catch (SQLException se) {se.printStackTrace();
}
}
}
}
三种 Executor 的区别
SimpleExecutor
每执行一次 update 或 select, 就开启一个 Statement 对象, 用完立即敞开 Statement 对象。
ReuseExecutor
- 执行 update 或 select, 以 sql 作为 key 查找 Statement 对象, 存在就应用, 不存在就创立
- 用完后, 不敞开 Statement 对象, 而是搁置于 Map 内, 供下一次应用。
- 简言之, 就是重复使用 Statement 对象
Batch Executor
-
执行 update(没有 select,JDBC 批处理不反对 select)
- 将所有 SQL 都增加到批处理中(add Batch())
- 期待对立执行 (executebatch()), 它缓存了多个 Statement 对象, 每个 Statement 对象都是 add Batch() 结束后, 期待逐个执行 execute Batch0 批处理。与 DBC 批处理雷同。
-
executeupdate()
- 是一个语句拜访一次数据库
-
executebatch()
- 是一批语句访词一次数据库(具体一批发送多少条 SQL 跟服务端的 max allowed packet 无关)。
-
Batchexecutor 底层是对 JDBC
- ps. add Batch()
- ps. execute Batch()的封装。
嵌套(关联查问 /N+1/ 提早加载)
https://mybatis.org/mybatis-3…
咱们在查问业务数据的时候常常会遇到跨表关联查问的状况,比方查问员工就会关联部门(一对一),查问问题就会关联课程(一对一),查问订单就会关联商品(一对多),等等。
咱们映射后果有两个标签,一个是 resultType,一个是 resultMap。
resultType 是 select 标签的一个属性,实用于返回 JDK 类型 (比方 Integer、String 等等) 和实体类。这种状况下后果集的列和实体类的属性能够间接映射。如果返回的字
段无奈间接映射,就要用 resultMap 来建设映射关系。对于关联查问的这种状况,通常不能用 resultType 来映射。用 resultMap 映射,要么就是批改 dto(Data Transfer Object),在外面减少字段,这个会导致减少很多无关的字段。要么就是援用关联的对象,比方 Blog 外面蕴含了一个 Author 对象,这种状况 下就要用到关联查问(association,或者嵌套查问),MyBatis 能够帮咱们主动做后果 的映射。
一对一的关联查问有两种配置形式:
嵌套后果
<!-- 依据文章查问作者,一对一查问的后果,嵌套后果 -->
<resultMap id="BlogWithAuthorResultMap" type="com.zzjson.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<!-- 联结查问,将 author 的属性映射到 ResultMap -->
<association property="author" javaType="com.zzjson.domain.Author">
<id column="author_id" property="authorId"/>
<result column="author_name" property="authorName"/>
</association>
</resultMap>
<!-- 依据文章查问作者,一对一,嵌套后果,无 N + 1 问题 -->
<select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap">
select b.bid, b.name, b.author_id, a.author_id, a.author_name
from blog b
left join author a
on b.author_id = a.author_id
where b.bid = #{bid, jdbcType=INTEGER}
</select>
嵌套查问 N+ 1 问题
<!-- 另一种联结查问 (一对一) 的实现,然而这种形式有“N+1”的问题 -->
<resultMap id="BlogWithAuthorQueryMap" type="com.zzjson.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="author" javaType="com.zzjson.domain.Author"
column="author_id" select="selectAuthor"/> <!-- selectAuthor 定义在上面 -->
</resultMap>
<!-- 嵌套查问 -->
<select id="selectAuthor" parameterType="int" resultType="com.zzjson.domain.Author">
select author_id authorId, author_name authorName
from author
where author_id = #{authorId}
</select>
是分两次查问,当咱们查问了员工信息之后,会再次发送一条 SQL 到数据库查问部门信息。
咱们只执行了一次查问员工信息的 SQL(所谓的 1),如果返回了 N 条记录,就会再发送 N 条到数据库查问部门信息(所谓的 N), 这就是咱们说的 N + 1 的问题,这样会白白的节约咱们的利用和数据库的性能。
懒加载
如果咱们应用了嵌套查问的形式,怎么解决这个问题?
能不能等到应用部门信息的时候再去查问?这就是咱们所说的提早加载,或者叫懒加载
在 Mybatis 外面能够通过开启提早加载的开关来解决这个问题。
setting 配置 + 代理
在 setting 标签外面能够配置
<!-- 提早加载的全局开关。当开启时,所有关联对象都会提早加载。默认 false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当开启时,任何办法的调用都会加载该对象的所有属性。默认 false,可通过 select 标签的 fetchType 来笼罩 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- Mybatis 创立具备提早加载能力的对象所用到的代理工具,默认 JAVASSIST-->
<setting name ="proxyFactory" value="CGLIB"/>
lazyLoadingEnabled 决定了是否提早加载。
aggressiveLazyLoading 决定了是不是对象的所有办法都会触发查问。
先来测试一下(也能够改成查问列表):
1、没有开启提早加载的开关,会间断发送两次查问;
2、开启了提早加载的开关,调用 blog.getAuthor()以及 默认的 (equals,clone,hashCode,toString)
时才会发动第二次查问,其余办法并不会触发查问,比方 blog.getName()
;
3、如果开启了 aggressiveLazyLoading=true
,其余办法也会触发查问,比方blog.getName()
。
问题: 为什么能够做到提早加载?
blog.getAuthor(),只是一个获取属性的办法,外面并没有连贯数据库的代码,为什么会触发对数据库的查问呢?
是因为咱们这个类被代理了
System.out.println(blog.getClass());
打印进去果然不对
class com.zzjson.domain.associate.BlogAndAuthor_$$_jvst70_0
这个类的名字前面有 jvst,是 JAVASSIST 的缩写
当开启了提早加载的开关,对象是怎么变成代理对象的?
DefaultResultSetHandler.createResultObject()
既然是代理对象,那么必须要有一种创立代理对象的办法。咱们有哪些实现动静代 理的形式?
这个就是为什么 settings 外面提供了一个 ProxyFactory 属性。MyBatis 默认应用 JAVASSIST 创立代理对象。也能够改为 CGLIB,这时须要引入 CGLIB 的包。
CGLIB 和 JAVASSIST 区别是什么?
测试一下,咱们把默认的 JAVASSIST 批改为 CGLIB,再打印这个对象。
分页
RowBounds
public void testSelectByRowBounds() throws IOException {SqlSession session = sqlSessionFactory.openSession();
try {BlogMapper mapper = session.getMapper(BlogMapper.class);
int start = 0; // offset
int pageSize = 5; // limit
RowBounds rb = new RowBounds(start, pageSize);
List<Blog> list = mapper.selectBlogList(rb); // 应用逻辑分页
for(Blog b :list){System.out.println(b);
}
} finally {session.close();
}
}
参数传入 RowBounds
- 是一个伪的分页,实际上会先查问所有,而后获取多少条
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap
手动 limit
<select id="selectBlogPage" parameterType="map" resultMap="BaseResultMap">
select * from blog limit #{curIndex} , #{pageSize}
</select>
须要在 java 代码计算序号
PageHelper
https://github.com/pagehelper…
-
利用插件
- ThreadLocal 来设置
依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>x.x.x</version>
</dependency>
插件配置
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- config params as the following -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
应用
静态方法调用
// 获取第 1 页,10 条内容,默认查问总数 count
PageHelper.startPage(1, 10);
PageInfo
// 获取第 1 页,10 条内容,默认查问总数 count
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll();
// 用 PageInfo 对后果进行包装
PageInfo page = new PageInfo(list);
参数形式
<plugins>
<!-- com.github.pagehelper 为 PageHelper 类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 应用上面的形式配置参数,前面会有所有的参数介绍 -->
<property name="supportMethodsArguments" value="true"/>
<property name="params" value="pageNum=pageNumKey;pageSize=pageSizeKey;"/>
</plugin>
</plugins>
List<User> selectByPageNumSize(@Param("user") User user,
@Param("pageNumKey") int pageNum,
@Param("pageSizeKey") int pageSize);
MybatisGenerator
https://github.com/mybatis/ge…
咱们在我的项目中应用 MyBaits 的时候,针对须要操作的一张表,须要 创立实体类、Mapper 映射器、Mapper 接口
,外面又有很多的字段和办法的配置,这部分的工作是 十分繁琐的。而大部分时候咱们对于表的操作是雷同的,比方依据主键查问、依据 Map 查问、单条插入、批量插入、依据主键删除等等等等。当咱们的表很多的时候,意味着 有大量的反复工作。所以有没有一种方法,能够依据咱们的表,主动生成 实体类、Mapper 映射器、Mapper 接口
,外面蕴含了咱们须要用到的这些根本办法和 SQL 呢?
MyBatis 也提供了一个这样的货色,叫做 MyBatis Generator,简称 MBG。咱们只须要批改一个配置文件,应用相干的 jar 包命令或者 Java 代码就能够帮忙咱们生成实体类、映射器和接口文件。不晓得用 MyBatis 的同学有没有跟当年的我一样,还是实体类的一个一个字段,接口的一个一个办法,映射器的一条一条 SQL 去写的。
MBG 的配置文件外面有一个 Example 的开关,这个货色用来结构简单的筛选条件的,换句话说就是依据咱们的代码去生成 where 条件
原理: 在实体类中蕴含了两个有继承关系的 Criteria,用其中主动生成的办法来构建查问条件。把这个蕴含了 Criteria 的实体类作为参数传到查问参数中,在解析 Mapper 映射器的时候会转换成 SQL 条件。
(mybatis-standalone 工程:
com.zzjson.domain.BlogExample
com.zzjson.BlogExampleTest)
BlogExample 外面蕴含了一个两个 Criteria:
实例: 查问 bid=1 的 Blog,通过创立一个 Criteria 去构建查问条件:
BlogMapper mapper = session.getMapper(BlogMapper.class);
BlogExample example = new BlogExample();
BlogExample.Criteria criteria = example.createCriteria();
criteria.andBidEqualTo(1);
List<Blog> list = mapper.selectByExample(example);
生成的语句
select 'true' as QUERYID, bid, name, author_id from blog WHERE (bid = ?)
翻页
在写存储过程的年代,翻页也是一件很难调试的事件,咱们要实现数据不多不少精确地返回,须要大量的调试和批改。然而如果本人手写过分页,就能分明分页的原理。
在咱们查询数据库的操作中,有两种翻页形式,一种是逻辑翻页(假分页),一种是物理翻页(真分页)。逻辑翻页的原理是把所有数据查出来,在内存中删选数据。物理翻页是真正的翻页,比方 MySQL 应用 limit 语句,Oracle 应用 rownum 语句,SQLServer 应用 top 语句。
逻辑翻页
MyBatis 外面有一个逻辑分页对象 RowBounds,外面次要有两个属性,offset 和 limit(从第几条开始,查问多少条)。
咱们能够在 Mapper 接口的办法上加上这个参数,不须要批改 xml 外面的 SQL 语句。
public List<Blog> selectBlogList(RowBounds rowBounds);
应用:mybatis-standalone- MyBatisTest-testSelectByRowBounds()
int start = 10; // offset,从第几行开始查问
int pageSize = 5; // limit,查问多少条
RowBounds rb = new RowBounds(start, pageSize);
List<Blog> list = mapper.selectBlogList(rb); for(Blog b :list){System.out.println(b);
}
它的底层其实是对 ResultSet 的解决。它会舍弃掉后面 offset 条数据,而后再取剩下的数据的 limit 条。
// DefaultResultSetHandler.java
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext();
ResultSet resultSet = rsw.getResultSet();
this.skipRows(resultSet, rowBounds);
while(this.shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(resultSet,
resultMap, (String)null);
Object rowValue = this.getRowValue(rsw, discriminatedResultMap, (String)null);
this.storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); }
}
很显著,如果数据量大的话,这种翻页形式效率会很低 (跟查问到内存中再应用 subList(start,end) 没什么区别)。所以咱们要用到物理翻页。
物理翻页
物理翻页是真正的翻页,它是通过数据库反对的语句来翻页
第一种简略的方法就是传入参数(或者包装一个 page 对象),在 SQL 语句中翻页。
<select id="selectBlogPage" parameterType="map" resultMap="BaseResultMap">
select * from blog limit #{curIndex} , #{pageSize}
</select>
第一个问题是咱们要在 Java 代码外面去计算起止序号; 第二个问题是: 每个须要翻页的 Statement 都要编写 limit 语句,会造成 Mapper 映射器外面很多代码冗余。
那咱们就须要一种通用的形式,不须要去批改配置的任何一条 SQL 语句,只有在我 们须要翻页的中央封装一下翻页对象就能够了。
咱们最罕用的做法就是应用翻页的插件,这个是基于 MyBatis 的拦截器实现的,比方 PageHelper。
// pageSize 每一页几条
PageHelper.startPage(pn, 10);
List<Employee> emps = employeeService.getAll(); // navigatePages 导航页码数
PageInfo page = new PageInfo(emps, 10);
return Msg.success().add("pageInfo", page);
PageHelper 是通过 MyBatis 的拦截器实现的,插件的具体原理咱们前面再剖析。简略地来说,它会依据 PageHelper 的参数,改写咱们的 SQL 语句。比方 MySQL 会生成 limit 语句,Oracle 会生成 rownum 语句,SQL Server 会生成 top 语句。
通用 Mapper
问题: 当咱们的表字段发生变化的时候,咱们须要批改实体类和 Mapper 文件定义的字段和办法。如果是增量保护,那么一个个文件去批改。如果是全量替换,咱们还要去比照用 MBG 生成的文件。字段变动一次就要批改一次,保护起来十分麻烦。
解决这个问题,咱们有两种思路。
第一个,因为 MyBatis 的 Mapper 是反对继承的(见 https://github.com/mybatis/my…)。所 以 我 们 可 以 把 我 们 的 Mapper.xml 和 Mapper 接口都分成两个文件。一个是 MBG 生成的,这部分是固定不变的。而后创立 DAO 类继承生成的接口,变动的局部就在 DAO 外面保护。
mybatis-standalone 工程:
public interface BlogMapperExt extends BlogMapper {public Blog selectBlogByName(String name);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzjson.mapper.BlogMapperExt">
<!-- 只能继承 statement,不能继承 sql、resultMap 等标签 -->
<resultMap id="BaseResultMap" type="blog">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="author_id" property="authorId" jdbcType="INTEGER"/>
</resultMap>
<!-- 在 parent xml 和 child xml 的 statement id 雷同的状况下,会应用 child xml 的 statement id -->
<select id="selectBlogByName" resultMap="BaseResultMap" statementType="PREPARED">
select *
from blog
where name = #{name}
</select>
</mapper>
所以当前只有批改 Ext 的文件就能够了。
这么做有一个毛病,就是文件会增多。
既然针对每张表生成的根本办法都是一样的,也就是公共的办法局部代码都是一样的,咱们能不能把这部分合并成一个文件,让它反对泛型呢? 编写一个反对泛型的通用接口,比方叫 GPBaseMapper<T>,把实体类作为参数传 入。这个接口外面定义了大量的增删改查的根底办法,这些办法都是反对泛型的。自定义的 Mapper 接口继承该通用接口,例如 BlogMapper extends GPBaseMapper<Blog>
,主动取得对实体类的操作方法。遇到没有的办法,咱们仍然 能够在咱们本人的 Mapper 外面编写。咱们能想到的解决方案,早就有人做了这个事了,这个货色就叫做
通用 Mapper。https://github.com/abel533/Ma…
用处: 次要解决单表的增删改查问题,并不适用于多表关联查问的场景。
除了配置文件变动的问题之外,通用 Mapper 还能够解决:
- 每个 Mapper 接口中大量的反复办法的定义;
- 屏蔽数据库的差别;
- 提供批量操作的办法;
- 实现分页。
通用 Mapper 和 PageHelper 作者是同一个人(刘增辉)。
应用形式: 在 Spring 中应用时,引入 jar 包,替换 applicationContext.xml 中的
sqlSessionFactory 和 configure。
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="backPackage" value="com.zzjson.crud.dao"/>
</bean
Mybatis-Plus
https://mybatis.plus/guide
MyBatis-Plus 是原生 MyBatis 的一个加强工具,能够在应用原生 MyBatis 的所有 性能的根底上,应用 plus 特有的性能。
MyBatis-Plus 的外围性能:
通用 CRUD:
定义好 Mapper 接口后,只须要继承 BaseMapper<T> 接口即可取得通用的增删改查性能,无需编写任何接口办法与配置文件。条件结构器: 通过 EntityWrapper<T>(实体包装类),能够用于拼接 SQL 语句,并且反对排序、分组查问等简单的 SQL。代码生成器: 反对一系列的策略配置与全局配置,比 MyBatis 的代码生成更好用。
另外 MyBatis-Plus 也有分页的性能。
我的笔记仓库地址 gitee 快来给我点个 Star 吧