简介 
MyBatis-Plus (简称 MP)是一个 MyBatis  的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
 
官网:https://baomidou.com/ 
特性 
无侵入 :只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小 :启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作 
支持数据库 
mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver 、 presto 
达梦数据库 、 虚谷数据库 、 人大金仓数据库 
 
框架结构 
快速开始 创建数据库表 1 2 3 4 5 6 7 8 CREATE  TABLE  user ( 	id BIGINT (20 ) NOT  NULL  COMMENT '主键ID' , 	name VARCHAR (30 ) NULL  DEFAULT  NULL  COMMENT '姓名' , 	age INT (11 ) NULL  DEFAULT  NULL  COMMENT '年龄' , 	email VARCHAR (50 ) NULL  DEFAULT  NULL  COMMENT '邮箱' , 	PRIMARY  KEY (id) ); 
1 2 3 4 5 6 INSERT  INTO  user  (id, name, age, email) VALUES (1 , 'Jone' , 18 , 'test1@baomidou.com' ), (2 , 'Jack' , 20 , 'test2@baomidou.com' ), (3 , 'Tom' , 28 , 'test3@baomidou.com' ), (4 , 'Sandy' , 21 , 'test4@baomidou.com' ), (5 , 'Billie' , 24 , 'test5@baomidou.com' ); 
创建SpringBoot项目,添加依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <?xml version="1.0" encoding="UTF-8"?> <project  xmlns ="http://maven.apache.org/POM/4.0.0"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" >     <modelVersion > 4.0.0</modelVersion >      <parent >          <groupId > org.springframework.boot</groupId >          <artifactId > spring-boot-starter-parent</artifactId >          <version > 2.3.3.RELEASE</version >          <relativePath />       </parent >      <groupId > cn.yanghuisen</groupId >      <artifactId > mp-demo</artifactId >      <version > 0.0.1-SNAPSHOT</version >      <name > mp-demo</name >      <description > Demo project for MyBatis-Plus</description >      <properties >          <java.version > 1.8</java.version >      </properties >      <dependencies >          <dependency >              <groupId > org.springframework.boot</groupId >              <artifactId > spring-boot-starter</artifactId >          </dependency >          <dependency >              <groupId > org.springframework.boot</groupId >              <artifactId > spring-boot-starter-web</artifactId >          </dependency >          <dependency >              <groupId > mysql</groupId >              <artifactId > mysql-connector-java</artifactId >              <scope > runtime</scope >          </dependency >          <dependency >              <groupId > org.projectlombok</groupId >              <artifactId > lombok</artifactId >              <optional > true</optional >          </dependency >          <dependency >              <groupId > org.springframework.boot</groupId >              <artifactId > spring-boot-starter-test</artifactId >              <scope > test</scope >          </dependency >                   <dependency >              <groupId > com.baomidou</groupId >              <artifactId > mybatis-plus-boot-starter</artifactId >              <version > 3.3.2</version >          </dependency >      </dependencies >      <build >          <plugins >              <plugin >                  <groupId > org.springframework.boot</groupId >                  <artifactId > spring-boot-maven-plugin</artifactId >              </plugin >          </plugins >      </build >  </project > 
注:如果引入了MyBatis-Plus就不要在引入MyBtais,两者选一 
配置数据库账号密码 修改application.yml文件
1 2 3 4 5 6 spring:   datasource:      driver-class-name:  com.mysql.cj.jdbc.Driver      username:  root      password:  123456      url:  jdbc:mysql://localhost:3306/mpdemo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8  
编码 创建实体类 使用Lombok减少代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  cn.yanghuisen.mpdemo.entity;import  lombok.Data;@Data public  class  User           private  Long id;          private  String name;          private  Integer age;          private  String email; } 
mapper接口 1 2 3 4 5 6 7 8 9 10 11 12 13 package  cn.yanghuisen.mpdemo.mapper;import  cn.yanghuisen.mpdemo.entity.User;import  com.baomidou.mybatisplus.core.mapper.BaseMapper;public  interface  UserMapper  extends  BaseMapper <User > } 
UserMapper接口继承BaseMapper,泛型参数为实体类对象
配置扫描注解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  cn.yanghuisen.mpdemo;import  org.mybatis.spring.annotation.MapperScan;import  org.springframework.boot.SpringApplication;import  org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication @MapperScan("cn.yanghuisen.mpdemo.mapper") public  class  MpDemoApplication      public  static  void  main (String[] args)           SpringApplication.run(MpDemoApplication.class, args);     } } 
使用@MapperScan指定扫描的mapper接口路径
开始使用 查询所有的数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  cn.yanghuisen.mpdemo;import  cn.yanghuisen.mpdemo.entity.User;import  cn.yanghuisen.mpdemo.mapper.UserMapper;import  lombok.extern.slf4j.Slf4j;import  org.junit.jupiter.api.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.boot.test.context.SpringBootTest;import  org.springframework.test.context.junit4.SpringRunner;import  java.util.List;@SpringBootTest  @RunWith(SpringRunner.class)     @Slf4j   class  MpDemoApplicationTests      @Autowired      private  UserMapper userMapper;     @Test      void  selectListTest ()           log.info("*****查询User列表*****" );         List<User> userList = userMapper.selectList(null );         log.info("*****打印userList*****" );         userList.forEach(System.out::println);     } } 
1 2 3 4 5 User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com) 
到此就可以体会到MyBatis-Plus的强大魅力,只需要简单的配置就可以实现基本的CRUD操作。
日志配置 开始日志,查看具体SQL命令
application.yml
1 2 3 mybatis-plus:   configuration:      log-impl:  org.apache.ibatis.logging.stdout.StdOutImpl  
注解 @TableName 表名注解
属性 
类型 
必须指定 
默认值 
描述 
 
 
value 
String 
否 
“” 
表名 
 
