MyBatis-Plus学习总结

  • 什么是MyBatis-Plus?
  • MyBatis-Plus的优点有哪些?
  • 快速开始(在SpringBoot中使用MP)
  • MyBatis-Plus常用注解
  • MyBatis-Plus查询方法范例
  • MyBatis-Plus Mapper提供的CRUD方法详解
  • MyBatis-Plus Mapper提供的选装件
  • MyBatis-Plus的AR模式
    • MyBatis-Plus的AR模式使用
  • MyBatis-Plus 的Service CRUD 接口
  • MyBatis-Plus 的条件构造器
    • AbstractWrapper
    • QueryWrapper
    • UpdateWrapper
    • 使用 Wrapper 自定义SQL
  • MyBatis-Plus物理分页插件
  • MyBatis-Plus主键配置和自定义ID生成器
  • MyBatis-Plus配置实现逻辑删除
  • MyBatis-Plus自动填充功能
  • 执行 SQL 分析打印
  • 插件主体
    • 分页插件PaginationInnerInterceptor
    • 乐观锁插件OptimisticLockerInnerInterceptor
  • 教程推荐

什么是MyBatis-Plus?

  • List item

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

MyBatis-Plus的优点有哪些?

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速开始(在SpringBoot中使用MP)

1、新建SpringBoot项目,配置好数据库连接
2、引入Mybatis Plus依赖(注意不需要再引入Mybatis依赖了)

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version>
</dependency>

3、在数据库管理工具中创建数据库表
4、在项目中创建与数据库表对应的实体类

@Data
@TableName("user")
public class UserDO implements Serializable {/*** serialVersionUID*/private static final long serialVersionUID = 926397353672171598L;/*** 用户主信息 ***//*** 用户名*/private String username;/*** 用户密码*/private String password;/*** 邮箱*/private String email;/*** 年龄*/private Integer age;/*** 手机号*/private String phone;/*** 系统主信息 ***//*** 数据库主键*/@TableId(type = IdType.ASSIGN_ID)private Long id;/*** 数据的创建时间*/@TableField(fill = FieldFill.INSERT)private LocalDateTime created;/*** 数据修改时间*/@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime modified;/*** 创建者*/@TableField(fill = FieldFill.INSERT)private String creator;/*** 最后修改者*/@TableField(fill = FieldFill.INSERT_UPDATE)private String operator;/*** 逻辑删除字段:0:正常,1:逻辑删除*/@TableField(fill = FieldFill.INSERT)private Integer status;/*** 版本号*/@Version@TableField(fill = FieldFill.INSERT)private Long version;
}

3、创建Mapper包
4、创建Mapper文件,并且继承BaseMapper

@Mapper
public interface UserInfoMapper extends BaseMapper<UserDO> {// 这里可以自定义一些方法}

5、在SpringBootApplication当中加上MapperSacn(“Mapper包路径”)
例如:

@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")//这里是Mapper文件存放的包路径
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}

6、直接在Service当中注入Mapper,然后直接调用BaseMapper提供的功能

@Autowired
private UserInfoMapper userInfoMapper;

BaseMapper中提供了大量默认实现的CRUD方法,可以直接使用,下面是Mybatis Plus中的BaseMapper的源码

package com.baomidou.mybatisplus.core.mapper;import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;* Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能* <p>这个 Mapper 支持 id 泛型</p>** @author hubin* @since 2016-01-23*/
public interface BaseMapper<T> extends Mapper<T> {/*** 插入一条记录** @param entity 实体对象*/int insert(T entity);/*** 根据 ID 删除** @param id 主键ID*/int deleteById(Serializable id);/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,删除记录** @param wrapper 实体对象封装操作类(可以为 null)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);/*** 删除(根据ID 批量删除)** @param idList 主键ID列表(不能为 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根据 ID 修改** @param entity 实体对象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根据 whereEntity 条件,更新记录** @param entity        实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根据 ID 查询** @param id 主键ID*/T selectById(Serializable id);/*** 查询(根据ID 批量查询)** @param idList 主键ID列表(不能为 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查询(根据 columnMap 条件)** @param columnMap 表字段 map 对象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,查询一条记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询总记录数** @param queryWrapper 实体对象封装操作类(可以为 null)*/Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录* <p>注意: 只返回第一个字段的值</p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录(并翻页)** @param page         分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录(并翻页)** @param page         分页查询条件* @param queryWrapper 实体对象封装操作类*/<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

