二、常用注解
1.@TableId
问题:
经过以上的测试, MyBatis-Plus 在实现 CRUD 时,会默认将 id 作为主键列,并在插入数据时,默认
基于雪花算法的策略生成 id , 若实体类和表中表示主键的不是 id ,而是其他字段,例如 uid , MyBatis-Plus 会自动识别 uid 为主 键列吗? 我们实体类中的属性 id 改为 uid ,将表中的字段 id 也改为 uid,测试添加功能 程序抛出异常, Field 'uid' doesn't have a default value ,说明 MyBatis-Plus 没有将 uid 作为主键 赋值。
解决 :在实体类表中的字段加上@TableId注解。
@TeableId的Value属性:
若实体类中主键对应的属性为 id ,而表中表示主键的字段为 uid ,此时若只在属性 id 上添加注解
@TableId ,则抛出异常 Unknown column 'id' in 'field list' ,即 MyBatis-Plus 仍然会将 id 作为表的
主键操作,而表中表示主键的是字段 uid
此时需要通过 @TableId 注解的 value 属性,指定表中的主键字段, @TableId("uid") 或
@TableId(value="uid")
@TableId 的 type 属性:
使用数据库的自增策略,注意,该类型请确保数据库设置了 id 自增, 否则无效
配置全局主键策略:
mybatis-plus: configuration: # 配置MyBatis日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: # 配置MyBatis-Plus操作表的默认前缀 table-prefix: t_ # 配置MyBatis-Plus的主键策略 id-type: auto
2.@TableField
问题:如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?
如果是驼峰mybatisplus会自动匹配如果不是就要加入@TableField注解
解决:
@TableField("username") private String name;
3.@TableLogic
说明:用于逻辑删除
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为 “ 被删除状态 ” ,之后在数据库
中仍旧能看到此条数据记录
(1)在数据库加入is_delete字段(int类型 长度11 默认0,0表示未删除,1表示已删除)
(2)在实体类字段中加入@TableLogic注解
@TableLogic private Integer isDelete
三、条件构造器和常用接口
1、wapper介绍如图
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用 Lambda 语法
LambdaQueryWrapper :用于 Lambda 语法使用的查询 Wrapper
LambdaUpdateWrapper : Lambda 更新封装 Wrapper
2.QueryWrapper常用方法
常用:like,between,or,and,isNotNull,isNull,order,gt(大于),lt小于可以看我博客有详细介绍。
QuerWrapper常用条件参数
https://blog.csdn.net/weixin_47343544/article/details/119796505?spm=1001.2014.3001.5502
方法使用形式:(注:第一个参数是数据库中的字段名)
@Test public void test01(){ //查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息 //SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL) QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.like("username", "a") .between("age", 20, 30) .isNotNull("email"); List<User> list = userMapper.selectList(queryWrapper); list.forEach(System.out::println); }
3.UpdateWrapper
区别:UpdateWrapper与QueryWrapper区别主要在于使用update方法。updatewrapper有专属的set方法,不用创建实体 对象。
UpdateWrapper:
@Test public void test07() { //将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改 //组装set子句以及修改条件 UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); //lambda表达式内的逻辑优先运算 updateWrapper .set("age", 18) .set("email", "user@atguigu.com") .like("username", "a") .and(i -> i.gt("age", 20).or().isNull("email")); } QueryWrapper: @Test public void test04() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改 //UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND age > ? OR email IS NULL) ueryWrapper .like("username", "a") .gt("age", 20) .or() .isNull("email"); User user = new User(); user.setAge(18); user.setEmail("user@atguigu.com"); int result = userMapper.update(user, queryWrapper); System.out.println("受影响的行数:" + result); }
4.Condition
如果你想在使用QueryWrapper调用方法传入的字段的参数进行验证的话,不用if else可以使用Condition参数,选择方法带condition参数的方法。
例如:
QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper .like(StringUtils.isNotBlank(username), "username", "a") .ge(ageBegin != null, "age", ageBegin) .le(ageEnd != null, "age", ageEnd);
5.LambdaQueryWrapper
说明:LambdaQueryWrapper与QueryWrapper的区别主要在于,将数据库表中的字段变成了在实体类中调用方法如:将“user_name” 变为 User::getUserName
例:
@Test public void test09() { //定义查询条件,有可能为null(用户未输入) String username = "a"; Integer ageBegin = 10; Integer ageEnd = 24; LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); //避免使用字符串表示字段,防止运行时错误 queryWrapper .like(StringUtils.isNotBlank(username), User::getName, username) .ge(ageBegin != null, User::getAge, ageBegin) .le(ageEnd != null, User::getAge, ageEnd); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
四、插件
1.使用分页插件,配置
//创建配置类,添加内部拦截器 @Configuration @MapperScan("com.atguigu.mybatisplus.mapper") //可以将主类中的注解移到此处 public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
2.常用分页方法
@Test public void testPage(){ //设置分页参数 Page<User> page = new Page<>(1, 5); userMapper.selectPage(page, null); //获取分页数据 List<User> list = page.getRecords(); list.forEach(System.out::println); System.out.println("当前页:"+page.getCurrent()); System.out.println("每页显示的条数:"+page.getSize()); System.out.println("总记录数:"+page.getTotal()); System.out.println("总页数:"+page.getPages()); System.out.println("是否有上一页:"+page.hasPrevious()); System.out.println("是否有下一页:"+page.hasNext()); }
3.实现乐观锁
(1.)实现流程
SELECT id,`name`,price,`version` FROM product WHERE id=1 UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1
(2)在数据库表中添加version(int类型)字段。在实体类中添加version属性,添加@Version注解。
@Data public class Product { private Long id; private String name; private Integer price; @Version private Integer version; }
(3)添加乐观锁插件配置
在配置类中添加乐观锁拦截器
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //添加乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; }
(4)进行测试,在p2修改失败后,在进行一次查询版本号,在重新插入。
4.通用枚举
(1)在数据库表中加入sex字段(int类型),创建枚举实体类
@Data public enum SexEnum { MALE(1, "男"), FEMALE(2, "女"); @EnumValue private Integer sex; private String sexName; }
(2)进行配置
mybatis-plus: type-enums-package: com.atguigu.mybatisplus.enums
五、代码生成器
1.引入依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency>
2.输入代码
public class FastAutoGeneratorTest { public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "123456").globalConfig(builder -> { builder.author("atguigu") // 设置作者 //.enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir("D://mybatis_plus"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.atguigu") // 设置父包名 .moduleName("mybatisplus") // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("t_user") // 设置需要生成的表名 .addTablePrefix("t_", "c_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默认的是Velocity引擎模板 .execute(); } }