schema 
String 
否 
“” 
schema 
 
keepGlobalPrefix 
boolean 
否 
false 
是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值) 
 
resultMap 
String 
否 
“” 
xml 中 resultMap 的 id 
 
autoResultMap 
boolean 
否 
false 
是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入) 
 
@TableId 主键注解
属性 
类型 
必须指定 
默认值 
描述 
 
 
value 
String 
否 
“” 
主键字段名 
 
type 
Enum 
否 
IdType.NONE 
主键类型 
 
IdType 
主键生成方式
值 
描述 
 
 
AUTO 
数据库ID自增 
 
NONE 
无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) 
 
INPUT 
insert前自行set主键值 
 
ASSIGN_ID 
分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法) 
 
ASSIGN_UUID 
分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法) 
 
ID_WORKER分布式全局唯一ID 长整型类型(please use ASSIGN_ID) 
UUID32位UUID字符串(please use ASSIGN_UUID) 
ID_WORKER_STR分布式全局唯一ID 字符串类型(please use ASSIGN_ID) 
@TableField 字段注解(非主键)
属性 
类型 
必须指定 
默认值 
描述 
 
 
value 
String 
否 
“” 
数据库字段名 
 
el 
String 
否 
“” 
映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分 
 
exist 
boolean 
否 
true 
是否为数据库表字段 
 
condition 
String 
否 
“” 
字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考  
 
update 
String 
否 
“” 
字段 update set 部分注入, 例如:update=”%s+1”:表示更新时会set version=version+1(该属性优先级高于 el 属性) 
 
insertStrategy 
Enum 
N 
DEFAULT 
举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>) 
 
updateStrategy 
Enum 
N 
DEFAULT 
举例:IGNORED: update table_a set column=#{columnProperty} 
 
whereStrategy 
Enum 
N 
DEFAULT 
举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if> 
 
fill 
Enum 
否 
FieldFill.DEFAULT 
字段自动填充策略 
 
select 
boolean 
否 
true 
是否进行 select 查询 
 
keepGlobalFormat 
boolean 
否 
false 
是否保持使用全局的 format 进行处理 
 
jdbcType 
JdbcType 
否 
JdbcType.UNDEFINED 
JDBC类型 (该默认值不代表会按照该值生效) 
 
typeHandler 
Class<? extends TypeHandler> 
否 
UnknownTypeHandler.class 
类型处理器 (该默认值不代表会按照该值生效) 
 
numericScale 
String 
否 
“” 
指定小数点后保留的位数 
 
FieldStrategy 
值 
描述 
 
 
IGNORED 
忽略判断 
 
NOT_NULL 
非NULL判断 
 
NOT_EMPTY 
非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断) 
 
DEFAULT 
追随全局配置 
 
FieldFill 
字段填充策略
值 
描述 
 
 
DEFAULT 
默认不处理 
 