接下来,可以使用被这个BaseMapper增强过后的自己所定义的Mapper。

MyBatis-Plus常用注解

这里可以参考官方文档和源码

Mybatis常用注解

MyBatis-Plus查询方法范例

以下是 MyBatis-Plus查询方法的各种范例,分别应对不同的需求使用不同的查询方法

@Test
public void contextLoads() {
}@Autowired
private UserInfoMapper userInfoMapper;/*** 普通查询*/
@Test
public void selectById() {UserInfo userInfo = userInfoMapper.selectById(123);System.out.println(userInfo);
}/*** 批量查询*/
@Test
public void selectByIds() {List<Long> ids = Arrays.asList(123L,124L,125L);List<UserInfo> userInfo = userInfoMapper.selectBatchIds(ids);System.out.println(userInfo);
}/*** 名字包含娟并且年龄小雨30*/
@Test
public void selectByWrapper() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("username","娟").lt("age",30);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** 名字包含娟并且年龄大雨等于20且小于等于40并且email不为空*/
@Test
public void selectByWrapper2() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("username","娟").between("age",20,30).isNotNull("email");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 名字姓肖或者年量大雨等于20,按照年龄降序排列,年龄相同按照id生序排列*/
@Test
public void selectByWrapper3() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.likeRight("username","肖").or().ge("age",20).orderByDesc("age").orderByAsc("id");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 创建日期为2019年10月2日并且直属上级名字为王姓*/
@Test
public void selectByWrapper4() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.apply("date_format(create_time,'%Y-%m-%d')={0}","2019-10-07").inSql("parent_id","select id from user where username like '王%'");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 名字为王姓并且(年龄小于40或邮箱不为空)*/
@Test
public void selectByWrapper5() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.likeRight("username","王").and(wq->wq.lt("age",40)).or().isNotNull("email");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** 名字为王姓并且(年龄小于40并且大与20或邮箱不为空)*/
@Test
public void selectByWrapper6() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.likeRight("username","王").and(wq->wq.lt("age",40).gt("age",20)).or().isNotNull("email");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** (年龄小于40并且大与20或邮箱不为空)名字为王姓并且*/
@Test
public void selectByWrapper7() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.nested(wq->wq.lt("age",40)).or().isNotNull("email").likeRight("username","王");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** 年龄23,30,40*/
@Test
public void selectByWrapper8() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.in("age",Arrays.asList(20,30,40));List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** 只返回满足条件的其中一条语句即可*/
@Test
public void selectByWrapper9() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.in("age",Arrays.asList(20,30,40)).last("limit 1");List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 名字中包含雨并且年龄小于40(只取id,username)*/
@Test
public void selectByWrapper10() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.select("id","username").like("username","雨").lt("age",40);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 名字中包含雨并且年龄小于40(不取create_time,parent_id两个字段,即不列出全部字段)*/
@Test
public void selectByWrapper11() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("username","雨").lt("age",40).select(UserInfo.class,info->!info.getColumn().equals("create_time")&&!info.getColumn().equals("parent_id"));List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 姓名和邮箱不为空*/
public void testCondition() {String username = "王";String email = "";condition(username,email);
}private void condition(String username,String email){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like(StringUtils.isNullOrEmpty(username),"name",username).like(StringUtils.isNullOrEmpty(email),"email",email);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 实体作为条件构造器方法的参数*/
@Test
public void selectByWrapperEntity() {UserInfo whereUser = new UserInfo();whereUser.setUsername("xiaojuan");whereUser.setAge(22);QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>(whereUser);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}
/*** AllEq用法*/
@Test
public void selectByWrapperAllEq() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();Map<String, Object> params = new HashMap<String, Object>();params.put("nuserame","xiaojuan");params.put("age",null);queryWrapper.allEq(params);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** AllEq用法(排除不是条件的字段)*/
@Test
public void selectByWrapperAllEq2() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();Map<String, Object> params = new HashMap<String, Object>();params.put("nuserame","xiaojuan");params.put("age",null);queryWrapper.allEq((k,v)->!k.equals("name"),params);List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);userInfoList.forEach(System.out::println);
}/*** selectMaps*/
@Test
public void selectByWrapperMaps() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("name","肖").lt("age",40);List<Map<String,Object>> userInfoList = userInfoMapper.selectMaps(queryWrapper);userInfoList.forEach(System.out::println);
}/*** 按照直属上级分组,查询每组的平均年龄,最大年龄,最小年龄。并且只取年龄总和小于500的组*/
@Test
public void selectByWrapperMaps2() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.select("avg(age) avg_age","min(min) min_age","max(age) max_age").groupBy("parent_id").having("sum(age)<{0}",500);List<Map<String,Object>> userInfoList = userInfoMapper.selectMaps(queryWrapper);userInfoList.forEach(System.out::println);
}/*** selectObjs*/
@Test
public void selectByWrapperObjs() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.select("id","name").like("name","肖").lt("age",40);List<Object> userInfoList = userInfoMapper.selectObjs(queryWrapper);userInfoList.forEach(System.out::println);
}/*** selectCount*/
@Test
public void selectByWrapperCount() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("name","肖").lt("age",40);Integer count = userInfoMapper.selectCount(queryWrapper);System.out.println(count);
}/*** selectOne*/
@Test
public void selectByWrapperSelectOne() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();queryWrapper.like("name","肖").lt("age",40);UserInfo user = userInfoMapper.selectOne(queryWrapper);System.out.println(user);
}/*** 使用Lambda*/
@Test
public void selectLambda() {// LambdaQueryWrapper<UserInfo> lambda = new QueryWrapper<UserInfo>().lambda();LambdaQueryWrapper<UserInfo> lambda = new LambdaQueryWrapper<UserInfo>();lambda.like(UserInfo::getUsername,"娟").lt(UserInfo::getAge,40);List<UserInfo> userInfoList = userInfoMapper.selectList(lambda);userInfoList.forEach(System.out::println);
}/*** 使用Lambda,名字为王姓(年龄小于40或邮箱不为空)*/
@Test
public void selectLambd2() {LambdaQueryWrapper<UserInfo> lambda = new LambdaQueryWrapper<UserInfo>();lambda.like(UserInfo::getUsername,"娟").and(lqw->lqw.lt(UserInfo::getAge,40).or().isNotNull(UserInfo::getEmail));List<UserInfo> userInfoList = userInfoMapper.selectList(lambda);userInfoList.forEach(System.out::println);
}/*** 使用Lambda链式*/
@Test
public void selectLambd3() {List<UserInfo> userInfoList = new LambdaQueryChainWrapper<UserInfo>(userInfoMapper).like(UserInfo::getUsername,"娟").ge(UserInfo::getAge,20).list();userInfoList.forEach(System.out::println);
}

