可对比:
官网:https://mp.baomidou.com/
MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提供效率。
特性
入门案例 <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.4.1</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.1.16</version > </dependency >
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC username: root password: root
@Mapper public interface UserDao extends BaseMapper <User>{}
标准数据层CRUD功能
lombok <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency >
新版本IDEA已经内置了该插件,如果删除setter和getter方法程序有报红,则需要安装插件
MP分页查询 设置分页拦截器作为Spring管理的bean
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor () { MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor (); mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor ()); return mpInterceptor; } }
执行分页查询
IPage<User> page=new Page <>(1 ,3 ); userDao.selectPage(page,null ); System.out.println("当前页码值:" +page.getCurrent()); System.out.println("每页显示数:" +page.getSize()); System.out.println("一共多少页:" +page.getPages()); System.out.println("一共多少条数据:" +page.getTotal()); System.out.println("数据:" +page.getRecords());
开启日志 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: banner: off
取消初始化spring日志打印,resources目录下添加logback.xml,名称固定,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <configuration > </configuration >
取消SpringBoot的log打印
spring: main: banner-mode: off
条件查询 QueryWrapper qw = new QueryWrapper ();qw.lt("age" ,18 ); QueryWrapper<User> qw = new QueryWrapper <User>(); qw.lambda().lt(User::getAge, 10 ); LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.lt(User::getAge, 10 ); List<User> userList = userDao.selectList(lqw);
多条件构建 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.lt(User::getAge, 30 ).gt(User::getAge, 10 ); lqw.lt(User::getAge, 10 ).or().gt(User::getAge, 30 ); List<User> userList = userDao.selectList(lqw);
null值处理 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.lt(null !=uq.getAge2(),User::getAge, uq.getAge2()) .gt(null !=uq.getAge(),User::getAge, uq.getAge()); List<User> userList = userDao.selectList(lqw);
查询投影 查询指定字段 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.select(User::getId,User::getName,User::getAge); List<User> userList = userDao.selectList(lqw);
// 非lambda版
QueryWrapper<User> qw = new QueryWrapper <User>(); qw.select("id" ,"name" ,"age" ,"tel" ); List<User> userList = userDao.selectList(qw);
聚合查询 QueryWrapper<User> lqw = new QueryWrapper <User>(); lqw.select("count(*) as count" ); lqw.select("max(age) as maxAge" ); lqw.select("min(age) as minAge" ); lqw.select("sum(age) as sumAge" ); lqw.select("avg(age) as avgAge" ); List<Map<String, Object>> userList = userDao.selectMaps(lqw);
分组查询 QueryWrapper<User> lqw = new QueryWrapper <User>(); lqw.select("count(*) as count,tel" ); lqw.groupBy("tel" ); List<Map<String, Object>> list = userDao.selectMaps(lqw);
查询条件 MP的查询条件有很多:
范围匹配(> 、 = 、between)
模糊匹配(like)
空判定(null)
包含性匹配(in)
分组(group)
排序(order)
……
等值查询 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.eq(User::getName, "Jerry" ).eq(User::getPassword, "jerry" ); User loginUser = userDao.selectOne(lqw);
相当于:
SELECT id,name ,password ,age,tel FROM user WHERE (name = ? AND password = ?)
范围查询 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.between(User::getAge, 10 , 30 ); List<User> userList = userDao.selectList(lqw);
相当于:
SELECT id,name ,password ,age,tel FROM user WHERE (age BETWEEN ? AND ?)
gt():大于(>)
ge():大于等于(>=)
lt():小于(<)
lte():小于等于(<=)
between():between ? and ?
模糊查询 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper <User>(); lqw.likeLeft(User::getName, "J" ); List<User> userList = userDao.selectList(lqw);
相当于:
SELECT id,name ,password ,age,tel FROM user WHERE (name LIKE ?)
like():前后加百分号,如 %J%
likeLeft():前面加百分号,如 %J
likeRight():后面加百分号,如 J%
排序查询 LambdaQueryWrapper<User> lwq = new LambdaQueryWrapper <>(); lwq.orderBy(true ,false , User::getId);
orderBy排序
condition:条件,true则添加排序,false则不添加排序
isAsc:是否为升序,true升序,false降序
columns:排序字段,可以有多个
orderByAsc/Desc(单个column):按照指定字段进行升序/降序
orderByAsc/Desc(多个column):按照多个字段进行升序/降序
orderByAsc/Desc
condition:条件,true添加排序,false不添加排序
多个columns:按照多个字段进行排序
除此之外,还有isNull,isNotNull,in,notIn等等方法可供选择,具体参考官方文档的条件构造器
映射匹配兼容性 @Data @TableName("tbl_user") public class User { private Long id; private String name; @TableField(value="pwd",select=false) private String password; private Integer age; private String tel; @TableField(exist=false) private Integer online; }
id生成策略控制 @TableId(type = IdType.AUTO) private Long id;
AUTO: 使用数据库ID自增
NONE: 不设置id生成策略
INPUT: 用户手工输入id 这种ID生成策略,需要将表的自增策略删除掉
ASSIGN_ID: 雪花算法生成id(可兼容数值型与字符串型), 这种生成策略,不需要手动设置ID,如果手动设置ID,则会使用自己设置的值。
ASSIGN_UUID: 以UUID生成算法作为id生成策略, 使用uuid需要注意的是,主键的类型不能是Long,而应该改成String类型
其他的几个策略均已过时,都将被ASSIGN_ID和ASSIGN_UUID代替掉。
ID生成策略对比
介绍了这些主键ID的生成策略,我们以后该用哪个呢?
NONE: 不设置id生成策略,MP不自动生成,约等于INPUT,所以这两种方式都需要用户手动设置,但是手动设置第一个问题是容易出现相同的ID造成主键冲突,为了保证主键不冲突就需要做很多判定,实现起来比较复杂
AUTO:数据库ID自增,这种策略适合在数据库服务器只有1台的情况下使用,不可作为分布式ID使用
ASSIGN_UUID:可以在分布式的情况下使用,而且能够保证唯一,但是生成的主键是32位的字符串,长度过长占用空间而且还不能排序,查询性能也慢
ASSIGN_ID:可以在分布式的情况下使用,生成的是Long类型的数字,可以排序性能也高,但是生成的策略和服务器时间有关,如果修改了系统时间就有可能导致出现重复主键
综上所述,每一种主键策略都有自己的优缺点,根据自己项目业务的实际情况来选择使用才是最明智的选择。
简化配置 模型类主键策略设置:
mybatis-plus: global-config: db-config: id-type: assign_id
数据库表与模型类的映射关系:
mybatis-plus: global-config: db-config: table-prefix: tbl_
雪花算法 雪花算法(SnowFlake),是Twitter官方给出的算法实现 是用Scala写的。其生成的结果是一个64bit大小整数,它的结构如下图:
1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。
41bit-时间戳,用来记录时间戳,毫秒级
10bit-工作机器id,用来记录工作机器id,其中高位5bit是数据中心ID其取值范围0-31,低位5bit是工作节点ID其取值范围0-31,两个组合起来最多可以容纳1024个节点
序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID
多记录操作 List<T> selectBatchIds (@Param(Constants.COLLECTION) Collection<? extends Serializable> idList) ;
List<Long> list = new ArrayList <>(); list.add(1L ); list.add(3L ); list.add(4L ); userDao.selectBatchIds(list); List<Long> list = Arrays.asList(new Long []{2 ,3 }); userDao.deleteBatchIds(ids);
逻辑删除 步骤1:修改数据库表添加deleted
列
步骤2:实体类添加属性
@TableLogic(value="0",delval="1") private Integer deleted;
也可在yaml中配置:
mybatis-plus: global-config: db-config: logic-delete-field: deleted logic-not-delete-value: 0 logic-delete-value: 1
逻辑删除的本质为:
逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。
底层执行的SQL语句为:
UPDATE tbl_user SET deleted= 1 where id = ? AND deleted= 0
乐观锁 步骤1:数据库中添加锁标记字段
步骤2:实体类中添加对应的属性
@Version private Integer version;
步骤3:添加乐观锁的拦截器
@Configuration public class MpConfig { @Bean public MybatisPlusInterceptor mpInterceptor () { MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor (); mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor ()); return mpInterceptor; } }
携带version字段更新
User user = new User ();user.setId(3L ); user.setName("Jock666" ); user.setVersion(1 ); userDao.updateById(user);
也可以根据主键查询出数据,这样自带version
User user = userDao.selectById(3L );user.setName("Jock888" ); userDao.updateById(user);
底层执行的SQL语句为:
UPDATE tbl_user SET name = ?, version = ? where id = ? AND version= ?
MP官网乐观锁配置步骤
代码生成器
模板: MyBatisPlus提供,可以自己提供,但是麻烦,不建议
数据库相关配置:读取数据库获取表和字段信息
开发者自定义配置:手工配置,比如ID生成策略
<dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-generator</artifactId > <version > 3.4.1</version > </dependency > <dependency > <groupId > org.apache.velocity</groupId > <artifactId > velocity-engine-core</artifactId > <version > 2.3</version > </dependency >
public class CodeGenerator { public static void main (String[] args) { AutoGenerator autoGenerator = new AutoGenerator (); DataSourceConfig dataSource = new DataSourceConfig (); dataSource.setDriverName("com.mysql.cj.jdbc.Driver" ); dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC" ); dataSource.setUsername("root" ); dataSource.setPassword("root" ); autoGenerator.setDataSource(dataSource); GlobalConfig globalConfig = new GlobalConfig (); globalConfig.setOutputDir(System.getProperty("user.dir" )+"/mybatisplus_04_generator/src/main/java" ); globalConfig.setOpen(false ); globalConfig.setAuthor("黑马程序员" ); globalConfig.setFileOverride(true ); globalConfig.setMapperName("%sDao" ); globalConfig.setIdType(IdType.ASSIGN_ID); autoGenerator.setGlobalConfig(globalConfig); PackageConfig packageInfo = new PackageConfig (); packageInfo.setParent("com.aaa" ); packageInfo.setEntity("domain" ); packageInfo.setMapper("dao" ); autoGenerator.setPackageInfo(packageInfo); StrategyConfig strategyConfig = new StrategyConfig (); strategyConfig.setInclude("tbl_user" ); strategyConfig.setTablePrefix("tbl_" ); strategyConfig.setRestControllerStyle(true ); strategyConfig.setVersionFieldName("version" ); strategyConfig.setLogicDeleteFieldName("deleted" ); strategyConfig.setEntityLombokModel(true ); autoGenerator.setStrategy(strategyConfig); autoGenerator.execute(); } }
官方文档