mybatis-plus Mybatis-Plus简介 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
官网:https://baomidou.com/
愿景:我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。
特性
无侵入 :只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小 :启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持数据库
任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。
MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库,星瑞格数据库
框架结构
代码托管
Gitee | Github
Mybatis-Plus环境搭建 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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 # 1.创建一个springboot项目 我这里只标注下依赖 <!--springboot父项目--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.7</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!--引入web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> # 2.引入mybatis-plus依赖和后边使用的依赖 注意:不需要再引入mybatis的相关依赖,只引入mybatis-plus这一个即可,当然数据库相关的驱动还需要显式引入。 <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> <!--打包时不需要--> </dependency> <!--springnboot热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!--引入阿里巴巴druid数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.19</version> </dependency> <!--引入test测试依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 打包插件,可以以java -jar打包 在打成jar包运行时,必须放入此插件配置,没有插件配置无法运行打包的项目 --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> # 3.入口类添加@MapperScan注解扫描dao包!!! - 用来扫描DAO接口所在包,同时将所有DAO接口在工厂中创建对象 # 4.配置文件编写配置mybatis-plus及日志相关配置 日志的配置可以方便我们看sql语句 #配置mybatis-plus,mapper文件位置、实体类别名设置均可省略不写 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=xxxx # 日志配置 logging.level.root=info logging.level.com.chabai.dao=debug # 5.创建数据库及表结构 DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `bir` timestamp null default null, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1; INSERT INTO `user` VALUES (1,'chabai',22,'2022-08-01'); # 6.开发实体类 package com.chabai.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import lombok.experimental.Accessors; import java.util.Date; @Data //getter、setter @AllArgsConstructor //有参构造 @NoArgsConstructor //无参构造 @ToString //toString @Accessors(chain = true)//开启链式调用 public class User { private String id; private String name; private Integer age; private Date bir; } # 7.开发dao接口(即mapper通用实现,无需再写XxxMapper.xml对应实现) package com.chabai.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.chabai.entity.User; //使用mybatis-plus去增强接口 继承BaseMapper里面已经为我们声明了许多增删改查的方法 不需要我们自己声明了 public interface UserDAO extends BaseMapper<User> { } # 8.到这里我们dao模块就开发完成了 我们不需要写mapper映射文件就可以使用方法了我们可以做以下测试验证 如果自己有特殊需求可自己在dao接口声明方法 在mapper映射文件实现方法 自定义的话别忘了配置文件 - 注意:该测试类在测试包test下的包结构要和入口类的包结构相同 package com.chabai; import com.chabai.dao.UserDAO; import com.chabai.entity.User; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @SpringBootTest public class TestUserDAO { private static final Logger log = LoggerFactory.getLogger(TestUserDAO.class); @Autowired private UserDAO userDAO; //查询所有 @Test public void testFindAll(){ List<User> users = userDAO.selectList(null); for (User user : users) { log.info("user:{}",user); } } } # 9.经测试发现可以成功使用方法
常用注解
使用mybatis时我们指定顶哪张表哪个记录是通过我们mapper映射文件指定的 我们mybatispllus可用注解实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 0.常见注解 我们这里只讲几个实用的 别的开发时遇到 - 参考官方文档https://baomidou.com/pages/223848/#tablename- @TableName- @Tableld- @TableField# 1.@TableName注解 - 描述:用来将实体对象与数据库表明完成映射- 修饰范围:用在类上- 常见属性: - value:String类型,指定映射的表名 不指定时默认将类名首字母小写作为表名 - resultMap:String类型,用来指定XML配置文件中resultMap的id值 一般用不上# 2.@Tableld注解 - 描述:主键注释- 修饰范围:用在属性上- 常见属性: - value:String类型,指定实体类与表中对应的主键列名 和数据库主键名一致可不指定 - resultMap:枚举类型,指定主键生成类型 值如下:
值
描述
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)
UUID
32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR
分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)
1 2 3 4 5 6 7 # 3.@TableField注解 - 描述:字段注解(非主键)- 修饰范围:用在属性上- 常见属性: - value:String类型,用来指定对应的数据库表中的字段名 - el:String类型,映射为原生 #{...} 逻辑,相当于写在 xml #{...}部分 废弃 - exist: boolen是否为数据库表字段 ture代表是数据库字段 ,false代表不是 可帮助我们处理不映射数据库的业务属性
常见方法使用
查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 1.查询所有 List<User> users = userDAO.selectList(null); # 2.根据主键查询一个 User user = userDAO.selectById("2"); # 3.条件查询 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",val:23);//设置等值查询 queryWrapper.lt("age",val:23);//设置小于查询 queryWrapper.le("age",val:23);//设置小于等于查询 //gt大于 ge大于等于......用的时候自己找合适的即可 queryWrapper.like("name","chabai")//模糊查询 %chabai% queryWrapper.likeLeft("name","chabai")//模糊查询 %chabai queryWrapper.likeRight("name","chabai")//模糊查询 chabai% List<User> users = userDAO.selectList(queryWrapper); # //4.分页查询后边讲
保存
1 2 3 4 # 1.保存 User entity = new User(); entity.setName("chabai").setAge(22).setBir(new Date()); user.insert(entity);
修改
1 2 3 4 5 6 7 8 9 10 11 # 1.基于主键id进行数据修改 User user = userDao.selectById(3); user.setName("大漂亮"); userDao.updateById(user); # 2.批量修改 User user = new User(); user.setName("大聪明"); //如果为User user = userDao.selectById(3)要自己设置不修改哪个字段 user.setBir(null) QueryWrapper<User> updateWrapper = new QueryWrapper<>(); updateWrapper.eq("age",28);//将年龄为28岁的名字修改为大聪明 userDao.update(user,updateWrapper);
删除
1 2 3 4 5 6 # 1.基于主键id进行删除 userDao.deleteById(6); # 2.基于条件删除 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",28); userDao.delete(queryWrapper);
分页查询 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 # 写配置类 添加分页插件 @Configuration @MapperScan("com.chabai.dao") public class MybatisPlusConfig { //分页的拦截器对象 MybatisPlusInterceptor @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加 //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType return interceptor; } } # 无条件分页查询使用 //参数一:当前页 默认值为1 参数二:每页显示记录数 默认值为10 IPage<User> page = new Page<>(1,2); IPage<User> userIPage = userDAO.selectPage(page,null); long total = userIPage.getTatol();//总记录数 # 有条件分页查询使用 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",22); //参数一:当前页 默认值为1 参数二:每页显示记录数 默认值为10 IPage<User> page = new Page<>(1,2); IPage<User> userIPage = userDAO.selectPage(page,null); long total = userIPage.getTatol();//总记录数
多数据源配置实现读写分离
引言
为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据服务器,主要是进行读的操作。
代码实现 注:我们这里只实现读写分离 没有主从同步
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 102 103 104 105 106 107 108 109 110 111 112 113 114 # l.引入dynamic-datasource-spring-boot-starter依赖 <!--多数据源依赖dynamic-datasource--> <dependency > <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.0.0</version> </dependency> # 2. application.properties配置数据源 #不能再使用传统方式配置了,我们数据源有多个 ##配置mybatis-plus,mapper文件位置、实体类别名设置均可省略不写 #spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?characterEncoding=UTF-8 #spring.datasource.username=root #spring.datasource.password=root #一主一从举例 #指定默认数据源 spring.datasource.primary=master #主数据源 master,默认执行增删改操作 spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.jdbc.Driver spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/mybatis-plus?characterEncoding=UTF-8 spring.datasource.dynamic.datasource.master.username=root spring.datasource.dynamic.datasource.master.password=root #从数据源 salve_1,执行查询操作 spring.datasource.dynamic.datasource.slave_1.driver-class-name=com.mysql.jdbc.Driver spring.datasource.dynamic.datasource.slave_1.url=jdbc:mysql://localhost:3306/mybatis-plus-1?characterEncoding=UTF-8 spring.datasource.dynamic.datasource.slave_1.username=root spring.datasource.dynamic.datasource.slave_1.password=root # 3.DS注解 不加主机默认使用master主库数据源 作用: 用来切换数据源的注解 修饰范围: 方法上和类上均可使用,同时存在时方法注解优先于类上注解(局部优先)。 Value属性: 切换数据源名称 # 4.在业务层才能完成多数据源切换 - 开发service接口 package com.chabai.service; import com.chabai.entity.User; import java.util.List; public interface UserService { List<User> findAll(); void save(User user); } - 写实现类 package com.chabai.service; import com.chabai.dao.UserDAO; import com.chabai.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Override @DS("salve_1") public List<User> findAll() { return userDAO.selectList(null); } @Override @DS("master") public void save(User user) { userDAO.insert(user); } } # 测试 package com.chabai; import com.chabai.dao.UserDAO; import com.chabai.entity.User; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @SpringBootTest public class TestUserDAO { private static final Logger log = LoggerFactory.getLogger(TestUserDAO.class); @Autowired private UserService userService; @Test public void testFindAll(){ userService.findAll().forEach(user->System.out.println("user =" + user)); } @Test public String testSave(User user){ User use = new User(); user.setName("aaa").setAge(22).setBir(new Date()); userService.save(user); } }
更多使用方法请参考官方文档