当前位置:   article > 正文

SpringBoot与MybatisPlus MybatisPlus_mybatisplus版本匹配spring boot版本

mybatisplus版本匹配spring boot版本

一、MyBatisPlus概述

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

MyBatisPlus的愿景是成为MyBatis最好的搭档,就像魂斗罗中的1P、2P,基友搭配,效率翻倍。

官方网址:MyBatis-Plus 

二、SpringBoot集成MyBatisPlus

1、创建SpringBoot项目,添加MyBatisPlus起步依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-test</artifactId>
  8. <scope>test</scope>
  9. </dependency>
  10. <!-- MyBatisPlus -->
  11. <dependency>
  12. <groupId>com.baomidou</groupId>
  13. <artifactId>mybatis-plus-boot-starter</artifactId>
  14. <version>3.5.0</version>
  15. </dependency>
  16. <!-- mysql驱动 -->
  17. <dependency>
  18. <groupId>mysql</groupId>
  19. <artifactId>mysql-connector-java</artifactId>
  20. <version>8.0.26</version>
  21. </dependency>
  22. <!-- lombok -->
  23. <dependency>
  24. <groupId>org.projectlombok</groupId>
  25. <artifactId>lombok</artifactId>
  26. <optional>true</optional>
  27. </dependency>

2、在SpringBoot配置文件中配置数据源

  1. # 数据源
  2. spring:
  3. datasource:
  4. driver-class-name: com.mysql.cj.jdbc.Driver
  5. url: jdbc:mysql:///mybatis?serverTimezone=UTC
  6. username: root
  7. password: 123456

3、编写实体类

  1. @Data
  2. public class User {
  3. public Integer id;
  4. public String username;
  5. public String sex;
  6. public String address;
  7. public Integer account;
  8. }

 4、编写Mapper接口,继承BaseMapper

  1. public interface UserMapper extends BaseMapper<User> {
  2. }

5、在 SpringBoot启动类中添加 @MapperScan 注解,扫描Mapper文件夹

  1. @SpringBootApplication
  2. @MapperScan("com.zj.mapper")
  3. public class DemoApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(DemoApplication.class, args);
  6. }
  7. }

6、测试Mapper方法

  1. @SpringBootTest
  2. public class TestUserMapper {
  3. @Resource
  4. private UserMapper userMapper;
  5. @Test
  6. public void test(){
  7. User user = userMapper.selectById(10);
  8. System.out.println(user);
  9. }
  10. }

二、MyBatisPlus  CRUD

2.1 添加

1、配置文件开启SQL日志打印

  1. # 开启SQL日志
  2. mybatis-plus:
  3. configuration:
  4. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2、测试添加方法

  1. @Test
  2. public void testAdd(){
  3. User user = new User(null,"梅川内酷","男","临沂市",3000);
  4. userMapper.insert(user);
  5. // MyBatisPlus插入成功后,可直接直接获取主键的值
  6. System.out.println(user.getUserId());
  7. }

2.2 相关注解

我们将user类中的字段修改为和数据库表中的字段不一致。将表名称改为tb_user, 这样表中的字段、表名都和实体类不一致。这样mybatosplus无法自动将字段和属性对应。也就无法生成正确的sql语句。此时需要使用注解来指定映射关系。

@TableName

作用:指定类为哪个表的实体类

位置:类上方

@TableId

作用:指定实体类的属性为主键

位置:属性上方

属性:

  • value:主键字段名

  • type:主键策略

描述
NONE无状态,不设置主键类型
AUTO自增主键
INPUT插入前自行设置主键值
ASSIGN_ID默认策略,使用雪花算法自动生成主键ID,主键类型为整形或字符串。(雪花算法:微博开源的分布式ID生成算法,使用一个64位的Long类型数字作为全局唯一ID。在分布式系统中的应用十分广泛,且ID引入了时间戳,基本上保持自增)
ASSIGN_UUID自动生成排除中划线的UUID作为主键,主键类型为

@TableField