INSERT 
插入时填充字段 
 
UPDATE 
更新时填充字段 
 
INSERT_UPDATE 
插入和更新时填充字段 
 
@TableLogic 表字段逻辑处理注解(逻辑删除)
属性 
类型 
必须指定 
默认值 
描述 
 
 
value 
String 
否 
“” 
逻辑未删除值 
 
delval 
String 
否 
“” 
逻辑删除值 
 
CRUD接口 MapperCRUD接口 
这里只是一部分查询接口,完整的查询接口请查看官方文档。
 
insert-插入数据 1 2 3 4 5 6 7 8 9 10 @Test void  insertTest ()     User user = new  User();     user.setName("Ahh" );     user.setAge(20 );     user.setEmail("admin@yanghuisen.cn" );     userMapper.insert(user);     log.info(user.toString());     selectListTest(); } 
调用insert方法进行数据插入,传入一个user对象。插入成功后会把生成的ID,回填到user对象中。
注:默认使用的是雪花算法 生成对应的ID,如果要修改ID生成算法可以在实体类上添加注解@TableId
1 2 3 4 5 6 7 8 9 10 11 public  class  User           @TableId(type = IdType.AUTO)      private  Long id;          private  String name;          private  Integer age;          private  String email; } 
注:如果要使用auto自增主键的话,需要开启数据库的主键ID自增。
update-更新数据 1 2 3 4 5 6 7 8 9 10 11 @Test void  updateTest ()     User user = new  User();     user.setId(6L );     user.setName("啊哈哈" );     user.setAge(20 );     user.setEmail("admin@yanghuisen.cn" );     int  i = userMapper.updateById(user);     log.info(i+"" );     selectListTest(); } 
注:updateById传入的是user对象,不是具体的ID。
select-查询数据 批量查询 1 2 3 4 5 @Test void  selectUserByBatchId ()     List<User> userList = userMapper.selectBatchIds(Arrays.asList(1 ,2 ,3 ,4 ,5 ));     userList.forEach(System.out::println); } 
Map条件查询 1 2 3 4 5 6 7 8 @Test void  selectUserByMap ()     Map<String,Object> map = new  HashMap<>();     map.put("id" ,1 );     map.put("name" ,"Jone" );     List<User> userList = userMapper.selectByMap(map);     userList.forEach(System.out::println); } 
delete-删除数据 1 2 3 4 5 @Test void  deleteUserById ()     userMapper.deleteById(1302239794451763202L );     selectListTest(); } 
删除同样有批量删除和map删除,使用方式和查询的一样
条件构造器 细心的就会发现,上面的CRUD都是一些简单的操作,如果是复杂的就没办法了,所以这时就要用到了条件构造器。
条件构造器有很多,具体的还请查看官方网文档,这里只会列举几个使用方法。
isNotNull-不为空 查询name不为空的用户,并且邮箱部位空的用户
1 2 3 4 5 6 7 8 9 10 @Test public  void  isNotNullTest () QueryWrapper<User> wrapper = new  QueryWrapper<>(); wrapper.isNotNull("name" ); wrapper.isNotNull("email" ); userMapper.selectList(wrapper).forEach(System.out::println); } 
ge-大于等于 查询age大于等于22的用户
1 2 3 4 5 6 7 @Test public  void  geTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.ge("age" ,22 );     userMapper.selectList(wrapper).forEach(System.out::println); } 
eq-等于 查询name等于Jone的用户
1 2 3 4 5 6 7 @Test public  void  eqTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.eq("name" ,"Jone" );     System.out.println(userMapper.selectOne(wrapper)); } 
selectOne:只查询一条数据
between-X与N之间的值 查询年龄在20到25之间的用户的数量
1 2 3 4 5 6 7 8 @Test public  void  betweenTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.between("age" ,20 ,25 );     Integer count = userMapper.selectCount(wrapper);     System.out.println(count); } 
selectCount:查询数量
like-模糊查询 1 2 3 4 5 6 7 8 @Test public  void  likeTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.like("name" ,"a" );     List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);     maps.forEach(System.out::println); } 
selectMaps:返回List<Map>形式的数据
notLike-模糊查询 查询name中不包含a的用户
1 2 3 4 5 6 7 8 @Test public  void  notLikeTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.notLike("name" ,"a" );     List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);     maps.forEach(System.out::println); } 
likeLeft-左模糊查询 查询name中以e结尾的用户
1 2 3 4 5 6 7 8 @Test public  void  likeLeftTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.likeLeft("name" ,"e" );     List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);     maps.forEach(System.out::println); } 
likeRight-左模糊查询 查询name中以j开头的用户
1 2 3 4 5 6 7 8 @Test public  void  likeRightTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.likeRight("name" ,"j" );     List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);     maps.forEach(System.out::println); } 
inSql id 在子查询中查询出来
1 2 3 4 5 6 7 8 @Test public  void  inSqlTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.inSql("id" ,"select id from user where id < 5" );     List<Object> objects = userMapper.selectObjs(wrapper);     objects.forEach(System.out::println); } 
selectObjs:返回List<Object>形式的数据
orderByDesc-降序排序 根据id进行降序排序
1 2 3 4 5 6 7 8 @Test public  void  orderByDescTest ()          QueryWrapper<User> wrapper = new  QueryWrapper<>();     wrapper.orderByDesc("id" );     List<User> userList = userMapper.selectList(wrapper);     userList.forEach(System.out::println); } 
分页插件 MyBatisPlus也提供了分页插件,但是需要稍微的配置一下
在配置类中添加分页插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  cn.yanghuisen.mpdemo.config;import  com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;@Configuration public  class  MyBatisPlusConfig      @Bean      public  PaginationInterceptor paginationInterceptor ()           return  new  PaginationInterceptor();     } } 
测试分页
1 2 3 4 5 6 7 8 @Test void  pageTest ()          Page<User> page = new  Page<>(1 ,5 );     userMapper.selectPage(page,null );     page.getRecords().forEach(System.out::println);     log.info("总条数:" +page.getTotal()); } 
代码生成器、 
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
 