以上范例转载至Mybatis Plus 查询方法记录

MyBatis-Plus Mapper提供的CRUD方法详解

Mybatis-Plus框架的BaseMapper给我们提供了常用的CRUD接口,我们可以通过官方文档查看

Mapper CRUD 接口

MyBatis-Plus Mapper提供的选装件

选装件,位于 com.baomidou.mybatisplus.extension.injector.methods 包下, 需要配合Sql 注入器使用,可以进行批量更新、插入和逻辑删除

mapper 层 选装件

MyBatis-Plus的AR模式

AR,又叫做ActiveRecord,AR模式是一种领域模型模式,特点是一个模型类对应关系型数据库中的 一个表,而模型类的一个实例对应表中的一行记录。

AR模式 一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 本身却不提供这种模式的实现,不过MyBatis-Plus在AR模式上做出了一定的实现。

MyBatis-Plus的AR模式使用

首先,自定义实体类,然后将该实体类继承MyBatis-Plus的Model

@Data
public class User extends Model<User> {/*** 用户主信息 ***//*** 用户名*/private String username;/*** 用户密码*/private String password;/*** 邮箱*/private String email;/*** 年龄*/private Integer age;/*** 手机号*/private String phone;/*** 系统主信息 ***//*** 数据库主键*/@TableId(type = IdType.ASSIGN_ID)private Long id;/*** 数据的创建时间*/@TableField(fill = FieldFill.INSERT)private LocalDateTime created;/*** 数据修改时间*/@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime modified;/*** 创建者*/@TableField(fill = FieldFill.INSERT)private String creator;/*** 最后修改者*/@TableField(fill = FieldFill.INSERT_UPDATE)private String operator;/*** 逻辑删除字段:0:正常,1:逻辑删除*/@TableField(fill = FieldFill.INSERT)private Integer status;/*** 版本号*/@Version@TableField(fill = FieldFill.INSERT)private Long version;}