作用:在属性和列名不同的情况下,指定映射关系

位置:非主键属性上方

  1. @Data
  2. @AllArgsConstructor
  3. @TableName("tb_user")
  4. public class User {
  5. @TableId(value = "id",type = IdType.AUTO)
  6. public Integer UserId;
  7. @TableField("username")
  8. public String userName;
  9. @TableField("sex")
  10. public String userSex;
  11. @TableField("address")
  12. public String userAddress;
  13. @TableField("account")
  14. public Integer userAccount;
  15. }

2.3 修改

  1. @Test
  2. public void testUpdate(){
  3. User user = new User(1,"梅川丘酷","男","烟台市",4000);
  4. userMapper.updateById(user);
  5. }

2.4 删除

 根据id删除

  1. @Test
  2. public void testDeleteById(){
  3. userMapper.deleteById(8);
  4. }

批量删除

  1. @Test
  2. public void testDeleteBatch(){
  3. ArrayList<Integer> ids = new ArrayList<>();
  4. ids.add(9);
  5. ids.add(10);
  6. ids.add(11);
  7. userMapper.deleteBatchIds(ids);
  8. }

根据字段的条件删除

  1. @Test
  2. public void testDeleteMap(){
  3. Map<String,Object> map = new HashMap<String,Object>();
  4. map.put("sex","男"); ;//删除所有字段(字段是数据库列名不是类的属性名)值是男的数据
  5. userMapper.deleteByMap(map);
  6. }

2.5 查询