添加依赖 MyBatisPlus在 3.0.3版本之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖
1 2 3 4 5 <dependency >     <groupId > com.baomidou</groupId >      <artifactId > mybatis-plus-generator</artifactId >      <version > 3.4.0</version >  </dependency > 
编码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 package  cn.yanghuisen.mpdemo;import  com.baomidou.mybatisplus.annotation.DbType;import  com.baomidou.mybatisplus.annotation.FieldFill;import  com.baomidou.mybatisplus.annotation.IdType;import  com.baomidou.mybatisplus.generator.AutoGenerator;import  com.baomidou.mybatisplus.generator.config.DataSourceConfig;import  com.baomidou.mybatisplus.generator.config.GlobalConfig;import  com.baomidou.mybatisplus.generator.config.PackageConfig;import  com.baomidou.mybatisplus.generator.config.StrategyConfig;import  com.baomidou.mybatisplus.generator.config.po.TableFill;import  com.baomidou.mybatisplus.generator.config.rules.DateType;import  com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;import  java.util.ArrayList;public  class  CodeGeneration      public  static  void  main (String[] args)                    AutoGenerator autoGenerator = new  AutoGenerator();                  GlobalConfig gc = new  GlobalConfig();                  String projectPath = System.getProperty("user.dir" );                  gc.setOutputDir(projectPath+"src/main/java" );                  gc.setAuthor("啊哈哈" );                  gc.setOpen(false );                  gc.setFileOverride(false );                  gc.setServiceName("%sService" );                  gc.setIdType(IdType.ASSIGN_ID);                  gc.setDateType(DateType.ONLY_DATE);                  DataSourceConfig dsc = new  DataSourceConfig();         dsc.setUrl("jdbc:mysql://localhost:3306/mpdemo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8" );         dsc.setDriverName("com.mysql.cj.jdbc.Driver" );         dsc.setUsername("root" );         dsc.setPassword("123456" );         dsc.setDbType(DbType.MYSQL);                  PackageConfig pc = new  PackageConfig();                  pc.setModuleName("demo" );                  pc.setParent("cn.yanghuisen.mpdemo" );         pc.setEntity("entity" );         pc.setMapper("mapper" );         pc.setService("service" );         pc.setController("controller" );                  StrategyConfig strategy = new  StrategyConfig();         strategy.setInclude("t_user" );         strategy.setNaming(NamingStrategy.underline_to_camel);         strategy.setColumnNaming(NamingStrategy.underline_to_camel);                  strategy.setEntityLombokModel(true );                  strategy.setLogicDeleteFieldName("flag" );                  TableFill createTime = new  TableFill("create_time" , FieldFill.INSERT);         TableFill updateTime = new  TableFill("update_time" , FieldFill.INSERT_UPDATE);         ArrayList<TableFill> fills = new  ArrayList<>();         fills.add(createTime);         fills.add(updateTime);         strategy.setTableFillList(fills);                  strategy.setVersionFieldName("version" );         strategy.setRestControllerStyle(true );         strategy.setControllerMappingHyphenStyle(true );                  autoGenerator.setGlobalConfig(gc);                  autoGenerator.setDataSource(dsc);                  autoGenerator.setPackageInfo(pc);                  autoGenerator.setStrategy(strategy);                  autoGenerator.execute();     } } 
多数据源(2020-10-18补充) 
多数据源,顾名思义,就是配置多个数据来源。一般项目中都是使用一个数据源就足够了,但是也有例外的时候,有时候就需要根据不同的业务需求连接不同的数据库进行查询。
MyBatis-Plus中已经集成了多数据源的功能,只需要简单的配置就可以使用。
 