接下来,创建Mapper

public interface UserMapper extends BaseMapper<UserDO> {}

虽然AR模式用不到该接口,但是一定要定义,否则使用AR时会报空指针异常。

接下来使用就好了

@Testpublic void testArInsert(){UserDO user = new UserDO();user.setUsername("张文远");user.setAge(22);boolean result = user.insert();System.out.println(result);}

借助于Model提供的方法,可以直接执行增删改查等操作,例如上面的user.insert

我们可以通过Model的源码查看其提供的功能

/*** ActiveRecord 模式 CRUD* 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下* 才能使用此 AR 模式 !!!*/
public abstract class Model<T extends Model<?>> implements Serializable {private static final long serialVersionUID = 1L;private transient Log log = LogFactory.getLog(getClass());/*** 插入(字段选择插入)*/public boolean insert() {SqlSession sqlSession = sqlSession();try {return SqlHelper.retBool(sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), this));} finally {closeSqlSession(sqlSession);}}/*** 插入 OR 更新*/public boolean insertOrUpdate() {return StringUtils.checkValNull(pkVal()) || Objects.isNull(selectById(pkVal())) ? insert() : updateById();}/*** 根据 ID 删除** @param id 主键ID*/public boolean deleteById(Serializable id) {SqlSession sqlSession = sqlSession();try {return SqlHelper.retBool(sqlSession.delete(sqlStatement(SqlMethod.DELETE_BY_ID), id));} finally {closeSqlSession(sqlSession);}}/*** 根据主键删除*/public boolean deleteById() {Assert.isFalse(StringUtils.checkValNull(pkVal()), "deleteById primaryKey is null.");return deleteById(pkVal());}/*** 删除记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/public boolean delete(Wrapper<T> queryWrapper) {Map<String, Object> map = new HashMap<>(1);map.put(Constants.WRAPPER, queryWrapper);SqlSession sqlSession = sqlSession();try {return SqlHelper.retBool(sqlSession.delete(sqlStatement(SqlMethod.DELETE), map));} finally {closeSqlSession(sqlSession);}}/*** 更新(字段选择更新)*/public boolean updateById() {Assert.isFalse(StringUtils.checkValNull(pkVal()), "updateById primaryKey is null.");// updateByIdMap<String, Object> map = new HashMap<>(1);map.put(Constants.ENTITY, this);SqlSession sqlSession = sqlSession();try {return SqlHelper.retBool(sqlSession.update(sqlStatement(SqlMethod.UPDATE_BY_ID), map));} finally {closeSqlSession(sqlSession);}}/*** 执行 SQL 更新** @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/public boolean update(Wrapper<T> updateWrapper) {Map<String, Object> map = new HashMap<>(2);map.put(Constants.ENTITY, this);map.put(Constants.WRAPPER, updateWrapper);// updateSqlSession sqlSession = sqlSession();try {return SqlHelper.retBool(sqlSession.update(sqlStatement(SqlMethod.UPDATE), map));} finally {closeSqlSession(sqlSession);}}/*** 查询所有*/public List<T> selectAll() {SqlSession sqlSession = sqlSession();try {return sqlSession.selectList(sqlStatement(SqlMethod.SELECT_LIST));} finally {closeSqlSession(sqlSession);}}/*** 根据 ID 查询** @param id 主键ID*/public T selectById(Serializable id) {SqlSession sqlSession = sqlSession();try {return sqlSession.selectOne(sqlStatement(SqlMethod.SELECT_BY_ID), id);} finally {closeSqlSession(sqlSession);}}/*** 根据主键查询*/public T selectById() {Assert.isFalse(StringUtils.checkValNull(pkVal()), "selectById primaryKey is null.");return selectById(pkVal());}/*** 查询总记录数** @param queryWrapper 实体对象封装操作类(可以为 null)*/public List<T> selectList(Wrapper<T> queryWrapper) {Map<String, Object> map = new HashMap<>(1);map.put(Constants.WRAPPER, queryWrapper);SqlSession sqlSession = sqlSession();try {return sqlSession.selectList(sqlStatement(SqlMethod.SELECT_LIST), map);} finally {closeSqlSession(sqlSession);}}/*** 查询一条记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/public T selectOne(Wrapper<T> queryWrapper) {return SqlHelper.getObject(log, selectList(queryWrapper));}/*** 翻页查询** @param page         翻页查询条件* @param queryWrapper 实体对象封装操作类(可以为 null)*/public <E extends IPage<T>> E selectPage(E page, Wrapper<T> queryWrapper) {Map<String, Object> map = new HashMap<>(2);map.put(Constants.WRAPPER, queryWrapper);map.put("page", page);SqlSession sqlSession = sqlSession();try {page.setRecords(sqlSession.selectList(sqlStatement(SqlMethod.SELECT_PAGE), map));} finally {closeSqlSession(sqlSession);}return page;}/*** 查询总数** @param queryWrapper 实体对象封装操作类(可以为 null)*/public Integer selectCount(Wrapper<T> queryWrapper) {Map<String, Object> map = new HashMap<>(1);map.put(Constants.WRAPPER, queryWrapper);SqlSession sqlSession = sqlSession();try {return SqlHelper.retCount(sqlSession.<Integer>selectOne(sqlStatement(SqlMethod.SELECT_COUNT), map));} finally {closeSqlSession(sqlSession);}}/*** 执行 SQL*/public SqlRunner sql() {return new SqlRunner(getClass());}/*** 获取Session 默认自动提交*/protected SqlSession sqlSession() {return SqlHelper.sqlSession(getClass());}/*** 获取SqlStatement** @param sqlMethod sqlMethod*/protected String sqlStatement(SqlMethod sqlMethod) {return sqlStatement(sqlMethod.getMethod());}/*** 获取SqlStatement** @param sqlMethod sqlMethod*/protected String sqlStatement(String sqlMethod) {return SqlHelper.table(getClass()).getSqlStatement(sqlMethod);}/*** 主键值*/protected Serializable pkVal() {return (Serializable) ReflectionKit.getMethodValue(this, TableInfoHelper.getTableInfo(getClass()).getKeyProperty());}/*** 释放sqlSession** @param sqlSession session*/protected void closeSqlSession(SqlSession sqlSession) {SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(getClass()));}
}