根据id查询

  1. @Test
  2. public void testFindById(){
  3. User user = userMapper.selectById(1);
  4. System.out.println(user);
  5. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE id=?
  2. ==> Parameters: 5(Integer)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  5. <== Total: 1

根据id批量查询

  1. @Test
  2. public void testFindBatch(){
  3. ArrayList<Integer> ids = new ArrayList<>();
  4. ids.add(5);
  5. ids.add(6);
  6. ids.add(12);
  7. List<User> users = userMapper.selectBatchIds(ids);
  8. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE id IN ( ? , ? , ? )
  2. ==> Parameters: 5(Integer), 6(Integer), 12(Integer)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  5. <== Row: 6, 张晓, 女, 青岛市, 2500
  6. <== Row: 12, 唐宛凝, 女, 石家庄市, 3334
  7. <== Total: 3

根据字段条件查询

  1. @Test
  2. public void testFindByMap(){
  3. Map<String,Object> map = new HashMap<String,Object>();
  4. //条件之间是and关系
  5. map.put("username","张晓");
  6. map.put("address","青岛市");
  7. List<User> users = userMapper.selectByMap(map);
  8. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE address = ? AND username = ?
  2. ==> Parameters: 青岛市(String), 张晓(String)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 6, 张晓, 女, 青岛市, 2500
  5. <== Total: 1

 2.7 条件构造器

 Mybatis-Plus通过QueryWrapper对象让用户自由的构建SQL条件,简单便捷,没有额外的负担,能够有效提高开发效率。

条件参数说明:

查询方式说明
or或条件语句
and且条件语句
like模糊查询 like
notLike模糊查询 not Like
existsexists 条件语句
notExistsnot Exists 条件语句
isNullnull 值查询
isNotNullis Not Null 查询
inin 查询
notInnot in 查询
groupBy分组查询
orderBy排序查询
having分组后筛选
eq等于 =
ne不等于 <>
betweenbetween 条件语句
gt大于>
ge大于等于>=
lt小于<
le小于等于<=

 示例1:查询账户余额在1000-3000之间的用户的信息

  1. @Test
  2. public void testFindWrapper(){
  3. //创建条件构造器
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.ge("account", 1000).lt("account", 3000);
  6. List<User> users = userMapper.selectList(wrapper);
  7. for (User user : users) {
  8. System.out.println(user);
  9. }
  10. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE (account >= ? AND account < ?)
  2. ==> Parameters: 1000(Integer), 3000(Integer)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  5. <== Row: 6, 张晓, 女, 青岛市, 2500
  6. <== Total: 2

示例2:查询账户小于1000或者大于等于9000的用户

  1. @Test
  2. public void testFindWrapper(){
  3. //创建条件构造器
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.lt("account", 2000).or().ge("account", 9000);
  6. List<User> users = userMapper.selectList(wrapper);
  7. for (User user : users) {
  8. System.out.println(user);
  9. }
  10. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE (account < ? OR account >= ?)
  2. ==> Parameters: 2000(Integer), 9000(Integer)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  5. <== Row: 16, 郑怜雪, 女, 重庆市, 555900
  6. <== Row: 19, 黎飒, 男, 深圳市, 9000
  7. <== Total: 3

示例3:查询名字中有张的用户,按照账户升序排序。

  1. @Test
  2. public void testFindWrapper(){
  3. //创建条件构造器
  4. QueryWrapper<User> wrapper = new QueryWrapper<>();
  5. wrapper.like("username", "张").orderByAsc("account");
  6. List<User> users = userMapper.selectList(wrapper);
  7. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE (username LIKE ?) ORDER BY account ASC
  2. ==> Parameters: %张%(String)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 6, 张晓, 女, 青岛市, 2500
  5. <== Row: 21, 张三, 男, 昆明市, 5000
  6. <== Total: 2

2.8 分页查询

1、在配置类或启动类配置分页插件

  1. // 注册插件
  2. @Bean
  3. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  4. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  5. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  6. return interceptor;
  7. }

2、测试分页查询

  1. @Test
  2. public void testFindPage(){
  3. //分页条件;第一个参数表示从第几条开始,第二个参数表示取几条数据。
  4. Page page = new Page(0,2);
  5. IPage<User> iPage = userMapper.selectPage(page, null);//null表示查询全部
  6. System.out.println("结果集:"+iPage.getRecords());
  7. System.out.println("总页数:"+iPage.getPages());
  8. System.out.println("总条数:"+iPage.getTotal());
  9. System.out.println("当前页:"+iPage.getCurrent());
  10. System.out.println("每页条数:"+iPage.getSize());
  11. }
  1. ==> Preparing: SELECT COUNT(*) AS total FROM tb_user
  2. ==> Parameters:
  3. <== Columns: total
  4. <== Row: 8
  5. <== Total: 1
  6. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user LIMIT ?
  7. ==> Parameters: 2(Long)
  8. <== Columns: UserId, username, userSex, userAddress, userAccount
  9. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  10. <== Row: 6, 张晓, 女, 青岛市, 2500
  11. <== Total: 2
  12. Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5ff2b8ca]
  13. 结果集:[User(UserId=5, userName=翟玲娇, userSex=女, userAddress=长沙市, userAccount=1000), User(UserId=6, userName=张晓, userSex=女, userAddress=青岛市, userAccount=2500)]
  14. 总页数:4
  15. 总条数:8
  16. 当前页:1
  17. 每页条数:2

2.9 全局配置

 假如数据库的所有表都以tb_开头,主键都是自增的。如果针对每一个实体类都要添加相关注解比较麻烦,可以在SpringBoot配置文件中进行全局配置,该配置在所有的实体类中都生效。

  1. mybatis-plus:
  2. # 全局配置
  3. global-config:
  4. db-config:
  5. #主键类型
  6. id-type: AUTO
  7. # 设置表名前缀
  8. table-prefix: tb_
  9. # 是否使用驼峰转下划线命名,默认开启 ,例如 实体类中的UserAddress属性等于数据库中的 user_address字段
  10. table-underline: true

三、ActiveRecord

Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。

在MyBatisPlus中,AR模式即在实体类中封装了对数据库的访问,而不通过mapper类。

1、虽然操作数据库不通过mapper类,但需要编写mapper类并继承BaseMapper

  1. public interface UserMapper extends BaseMapper<User> {
  2. }

2、实体类继承Model类,开启AR模式

  1. @Data
  2. @AllArgsConstructor
  3. @TableName("tb_user")
  4. public class User extends Model<User> {
  5. @TableId(value = "id",type = IdType.AUTO)
  6. public Integer UserId;
  7. @TableField("username")
  8. public String userName;
  9. @TableField("sex")
  10. public String userSex;
  11. @TableField("address")
  12. public String userAddress;
  13. @TableField("account")
  14. public Integer userAccount;
  15. }

四、ActiveRecord增删改查

 4.1 AR添加

  1. @Test
  2. public void testAdd(){
  3. User user = new User(null, "李四", "男", "北京市", 12000);
  4. user.insert();
  5. }
  1. ==> Preparing: INSERT INTO tb_user ( username, sex, address, account ) VALUES ( ?, ?, ?, ? )
  2. ==> Parameters: 李四(String), 男(String), 北京市(String), 12000(Integer)
  3. <== Updates: 1

4.2 AR根据id修改

  1. @Test
  2. public void testUpdate(){
  3. // 创建实体类对象
  4. User user = new User();
  5. // 设置需要更新的属性
  6. user.setUserAccount(13000);
  7. // 设置需要修改的id
  8. user.setUserId(22);
  9. // 根据主键进行更新,没有设置的值忽略
  10. user.updateById();
  11. }
  1. ==> Preparing: UPDATE tb_user SET account=? WHERE id=?
  2. ==> Parameters: 13000(Integer), 22(Integer)
  3. <== Updates: 1

4.3 AR根据id查询

  1. @Test
  2. public void testFindById(){
  3. User user = new User();
  4. user.setUserId(16);
  5. User user1 = user.selectById();
  6. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE id=?
  2. ==> Parameters: 16(Integer)
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 16, 郑怜雪, 女, 重庆市, 555900
  5. <== Total: 1

4.4 AR删除

  1. @Test
  2. public void testDeleteById(){
  3. User user = new User();
  4. user.setUserId(21);
  5. user.deleteById();
  6. }
  1. ==> Preparing: DELETE FROM tb_user WHERE id=?
  2. ==> Parameters: 21(Integer)
  3. <== Updates: 1

4.5 AR查询所有

  1. @Test
  2. public void testFindAll(){
  3. User user = new User();
  4. List<User> users = user.selectAll();
  5. }
  1. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user
  2. ==> Parameters:
  3. <== Columns: UserId, username, userSex, userAddress, userAccount
  4. <== Row: 5, 翟玲娇, 女, 长沙市, 1000
  5. <== Row: 6, 张晓, 女, 青岛市, 2500
  6. <== Row: 12, 唐宛凝, 女, 石家庄市, 3334
  7. <== Row: 16, 郑怜雪, 女, 重庆市, 555900
  8. <== Row: 18, 梅川内酷, 男, 临沂市, 3000
  9. <== Row: 19, 黎飒, 男, 深圳市, 9000
  10. <== Row: 20, 黄林, 男, 昆明市, 5000
  11. <== Row: 22, 李四, 男, 北京市, 13000
  12. <== Total: 8

4.6 AR分页查询

  1. @Test
  2. public void testFindPage(){
  3. // 创建分页条件
  4. Page page = new Page(0,2);
  5. // 查询构造器
  6. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  7. // 查询名字包含"张"的学生,按照账户升序排序
  8. queryWrapper.like("username","张").orderByAsc("account");
  9. User user = new User();
  10. // 分页查询
  11. IPage iPage = user.selectPage(page, queryWrapper);
  12. // 打印分页数据
  13. System.out.println("结果集:"+iPage.getRecords());
  14. System.out.println("总页数:"+iPage.getPages());
  15. System.out.println("总条数:"+iPage.getTotal());
  16. System.out.println("当前页:"+iPage.getCurrent());
  17. System.out.println("每页条数:"+iPage.getSize());
  18. }
  1. ==> Preparing: SELECT COUNT(*) AS total FROM tb_user WHERE (username LIKE ?)
  2. ==> Parameters: %张%(String)
  3. <== Columns: total
  4. <== Row: 2
  5. <== Total: 1
  6. ==> Preparing: SELECT id AS UserId,username,sex AS userSex,address AS userAddress,account AS userAccount FROM tb_user WHERE (username LIKE ?) ORDER BY account ASC LIMIT ?
  7. ==> Parameters: %张%(String), 2(Long)
  8. <== Columns: UserId, username, userSex, userAddress, userAccount
  9. <== Row: 6, 张晓, 女, 青岛市, 2500
  10. <== Row: 23, 张三, 男, 北京市, 12000
  11. <== Total: 2

注意:AR分页查询也需要配置分页插件 

五、MyBatisPlus插件

5.1 插件概述 

MyBatis插件机制

MyBatis插件就是对Executor、StatementHandler、ParameterHandler、ResultSetHandler这四个接口上的方法进行拦截,利用JDK动态代理机制,为这些接口的实现类创建代理对象,在执行方法时,先去执行代理对象的方法,从而执行自己编写的拦截逻辑。

  • Executor

    MyBatis的内部执行器,它负责调用StatementHandler操作数据库,并把结果集通过 ResultSetHandler进行自动映射。

  • StatementHandler

    MyBatis直接让数据库执行sql脚本的对象。

  • ParameterHandler

    MyBatis实现Sql入参设置的对象。

  • ResultSetHandler

    MyBatis把ResultSet集合映射成POJO的接口对象。

MyBatisPlus常用插件

MyBatisPlus依据MyBatis插件机制,为我们提供了一些开发中常用的插件,我们在开发中使用即可。

常用插件:

  • 自动分页: PaginationInnerInterceptor
  • 防止全表更新与删除: BlockAttackInnerInterceptor
  • 乐观锁: OptimisticLockerInnerInterceptor

这些插件都实现了InnerInterceptor接口

5.2 分页插件

在配置类或启动类配置分页插件,之前用过,不配置插件的话分页功能无法实现。

  1. // 注册插件
  2. @Bean
  3. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  4. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  5. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  6. return interceptor;
  7. }

5.3 防止全表更新与删除插件

作用:分析删除/更新语句,防止小白或者恶意进行删除/更新全表操作。

注意:

  • 该插件只支持 MySQL5.6.3 以上版本
  • 该插件只建议在开发环境中使用,不建议在生产环境使用

插件使用:

1、在配置类或启动类配置防止全表更新与删除插件

  1. // 注册插件
  2. @Bean
  3. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  4. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  5. // 分页插件
  6. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  7. // 防止全表更新与删除插件
  8. interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
  9. return interceptor;
  10. }

2、测试全表删除

  1. @Test
  2. public void testDeleteAll() {
  3. User user = new User();
  4. user.delete(new QueryWrapper());
  5. }

 5.4 乐观锁插件

修改数据库中的数据时,为了避免同时被其他人修改,最好的办法就是对该数据进行加锁以防止并发。

锁的设计分为悲观锁和乐观锁:

  • 悲观锁:悲观锁对数据被外界修改持保守态度。即在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现往往依靠数据库提供的锁机制。

  • 乐观锁:乐观锁在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做

 MyBatisPlus乐观锁插件实现方式:

  1. 取出记录时,获取当前version
  2. 更新时,带上这个version
  3. 执行更新时, set version = newVersion where version = oldVersion
  4. 如果version不对,就更新失败

使用MyBatisPlus乐观锁插件:

1、注册乐观锁插件

  1. // 注册插件
  2. @Bean
  3. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  4. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  5. // 分页插件
  6. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  7. // 防止全表更新与删除插件
  8. interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
  9. // 乐观锁插件
  10. interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  11. return interceptor;
  12. }

2、修改实体类,添加version列并在该属性上面增加@Version

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @TableName("tb_user")
  5. public class User extends Model<User> {
  6. @TableId(value = "id",type = IdType.AUTO)
  7. public Integer UserId;
  8. @TableField("username")
  9. public String userName;
  10. @TableField("sex")
  11. public String userSex;
  12. @TableField("address")
  13. public String userAddress;
  14. @TableField("account")
  15. public Integer userAccount;
  16. @Version
  17. private Integer version;
  18. }

3、修改数据库表,添加一列整型version字段并设置默认值为0

4、测试修改功能 

  1. @Test
  2. public void testUpdate1() {
  3. User user = new User();
  4. user.setUserId(18);
  5. user.setUserName("梅川丘酷");
  6. //如果版本号和数据库一致更新成功,版本号+1,如果不一致更新失败
  7. user.setVersion(0);
  8. user.updateById();
  9. }
  1. ==> Preparing: UPDATE tb_user SET username=?, version=? WHERE id=? AND version=?
  2. ==> Parameters: 梅川丘酷(String), 1(Integer), 18(Integer), 0(Integer)
  3. <== Updates: 1

 六、MyBatisPlus逻辑删除

6.1 逻辑删除概念

 在实际开发中,由于数据十分重要,为了避免误删除数据导致数据无法找回,我们往往不会使用物理删除,即从数据库中直接删除数据。而是采用逻辑删除的方式,即不会真正在数据库删除数据,而是通过一个变量代表它被删除。

 

deleted属性代表该数据是否删除,0代表未删除,1代表已删除。此时增删改查的Sql语句发生变化:

  • 插入: 不作限制
  • 查找: 追加where条件过滤掉已删除数据。
  • 更新: 追加where条件防止更新到已删除数据。
  • 删除: 转变为更新

例如:

  • 删除: update user set deleted=1 where id = 1 and deleted=0
  • 查找: select id,name,deleted from user where deleted=0

6.2 逻辑删除使用

 1、在配置文件配置逻辑删除

  1. # mybatis-plus相关配置
  2. mybatis-plus:
  3. # 全局配置
  4. global-config:
  5. db-config:
  6. # 全局逻辑删除的字段名
  7. logic-delete-field: deleted
  8. # 逻辑已删除值(默认为 1)
  9. logic-delete-value: 1
  10. # 逻辑未删除值(默认为 0)
  11. logic-not-delete-value: 0

2、修改实体类,添加逻辑删除属性

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @TableName("tb_user")
  5. public class User extends Model<User> {
  6. @TableId(value = "id",type = IdType.AUTO)
  7. public Integer UserId;
  8. @TableField("username")
  9. public String userName;
  10. @TableField("sex")
  11. public String userSex;
  12. @TableField("address")
  13. public String userAddress;
  14. @TableField("account")
  15. public Integer userAccount;
  16. @Version
  17. private Integer version;
  18. /*逻辑删除*/
  19. @TableLogic
  20. private Integer deleted;
  21. }

3、修改数据库表,添加一列整型deleted字段并设置默认值为0

4、测试删除和查询方法,会看到删除时将deleted字段变为1,查询时添加条件deleted=0

  1. @Test
  2. public void testDelete() {
  3. User user = new User();
  4. user.deleteById(23);
  5. }
  1. ==> Preparing: UPDATE tb_user SET deleted=1 WHERE id=? AND deleted=0
  2. ==> Parameters: 23(Integer)
  3. <== Updates: 1

bug:

  1. Caused by: org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1
  2. at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:218)
  3. at org.yaml.snakeyaml.reader.StreamReader.ensureEnoughData(StreamReader.java:176)
  4. at org.yaml.snakeyaml.reader.StreamReader.ensureEnoughData(StreamReader.java:171)
  5. at org.yaml.snakeyaml.reader.StreamReader.peek(StreamReader.java:126)
  6. at org.yaml.snakeyaml.scanner.ScannerImpl.scanToNextToken(ScannerImpl.java:1177)
  7. at org.yaml.snakeyaml.scanner.ScannerImpl.fetchMoreTokens(ScannerImpl.java:287)
  8. at org.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:227)
  9. at org.yaml.snakeyaml.parser.ParserImpl$ParseImplicitDocumentStart.produce(ParserImpl.java:195)
  10. at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158)
  11. at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:148)
  12. at org.yaml.snakeyaml.composer.Composer.checkNode(Composer.java:72)
  13. at org.yaml.snakeyaml.constructor.BaseConstructor.checkData(BaseConstructor.java:114)
  14. at org.yaml.snakeyaml.Yaml$1.hasNext(Yaml.java:543)
  15. at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160)
  16. at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134)
  17. at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75)
  18. at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
  19. at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:562)
  20. at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:518)
  21. ... 37 common frames omitted
  22. Caused by: java.nio.charset.MalformedInputException: Input length = 1