多数据源的使用 添加依赖 Mybatis-Plus虽然支持多数据源配置,但是没有集成到MyBatis-Plus的的依赖中,需要单独添加依赖
1 2 3 4 5 6 <dependency >     <groupId > com.baomidou</groupId >      <artifactId > dynamic-datasource-spring-boot-starter</artifactId >      <version > 3.2.1</version >  </dependency > 
上面依赖是截止到我写多数据源这个文档的时候的最新的版本
配置数据源 修改application.yaml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 spring:   datasource:      dynamic:        primary:  master         strict:  false         datasource:           master:            driver-class-name:  com.mysql.cj.jdbc.Driver            username:  root            password:  123456            url:  jdbc:mysql://localhost:3306/mpdemo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8          slave_1:            driver-class-name:  com.mysql.cj.jdbc.Driver            username:  root            password:  123456            url:  jdbc:mysql://localhost:3306/slave_1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8  
@DS 
注解 
结果 
 
 
没有注解 
使用默认数据源 
 
@DS("dsName")dsName为数据源名称 
 
@DS注解就是切换数据源的关键,该注解可以声明在类和方法上。如果同时在类和方法上都声明了该注解,则方法上的优先于类上的 。(建议只在service上设数据源)
切换数据源非常简单,只需要在service方法上添加@DS注解即可,并且传递数据源名称即可
例子1:
1 2 3 4 5 6 7 @Override @DS("master")    public  List<User> master ()      List<User> userList = userMapper.selectList(null );     userList.forEach(x->log.info(x.toString()));     return  userList; } 
例子2:
1 2 3 4 5 6 7 @Override @DS("slave_1")   public  List<User> slave_1 ()      List<User> userList = userMapper.selectList(null );     userList.forEach(x->log.info(x.toString()));     return  userList; } 
这样就完成了数据源的切换
方法内切换数据源 上面的数据源切换有一个问题,就是在一个方法内还是只能使用一个数据源,如果要在方法内切换到别的数据源是无法做到的。比如以下代码
1 2 3 4 5 6 7 8 9 10 @Override @DS("slave_1")   public  List<User> slave_1 ()      List<User> userList = userMapper.selectList(null );     userList.forEach(x->log.info(x.toString()));          return  userList; } 
这种问题我在公司就遇到了,单使用@DS注解也是不行的。
这时就要用到DynamicDataSourceContextHolder类了,通过DynamicDataSourceContextHolder,在方法内切数据源
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override @DS("slave_1") public  List<User> test02 ()           DynamicDataSourceContextHolder.push("master" );     List<User> userList = this .dsMaster();          DynamicDataSourceContextHolder.poll();     userList.forEach(x->log.info(x.toString()));     log.info("----切换数据源----" );     userList = this .dsMaster();     userList.forEach(x->log.info(x.toString()));     return  userList; } 
使用DynamicDataSourceContextHolder.push("master");切换到指定数据源,并且使用之后要使用DynamicDataSourceContextHolder.poll();恢复到@DS指定的数据源。
拓展 自动填充 在阿里巴巴开发手册中明确规定,所有的数据库表中都应该含有create_time和update_time两个字段(用于表示该条记录的创建和修改时间)。通过自动填充可以自动化的设置这两个字段的值,避免每次都要手动设置。自动填充有两种方式。
数据库级别 数据库级别的就很简单了,给表中添加create_time和update_time字段后,设置下就好了。不同的数据库工具设置方法不一样,这里以Navicat为例。
不建议使用这种方式,一般工作中不允许随意改变数据库
代码级别 注:代码级别设置自动填充的话,需要关闭数据库级别的自动填充(取消Navicat中的根据当前时间戳更新)
通过@TableField注解设置填充策略。
修改实体类,添加@TableField注解,设置填充策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Data public  class  User      @TableId(type = IdType.ASSIGN_ID)      private  Long id;     private  String name;     private  Integer age;     private  String email;          @TableField(fill = FieldFill.INSERT)      private  Date createTime;          @TableField(fill = FieldFill.INSERT_UPDATE)      private  Date updateTime; } 
编写自动填充处理器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package  cn.yanghuisen.mpdemo.handler;import  com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;import  org.apache.ibatis.reflection.MetaObject;import  org.springframework.stereotype.Component;import  java.util.Date;@Component public  class  MyMetaObjectHandler  implements  MetaObjectHandler           @Override      public  void  insertFill (MetaObject metaObject)           this .setFieldValByName("createTime" ,new  Date(),metaObject);         this .setFieldValByName("updateTime" ,new  Date(),metaObject);     }          @Override      public  void  updateFill (MetaObject metaObject)           this .setFieldValByName("updateTime" ,new  Date(),metaObject);     } } 
这样在进行插入和更新操作时,就可以自动填充时间到数据库了。
乐观锁 什么是乐观锁,什么是悲观锁 
乐观锁,顾名思义,很乐观。就是它总会知道自己不会出现问题,无论干什么都不会上锁。如果出现问题,再次更新测试。
悲观锁,顾名思义,很悲观。就是它做什么都会上锁,再去操作。
 