MyBatis-Plus 的Service CRUD 接口

MyBatis-Plus提供了BaseMapper,可以让我们自定义Mapper并继承,从而使用增强版本的Mapper。
既然Mapper大多都要在Service中使用,那么可不可以一步到位直接增强Service呢?

MyBatis-Plus为此提供了IService接口,继承该接口之后可以直接使用IService生成的CRUD方法。

IService CRUD 接口

MyBatis-Plus 的条件构造器

Mybatis-Plus提供了强大的条件构造器,提供了很多sql语法支持的方法,比如模糊查询,比较,区间,分组查询,排序,判断空,子查询等等,方便我们用面向对象的方式去实现sql语句。

我们主要使用的MyBatis-Plus 的条件构造器主要包括QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper)。

AbstractWrapper

AbstractWrapper是QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类,用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。

AbstractWrapper详细说明

QueryWrapper

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取

QueryWrapper详细说明

UpdateWrapper

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

UpdateWrapper详细说明

使用 Wrapper 自定义SQL

使用 Wrapper 自定义SQL,需要mybatis-plus版本 >= 3.0.7 param 参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER) 使用${ew.customSqlSegment} 不支持 Wrapper 内的entity生成where语句

使用 Wrapper 自定义SQL

MyBatis-Plus物理分页插件

物理分页插件

使用过程中要注意,paginationInterceptor类本质就是Mybatis的拦截器,不配置会导致Mybatis的分页插件不能的正常使用。

MyBatis-Plus主键配置和自定义ID生成器

MyBatis-Plus可以配置实体类对应到数据库表的主键和对应的ID生成器

主键配置

自定义ID生成器

MyBatis-Plus配置实现逻辑删除

逻辑删除

MyBatis-Plus自动填充功能

自动填充功能

这个是MyBatis-Plus中相当好用的功能,当你的数据库表中有创建人、修改人、创建时间、修改时间等不依靠输入而填充的字段时,可以再自动填充方法中配置相关字段的填充。