这里要将编码格式设置为utf-8,然后再删除yml配置文件,再重新写一个yml。

 七、MyBatisPlus扩展

7.1 自动填充

由于有了逻辑删除字段,那么向数据库插入数据时候,都需要设置deleted=0,而每次插入数据时都要设置该值十分繁琐,于是MyBatisPlus提供了自动填充功能。

1、为实体类的自动填充字段添加@TableField 

  1. @TableLogic
  2. // 自动填充字段
  3. @TableField(fill = FieldFill.INSERT)
  4. private Integer deleted;

填充策略:

描述
DEFAULT默认不处理
INSERT插入操作填充字段
UPDATE更新操作填充字段
INSERT_UPDATE插入操作和更新操作均填充字段

2、自定义填充类实现MetaObjectHandler接口

  1. package com.zj.meta;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import org.apache.ibatis.reflection.MetaObject;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class MyMetaObjectHandler implements MetaObjectHandler {
  7. /* 插入时填充逻辑
  8. * metaObject 元对象
  9. * */
  10. @Override
  11. public void insertFill(MetaObject metaObject) {
  12. /* 参数1:填充字段名
  13. * 参数2:参数值
  14. * 参数3:元对象*/
  15. this.setFieldValByName("deleted",0,metaObject);
  16. }
  17. @Override
  18. public void updateFill(MetaObject metaObject) {
  19. }
  20. }