乐观锁在数据库中一般使用version字段表示。
乐观锁的实现机制: 
取出记录时,获取当前version 
更新时,带上这个version 
执行更新时, set version = newVersion where version = oldVersion 
如果version不对,就更新失败 
 
乐观锁的实现 给数据库表添加version字段,默认值为1
实体类添加version属性,并给其添加@Version注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package  cn.yanghuisen.mpdemo.entity;import  com.baomidou.mybatisplus.annotation.*;import  lombok.Data;import  java.util.Date;@TableName("user") @Data public  class  User      @TableId(type = IdType.ASSIGN_ID)      private  Long id;     private  String name;     private  Integer age;     private  String email;          @TableField(fill = FieldFill.INSERT)      private  Date createTime;          @TableField(fill = FieldFill.INSERT_UPDATE)      private  Date updateTime;          @Version      private  Integer version; } 
创建配置类,注册乐观锁插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  cn.yanghuisen.mpdemo.config;import  com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;import  org.springframework.context.annotation.Bean;import  org.springframework.context.annotation.Configuration;@Configuration public  class  MyBatisPlusConfig      @Bean      public  OptimisticLockerInterceptor optimisticLockerInterceptor ()           return  new  OptimisticLockerInterceptor();     } } 
逻辑删除 
物理删除:直接把数据中的数据删除
逻辑删除:在数据中没有被删除,而是通过一个变量(字段)来表示其失效(删除)状态
 
添加flag字段(用于表示是否是删除状态),类型为int,默认值为0
实体类中添加flag属性,并且设置注解@TableLogic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package  cn.yanghuisen.mpdemo.entity;import  com.baomidou.mybatisplus.annotation.*;import  lombok.Data;import  java.util.Date;@TableName("user") @Data public  class  User      @TableId(type = IdType.ASSIGN_ID)      private  Long id;     private  String name;     private  Integer age;     private  String email;          @TableField(fill = FieldFill.INSERT)      private  Date createTime;          @TableField(fill = FieldFill.INSERT_UPDATE)      private  Date updateTime;          @Version      private  Integer version;          @TableLogic      private  Integer flag; } 
在application.yml进行配置逻辑删除
1 2 3 4 5 mybatis-plus:   global-config:      db-config:        logic-delete-value:  1               logic-not-delete-value:  0     
测试逻辑删除
1 2 3 4 5 @Test void  deleteUserById ()     userMapper.deleteById(7L );     selectListTest(); } 
注:在添加逻辑删除后,在查询时会自动过滤掉逻辑删除的记录。