执行 SQL 分析打印

SQL 分析打印

可以利用SQL 分析打印来对SQL语句的性能进行分析,但是要注意这个功能也会造成性能负担,所以最好只在测试环境中使用,不要在生产环境中使用。

插件主体

插件主体(必看!)(since 3.4.0)

个人开发常用插件为分页插件和乐观锁插件

分页插件PaginationInnerInterceptor

PaginationInnerInterceptor

乐观锁插件OptimisticLockerInnerInterceptor

OptimisticLockerInnerInterceptor

通过自动配置就可以实现乐观锁,不过利用乐观锁进行的更新方法还是需要自己写。

教程推荐

MyBatis-Plus入门

MyBatis-Plus进阶

这两个教程讲的比较详细,非常推荐。

MyBatis-Plus学习总结相关推荐

  1. Spring+SpringMVC+MyBatis深入学习及搭建(十)——MyBatis逆向工程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6973266.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(九)--My ...

  2. java学mybatis还用学jdbc吗,mybatis系统学习(二)——使用基础mybatis代替原始jdbc

    mybatis系统学习(二)--使用基础mybatis代替原始jdbc 前言 这一篇笔记的内容应当是建立在上一篇的基础之上,不论是使用的数据表,还是对应的实体类,都在上一篇有过说明. 有兴趣的或者对相 ...

  3. Spring+SpringMVC+MyBatis深入学习及搭建(十一)——SpringMVC架构

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6985816.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十)--My ...

  4. Spring+SpringMVC+MyBatis深入学习及搭建(十七)——SpringMVC拦截器

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7098753.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十六)--S ...

  5. Spring+SpringMVC+MyBatis深入学习及搭建(十四)——SpringMVC和MyBatis整合

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7010363.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十三)--S ...

  6. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  7. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

  8. Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发

    前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)--MyBatis的基础知识.MybatisFirst中存在大量重复的代码.这次简化下代码: 使用MyBatis开发Dao ...

  9. mybatis自己学习的一些总结

    以前一直在使用spring的JDBCTEMPLATE和hibernate做项目:两个都还不错,spring的jdbctemplate用起来比较麻烦,虽然很简单.而hibernate呢,用起来很好用,很 ...

  10. [Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

    上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC 下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringA ...

最新文章

  1. 来客推开源商城与你浅析:B2B2C多商户商城系统
  2. @Transactional事务几点注意
  3. 拖放(Drag和Drop)--html5
  4. oracle未找到远程连接,Oracle ORA-02019:未找到远程数据库的连接说明 | 学步园
  5. gitHub网站上常见英语翻译
  6. Taro+react开发(19)--arr声明const报错
  7. Huffman编码的设计与实现
  8. Canvas 数学、物理、动画学习笔记一
  9. iOS xcode4 编译环境
  10. transform子元素,绝对定位失效
  11. 安卓8.1放弃Java_升级到Android 8.1后,startForeground失败
  12. 干货!NB-IoTLoRa物联网项目实操来了!
  13. 互联网日报 | 1月30日 星期六 | 苹果单季营收首破1000亿美元;特斯拉连续六个季度盈利;全球新冠肺炎确诊病例超1亿例...
  14. 安科瑞电气系统Acrel-2000在数据中心机房的应用及产品选型
  15. 然而大部分工程师的期权并没有什么用
  16. linux平台 wifi 7601 porting
  17. 教学打铃单片机实现(课程设计)
  18. 外包程序员,如何提高自己跳出外包圈子?
  19. Matlab中Robotics toolbox的安装及使用
  20. The Street View House Numbers (SVHN) Dataset

热门文章

  1. 惠普EliteBook860笔记本使用U盘重装Win10系统教学
  2. 使用MV制作最简单的游戏:我要做游戏(9)
  3. CAD2023下载安装教程
  4. WPS创建多级级联菜单
  5. 利用envi对Landsat8图像进行NDVI处理
  6. 计算机二级WPS 选择题(模拟和解析八)
  7. java zip压缩包并加密
  8. 主机屋 mysql 数据库名_主机屋php链接数据库
  9. windows7显示摄像头图标的方法
  10. WP采集汇集WP采集插件-WP关键词采集文章