3、测试插入数据

  1. @Test
  2. public void testAdd() {
  3. User user = new User();
  4. user.setUserName("小刚");
  5. user.setUserAddress("淄博市");
  6. user.setUserSex("男");
  7. user.setUserAccount(4000);
  8. user.insert();
  9. }
  1. ==> Preparing: INSERT INTO tb_user ( username, sex, address, account, deleted ) VALUES ( ?, ?, ?, ?, ? )
  2. ==> Parameters: 小刚(String), 男(String), 淄博市(String), 4000(Integer), 0(Integer)
  3. <== Updates: 1: 1

 在插入数据的时候,如果将数据库的deleted字段设置默认值为0的话,其实不需要使用mybatisplus的自动填充,因为在添加数据的时候自动就赋值为0了。

7.2 SQL注入器

 MyBatisPlus方法是有限的,我们可以使用SQL注入器自定义全局方法,注入到全局中,这样所有的Mapper类都能使用该方法,接下来我们自定义一个deleteAll方法。

1、创建注入方法类,继承AbstractMethod

  1. public class DeleteAll extends AbstractMethod {
  2. @Override
  3. public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
  4. //1.定义sql语句
  5. String sql = "delete from "+tableInfo.getTableName();
  6. //2.定义方法名
  7. String methodName = "deleteAll";
  8. //3.构建sqlSource对象,负责将sql传递到数据库
  9. SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
  10. //4.构建删除方法
  11. return this.addDeleteMappedStatement(mapperClass,methodName,sqlSource);
  12. }
  13. }

2、创建SQL自动注入器,继承AbstractSqlInjector

  1. @Component
  2. public class MySqlInject extends AbstractSqlInjector {
  3. //注入自定义方法集合
  4. @Override
  5. public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
  6. ArrayList<AbstractMethod> abstractMethods = new ArrayList<>();
  7. abstractMethods.add(new DeleteAll());
  8. return abstractMethods;
  9. }
  10. }

3、注销防止全表更新与删除插件

4、在Mapper接口中定义deleteAll方法

  1. public interface UserMapper extends BaseMapper<User> {
  2. void deleteAll();
  3. }

5、测试deleteAll方法,测试的时候不能使用AR模式,因为该方法不存在User类中,而是自定义的。

  1. @Test
  2. public void testDeleteAll() {
  3. userMapper.deleteAll();
  4. }

7.3 代码生成器

如果不想手动编写实体类等文件,MyBaitsPlus提供了代码生成器,它可以读取数据库的表信息,生成MyBaitsPlus代码供我们使用,之前我们学过MyBatis的代码生成器MyBatis Generator,这二者的区别是:

  • MBG基于xml文件配置的,MyBaitsPlus代码生成器是基于Java代码配置的。
  • MBG可生成实体类、Mapper接口、Mapper映射文件;MyBaitsPlus代码生成器可生成实体类、Mapper接口、Mapper映射文件、Service类、Controller类

 1、添加代码生成器所需的依赖

  1. <!-- MyBatisPlus代码生成器 -->
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-generator</artifactId>
  5. <version>3.5.1</version>
  6. </dependency>
  7. <!-- MyBatisPlus代码生成器需要的模板引擎 -->
  8. <dependency>
  9. <groupId>org.apache.velocity</groupId>
  10. <artifactId>velocity-engine-core</artifactId>
  11. <version>2.2</version>
  12. </dependency>

2、编写代码生成器

  1. package com.zj.Generator;
  2. import com.baomidou.mybatisplus.generator.FastAutoGenerator;
  3. import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
  4. public class MyGenerator {
  5. public static void main(String[] args) {
  6. FastAutoGenerator.create("jdbc:mysql:///mybatis", "root", "123456")
  7. // 全局配置
  8. .globalConfig(builder -> {
  9. builder.author("zhangjin") // 设置作者
  10. .commentDate("MM-dd") // 注释日期格式
  11. .outputDir(System.getProperty("user.dir") + "/src/main/java") // 指定输出目录
  12. .fileOverride(); //覆盖文件
  13. })
  14. // 包配置
  15. .packageConfig(builder -> {
  16. builder.parent("com.zj") // 包名前缀
  17. .entity("pojo") //实体类包名
  18. .mapper("mapper") //mapper接口包名
  19. .service("service") //service包名
  20. .controller("controller") //controller包名
  21. .xml("mapper"); //映射文件包名
  22. })
  23. // 策略配置
  24. .strategyConfig(builder -> {
  25. builder.addInclude("tb_user") // 设置需要生成的表名,可以有多个
  26. .addTablePrefix("tb_") // 设置表名前缀
  27. .entityBuilder() // 开始实体类配置
  28. .enableLombok() // 开启lombok模型
  29. .naming(NamingStrategy.underline_to_camel) //表名下划线转驼峰
  30. .columnNaming(NamingStrategy.underline_to_camel);//列名下划线转驼峰
  31. })
  32. .execute();
  33. }
  34. }

3、运行代码生成器即可生成代码

7.4 MybatisX生成代码

MybatisX是一款基于IDEA的快速开发插件,为效率而生。

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Marketplace,输入 mybatisx 搜索并安装。

1、在IDEA中连接数据库

2、如下操作可以根据数据库表生成Mybaits代码

 

 7.5 MybatisX生成映射配置、代码跳转

 1、在Mapper接口中编写方法

  1. public interface StudentMapper extends BaseMapper<Student> {
  2. List<Student> selectAllBySname(String sname);
  3. }

2、如下操作即可在映射文件中自动生成映射配置

 

代码跳转

点击Mapper接口或映射文件前的小鸟图案,即可快速在Mapper接口与映射文件间跳转

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/201380
推荐阅读
相关标签
  

闽ICP备14008679号