经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MyBatis » 查看文章
Mybatis-Plus最优化持久层开发
来源:cnblogs  作者:二价亚铁  时间:2024/7/11 23:28:52  对本文有异议

Mybatis-plus:最优化持久层开发

一:Mybatis-plus快速入门:

1.1:简介:

  1. Mybatis-plus(简称MP)是一个Mybatis的增强工具,在mybatis的基础上只做增强不做改变; 提高效率;
  2. 自动生成单表的CRUD功能;
  3. 提供了丰富的条件拼接方式;
  4. 全自动ORM类型持久层框架;(不仅提供数据库操作的方法,还会提供sql语句的实现)

1.2:Mybatis-plus快速入门:

  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. 如果我们想要对User表的数据进行单表CRUD
  3. 我们使用Mybatis-plus之后:我们只需要:
  4. 1.创建mapper接口
  5. 2.继承 BaseMapper<User> (<>:要操作的表/实体类):我们就会拥有CRUD方法+CURDsql语句
  6. 注意:
  7. 继承的BaseMapper(它里面有单表的增删改查方法),就不用写mapper.xml文件了,
  8. 之后就可以直接使用mapper对象调用相应的CRUD方法即可进行数据库的操作了!!!

Mapper接口

  1. public interface UserMapper extends BaseMapper<User>{
  2. /*
  3. 原来Mybatis中:我们需要在mapper中自定义方法,然后在mapper.xml中使用sql实现方法
  4. 但是使用了Mybatis-plus之后,我们直接继承 “BaseMapper<>”:它里面有单表的增删改查各种方法以及实现
  5. 我们继承它以后就拥有了这些方法,就不用写mapper.xml文件了;
  6. */
  7. }

SpringBoot测试类

  1. @SpringBootTest //这个注解:就会自动完成ioc容器初始化,我们想要谁直接拿即可!!!!!!!!!!!!!!!!!
  2. public class SpringBootMybatisPlusTest {
  3. @Autowired
  4. private UserMapper userMapper; //拿到对象!!!
  5. public void test(){
  6. List<User> users = userMapper.selectList(null); //不传参数:直接写null:代表查询全部数据;
  7. 直接调用baseMapper接口中相应的方法即可
  8. }
  9. }

二:Mybatis-plus的核心功能

Mybatis-plus是如何增强的

  1. Mybatis-plus可以对三层架构的两层进行增强:
  2. 1.MapperC层:只要继承,就拥有了crud方法
  3. 2.Service层:继承

  1. 原理:!!!!!!!!
  2. mapper接口只要继承BaseMapper<实体类> 接口:
  3. 接下来我们就能使用通过mapper对象和BaseMapper接口中提供的CRUD方法来对 实体类表 进行操作;

2.1:基于Mapper接口的CRUD

  1. 1mapper接口
  2. 如果我们想要对User表的数据进行单表CRUD
  3. 我们使用Mybatis-plus之后:我们只需要:
  4. 1.创建mapper接口
  5. 2.继承 BaseMapper<User> (要操作的表/实体类):我们就会拥有CRUD方法+CURDsql语句
  6. */
  7. public interface Use rMapper extends BaseMapper<User> {
  8. //继承之后:下面就相当于有了方法
  9. }
  10. 2)测试类:
  11. @SpringBootTest
  12. public class MybatisPlusTest {
  13. @Autowired
  14. private UserMapper userMapper;
  15. //(1)insert:
  16. @Test
  17. public void test(){
  18. User user=new User();
  19. user.setName("kun");
  20. user.setAge(88);
  21. user.setEmail("xxx");
  22. //baseMapper提供的数据库insert方法
  23. int row = userMapper.insert(user);
  24. }
  25. //(2)delete:
  26. @Test
  27. public void test_delete(){
  28. //1.根据id删除:()内装值
  29. int rows = userMapper.deleteById(1687124323556002889L);
  30. //2.根据id删除:age=20 name=jack; ()内装条件: -->拼接条件
  31. Map param=new HashMap();
  32. param.put("age",20); //-->删除age=20 + name=jack
  33. param.put("name","jack");
  34. int i = userMapper.deleteByMap(param);
  35. System.out.println("i = " + i);
  36. //wrapper 条件封装对象,无限封装条件;
  37. //userMapper.delete(wrapper)
  38. }
  39. //(3)Update()
  40. @Test
  41. public void test_update(){
  42. //1.将主键userId为1的age改为30: ()内装值
  43. //update user set age=30 where id=1:就等同于下方
  44. User user=new User();
  45. user.setId(1L);
  46. user.setAge(30);
  47. int i = userMapper.updateById(user);
  48. //2.将所有人age改为20
  49. User user1=new User();
  50. user1.setAge(20); //
  51. int update = userMapper.update(user1, null);// null:代表没条件,该所有
  52. System.out.println("update = " + update);
  53. /*
  54. TODO:update:当属性为null时:代表不修改
  55. updateById():实体类的id必须有值
  56. update() :实体类可以没有id值
  57. */
  58. }
  59. //(4)select a:根据主键查询 b:根据主键集合查询
  60. public void test_select(){
  61. //a:根据id查询
  62. User user = userMapper.selectById(1);
  63. //b:根据集合查询:eg:根据ids查询
  64. List<Long> ids=new ArrayList<>();
  65. ids.add(1L);
  66. ids.add(2L);
  67. List<User> users = userMapper.selectBatchIds(ids); //selectBatchIds:批量ids
  68. System.out.println("users = " + users);
  69. }
  70. }

2.2:就Service接口的CRUD

service接口继承:

2.3:分页查询实现:

  1. Mybatis-plus实现分页查询:!!!!
  2. 使用步骤:
  3. 1.导入分页插件
  4. 2.使用分页查询

  1. -04
  2. @SpringBootApplication
  3. @MapperScan("com.atguigu.mapper")
  4. /*
  5. 启动类也是配置类:所以我们可以声明带@Bean的方法
  6. 1.配置一个分页的插件:Mybatis-plus提供的,我们直接加进来使用就行了;
  7. 在配置类/启动类:中使用@Bean返回
  8. */
  9. public class Main {
  10. public static void main(String[] args) {
  11. SpringApplication.run(Main.class, args);
  12. }
  13. @Bean
  14. //1.将Mybatis-plus插件加到ioc容器
  15. public MybatisPlusInterceptor plusInterceptor(){
  16. //a:是所有Mybatis-plus的插件集合:我们想要使用任何插件都可以加到这个集合中去;eg:我们可以将分页插件加到里面;
  17. MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
  18. //b:加入分页插件:
  19. mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  20. //指定数据库
  21. return mybatisPlusInterceptor;
  22. }
  23. }
  24. /*
  25. 测试类:
  26. 2.之后就可以使用分页插件了:
  27. */
  28. @SpringBootTest
  29. public class MybatisPlusTest {
  30. @Autowired
  31. private UserMapper userMapper; //注入UserMapper对象:进行数据库操作
  32. @Test
  33. public void testPage(){
  34. //a:创建Page对象: 参数解释:(参数1:页码, 参数2:页容量)
  35. Page<User> page=new Page<>(1,3);
  36. userMapper.selectPage(page,null); //需要放入Page对象
  37. //最后分页的结果也会被封装到page里面:-->所以直接通过page对象获取结果即可
  38. long pages = page.getPages();
  39. long current = page.getCurrent(); //获取当前页码、
  40. List<User> records = page.getRecords(); //获取当前页数据
  41. long total = page.getTotal();//获取总条数
  42. }
  43. }

自定义mapper方法使用分页

  1. 上面:我们是使用Mybatis提供的方法: userMapper.selectPage(page,null);
  2. 如果我们自定义的mapper方法想要使用分页查询:
  3. 1.mapper接口中定义方法:
  4. 自定义方法想要分页:在第一个参数加一个IPage对象,返回值也是IPage
  5. 2.mapper文件中实现:使用sql语句实现:不要加limit和;
  6. 3.测试

  1. 1.
  2. public interface UserMapper extends BaseMapper<User> {
  3. //继承BaseMapper接口:里面有单表的方法
  4. /*
  5. 演示:自定义mapper方法实现分页:
  6. eg:查询
  7. */
  8. //1.在mapper接口中定义抽象方法:但是:方法的第一个参数:要传一个IPage,返回值要是IPage,里面写查询集合的泛型即可
  9. IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
  10. }
  11. 2.
  12. <!--2.使用sql语句实现UserMapper接口的方法:不用在最后加limit,!-->
  13. <select id="queryByAge" resultType="com.atguigu.pojo.User"> <!--resultType:泛型-->
  14. select * from user where age>#{age}
  15. </select>
  16. 3.
  17. /*
  18. 3.测试自定义方法分页
  19. */
  20. public void test_MyPage(){
  21. //a:传一个分页插件的值:
  22. Page<User> page=new Page<>(1,3);
  23. //b.
  24. userMapper.queryByAge(page,1);
  25. //c:
  26. //最后分页的结果也会被封装到page里面:-->所以直接通过page对象获取结果即可
  27. long pages = page.getPages();
  28. long current = page.getCurrent(); //获取当前页码、
  29. List<User> records = page.getRecords(); //获取当前页数据
  30. long total = page.getTotal();//获取总条数
  31. System.out.println("total:"+total);
  32. }
  33. }

2.4:条件构造器使用:

2.4.1条件构造器的作用:

  1. warpper对象:动态进行 条件的拼接;
  2. 就相当于在sql语句后面加条件,只是使用java代码的格式;
  3. ---->:就不用在mapper.xml文件中使用sql语句实现了,直接使用java代码来代替sql语句;!!!!!!!!

warpper对象:动态进行 条件的拼接;
就相当于在sql语句后面加条件,只是使用java代码的格式;
---->:就不用在mapper.xml文件中使用sql语句实现了,直接使用java代码来代替sql语句;!!!!!!!!

2.4.2条件构造器的类结构:

  1. 一般使用:
  2. 第一种: UpdateWrapper(修改)、QueryWrapper(删除、查询、修改)
  3. 第二种: LambdaUpdateWrapper(修改)、 LambdaQueryWrapper(删除、查询、修改)
  • (1)第一种:基于queryWrapper组装条件:增/删/改

    1. 使用方法:
    2. 1.mapper接口中定义方法,并继承base接口(提供了各种方法的实现)
    3. 2.直接使用java代码实现:不需要在mapper.xml文件中实现了
    4. //a:创建QueryWrapper
    5. QueryWrapper<实体类>queryWrapper=new QueryWrapper<>();
    6. //b:条件拼接:调用queryWrapper方法
    7. //c:使用mappper对象:调用CRUD方法,传入对象即可

  1. 1.mapper接口:
  2. public interface UserMapper extends BaseMapper<User> {
  3. //继承BaseMapper接口:里面有单表的方法
  4. /*
  5. 演示:自定义mapper方法实现分页:
  6. eg:查询
  7. */
  8. //1.在mapper接口中定义抽象方法:但是:方法的第一个参数:要传一个IPage,返回值要是IPage,里面写查询集合的泛型即可
  9. IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
  10. }
  11. 2.
  12. /*
  13. 演示条件构造器使用:进行条件的动态拼接:
  14. (1)QueryWrapper测试:
  15. */
  16. @SpringBootTest
  17. public class MybatisPlusQueryWrapper {
  18. @Autowired
  19. private UserMapper userMapper; //拿到对象:操作数据库
  20. @Test
  21. public void test_01(){
  22. //查询用户名包含 a,age在20到30之间的,且邮箱不为空的用户;
  23. //分析:查询:返回的是集合List-->selectList
  24. //a:创建一个QueryWrapper集合:相当于容器来装条件
  25. QueryWrapper<User> queryWrapper=new QueryWrapper<>();
  26. //b:之后sql语句的条件:直接使用queryWrapper动态调用wrapper的方法来完成动态拼接;
  27. queryWrapper.like("name","a"); //条件1:name种包含a的
  28. queryWrapper.between("age",20,30); //条件2:age在20-30之间
  29. queryWrapper.isNotNull("email"); //第三个条件:email不为null
  30. List<User> users = userMapper.selectList(queryWrapper); ----->:因为继承了base接口,所以单表直接调用方法即可!
  31. //queryWrapper就是sql条件,将它·传进去!!!
  32. //之后这个就会变成sql语句; !!!!!!!!!!!
  33. //就相当于:select * from user where name(like %a% and age>=20 and age<=30 and email is not null)
  34. /*
  35. !!!一个个调用麻烦,可以使用链式调用:!!!!
  36. queryWrapper.like("name","a").between("age",20,30).isNotNull("email");
  37. */
  38. }
  39. }

(2)queryWrapper实战使用:

  1. @SpringBootTest
  2. public class MybatisPlusQueryWrapper {
  3. @Autowired
  4. private UserMapper userMapper; //拿到对象:操作数据库按照年龄降序查询用户,如果年龄age相同则按id升序排列
  5. //(2)queryWrapper:按年龄降序查询用户,如果年龄相同则按id升序排列
  6. @Test
  7. public void test_02(){
  8. //a:创建QueryMapper集合:装条件
  9. QueryWrapper<User> queryWrapper=new QueryWrapper<>();
  10. //b:使用条件构造器进行条件的拼接:
  11. queryWrapper.orderByDesc("age").orderByAsc("id");
  12. //a:条件1:age降序排列; b:条件2:id增序
  13. //c:放到queryWrapper中,进行条件拼接; ==order by age desc,id asc
  14. List<User> users = userMapper.selectList(queryWrapper);
  15. }
  16. //(3)删除email为null的用户
  17. @Test
  18. public void test_03(){
  19. //a:
  20. QueryWrapper<User> queryWrapper=new QueryWrapper<>();
  21. //b:
  22. queryWrapper.isNotNull("email");
  23. //c:
  24. int delete = userMapper.delete(queryWrapper);
  25. }
  26. //(4):将age>20且用户名中包含a或email为null的用户信息修改:
  27. //分析:修改:--update:所以usermapper调用update方法
  28. :相应的条件:age>20... 使用queryWrapper封装,然后作为条件放入update方法形参中;!!!!!
  29. @Test
  30. public void test_04(){
  31. //a:
  32. QueryWrapper<User> queryWrapper=new QueryWrapper<>();
  33. //b:添加条件:
  34. queryWrapper.gt("age",20).like("name","a") ---------->B:相当于:where .......
  35. .or().isNotNull("email");
  36. //1.条件:age>20 name包含a,--->:条件直接调用时:默认自动使用and进行拼接;!!!!!
  37. //queryWrapper.gt("age",20).like("name","a") == where age>20 and ..
  38. //2.如果想要在条件之后追加or关键字:可以使用: “or().条件”;
  39. //c:创建User对象,进行update修改
  40. User user=new User();
  41. user.setAge(88); ----->A:相当于update user set name="" age=
  42. user.setEmail("hehe");
  43. //d:如果要修改:第一位传入要修改的对象
  44. userMapper.update(user, queryWrapper); //放入对象 + queryWrapper
  45. }
  46. //(5):查询用户信息的name和age字段; --->指定列查询!!!
  47. //select name,age from t_user where id>1;
  48. public void test_05() {
  49. //a:
  50. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  51. //b:条件拼接:
  52. queryWrapper.gt("age",1);
  53. //!!!查询时:默认是查询全部???!!!!!,但可以使用select指定
  54. queryWrapper.select("name","age");
  55. userMapper.selectList(queryWrapper);
  56. }
  57. //(6)前端传入两个参数,name,age:---->:动态条件组织判断!!!!
  58. // 只要name不为null,就作为条件 来查询符合的
  59. //只要age>18作为条件,就作为条件 来查询符合的
  60. @Test
  61. public void test_06(){
  62. String name="xx";
  63. Integer age=19;
  64. //a:
  65. QueryWrapper<User>queryWrapper=new QueryWrapper<>();
  66. //b:进行条件拼接:
  67. //b.1:如果name!=null,就使用queryWrapper进行条件拼接
  68. if(StringUtils.isNotBlank(name)){ //调用isNotBlank进行判断
  69. //动态条件判断:如果name不为null,就进行条件的拼接
  70. queryWrapper.eq("name",name); //使用queryWrapper进行拼接
  71. }
  72. //b.2:如果age>18 进行动态拼接:
  73. if (age>18 && age!=null){
  74. queryWrapper.eq("age",age);
  75. }
  76. userMapper.selectList(queryWrapper);
  77. /*
  78. 注意:!!!!!!!!!!!!!!!!
  79. Wrapper每个方法都有:一个boolean类型的condition,允许我们第一个参数放一个比较表达式,
  80. :如果condition为true-->整个条件为true,就执行下面代码
  81. :如果condition为false-->整个条件为false,就失效,不执行下面代码
  82. -->condition里面有动态判断,就不用我们在外部写判断了
  83. eg:
  84. */
  85. queryWrapper.eq(StringUtils.isNotBlank(name),"name",name);
  86. queryWrapper.eq(age>18 && age!=null,"age",age);
  87. }

updateWrapper:改

进行修改时:使用updateWrapper:!!!!

  1. //a:
  2. UpdateWrapper<User> queryWrapper=new UpdateWrapper<>();
  3. //b:
  4. queryWrapper.gt("age",20).like("name","a").isNotNull("email")
  5. .set("email",null).set("age",100);
  6. //c:
  7. userMapper.update(null,queryWrapper);

在修改时updateWrapper和queryWrapper区别:

  1. (参数1:条件; 参数2:修改的数据)
  2. queryWrapper修改:参数1只能放条件,且列名不能为null
  3. updateWrapper修改:参数1可以放条件, 且列名可以设置为null;
  4. 且可以直接调用set方法进行修改
  • (2)第二种:

    1. 和第一种用法一样,只是对第一种的增强
    2. eg:
    3. Lambda:避免列写错的机制:传入的列名可以是” 方法引用的表达式 “:类名::getName -->相当于找方法对应的列名

LambdaQueryWrapper:增/删/改

  1. eg:
  2. 查询用户名包含 a like,年龄在20-30之间,并且邮箱不为null的用户信息;
  3. LambdaQueryWrapper<User>lambdaQueryWrapper=new LambdaQueryWrapper<>();
  4. //即只要将原来的列名,变为Lambda方法引用即可,其余不变!!!!!!!!!!
  5. lambdaQueryWrapper.like(User::getName,"a").between(User::getAge,20,30).isNotNull(User::getEmail);
  6. userMapper.selectList(queryWrapper);

LambdaupdateWrapper:改

  1. eg
  2. LambdaUpdateWrapper<User>lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
  3. //即只要将原来的列名,变为Lambda方法引用即可,其余不变!!!!!!!!!!
  4. lambdaUpdateWrapper.gt(User::getAge,20).like(User::getName,"a").isNotNull(User::getEmail)
  5. .set(User::getEmail,null).set(User::getAge,100);
  6. userMapper.update(null,lambdaUpdateWrapper);

(3)总结:

  1. Wrapper:里面:完成了动态条件封装
  2. 最终推荐使用Lambda;(不用写列名,只需类名::方法即可)
  3. 如果复杂的sqlqg:嵌套、子查询 不会使用Wrapper怎么办:
  4. 我们仍然使用原来的:定义mapper
  5. 如果为单表的话:直接使用mapper对象调用CRUD方法即可;
  6. 如果为多表的话:在mapper.xml文件中实现;

2.5Mybatis-plus核心注解的使用:

注解的作用:指定实体类和表之间的映射;

1.@TableName

  1. 作用:指定数据库表名;(当【BaseMapper<实体类>】 实体类名 数据库表名不同时);
  2. 使用:@TableName("数据库表名")
  3. a:位置:加到实体类上
  4. b:可以不加,不加的话默认使用实体类的名字作为 表名! 忽略大小写;
  5. eg:BaseMapper<User>:默认将实体类名:User,作为表名 来进行操作;
  6. c:使用@TableName注解场景:
  7. 当数据库的表名和实体类名称不同时(忽略大小写),需要使用@TableName来指定 表名:
  8. eg:数据库名:t_user; 实体类名:User
  9. 两个名称不同,此时我们需要在实体类上方使用: @TableName("t_user")“ 来指定表名;
  10. d: 如果表名命名规范:eg:都以 "t_"开头,且除了”t_“以外,实体类名=表名
  11. 我们可以将前缀统一提取到配置文件中(application.yml),这样就不需要每个实体类都加@TableName注解来指定表名了
  12. 它会自动查找相应的表;
  13. mybatis-plus:
  14. global-config:
  15. db-config:
  16. table-prefix: t_ #表名前缀;
  17. #加了这个之后,我们就不需要在每个实体类加@TableName注解了,它就会自己根据前缀"t_"进行查找;
  18. #前提:数据库的表都是以 “t_”开头的

2.@TableId:

  1. 作用:描述主键的一些特性;
  2. eg: value:指定表主键名; type:设置主键type策略
  3. 使用:在实体类的主键属性上:+@TableId(value="主键列名",type="主键策略");
  4. b:位置:加到实体类的主键属性上
  5. c:使用@TableId的场景:
  6. 场景1
  7. 主键的列名 实体类的属性名 不一致时,使用这个注解来指定表的列名;!!!
  8. eg: 1:如果 实体类属性名:id; 数据库主键列名:x_id; --->两个名称不一样,我们可以在实体类主键的属性上方加
  9. @TableId(value="x_id")
  10. 场景2
  11. 设置表主键增长:
  12. type主键策略:

type增长策略:

  1. @SpringBootTest
  2. public class MybatisPlusTableIdTest {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Test
  6. public void test_01(){
  7. //以插入数据举例:
  8. User user=new User();
  9. user.setName("坤坤");
  10. user.setAge(20);
  11. user.setEmail("xxx@qq.com");
  12. //插入的时候:主键id不要赋值; 主键自增长 或者 type策略 进行赋值!!!!!!!!!!!!
  13. /*
  14. 1.默认主键的type(策略)是:雪花算法;--->:它会生成一个不重复的long类型的数字; eg:123456789
  15. 雪花算法:
  16. a:要求数据库主键是 bigint / varchar(64) 类型; -->:eg:varchar(64)/bigint money;!!!
  17. b:要求实体类相应属性:使用Long/String接值(int接不到) -->:eg:Long/String money;!!!
  18. c:随机生成一个数字,给予主键值(不重复)
  19. 2.但我们想要把主键type(策略)变成auto自增长,
  20. 方式1:直接在实体类的主键上方加:@TableId(type= IdType.AUTO); 前提是mysql数据库必须设置了主键自增长(auto_increment)
  21. auto:
  22. a:要求mysql数据库的 表主键 必须设置了 自增长
  23. b:插入数据就是自增长了
  24. 方式2:全局设置主键自增长策略:如果每个表都设置为自增长(auto),在配置文件(application.yml)中配置
  25. */
  26. userMapper.insert(user); //之间调用BaseMapper中的insert方法;
  27. }
  28. }
  29. User视图类:
  30. public class User(){
  31. @TableId(type = IdType.AUTO)
  32. private Long id;
  33. }

3.@TableFiled

  1. 作用:描述非主键字段
  2. 使用:在实体类的非主键字段上:+@TableFiled(value="",exist="")
  3. a:使用场景1value="" (不是必须指定的,String类型)
  4. :当实体类的属性名 列名 不同的时候 使用@TableFiled指定数据库表名;
  5. 使用场景2esist=ture/false (默认为true
  6. eg@TableFiled(value="name",exist=false):
  7. private String name;
  8. -->:false代表:认为name没有数据库对应的列,因此在查询等时候不会对他进行操作;

三:Mybatis-plus高级扩展

3.1逻辑删除实现:

  1. (1)逻辑删除概念:
  2. 逻辑删除:是 "假删除数据":是将想要删除数据的状态修改为 "被删除状态",但是数据并没有消失,之后在查询时,查询没有 删除状态 的数据,也是一种删除;
  3. 物理删除:delete from:删除之后就没有了相应的数据;
  4. (2)逻辑删除的实现:
  5. 方式1:单个表逻辑删除的实现:
  6. a:在数据库表中 插入一个逻辑删除字段(int类型,有1/0状态字段!):
  7. alert table User add deleted int default 1/0; -->: 1/0:逻辑删除的状态字段:1代表:逻辑删除; 0代表:未逻辑删 除;!!!!
  8. b:在实体类的对应属性上加:@TableLogic
  9. eg
  10. @TableLogic //代表这个属性对应的列是 :逻辑删除状态字段
  11. //当我们删除数据时候,自动变成修改此列的属性值(即将deleted变为1); 默认:0是未删除,1是删除
  12. //当我们查询数据时候:默认只查询 deleted=0 的列的数据
  13. private Integer deleted;
  14. 方式2:多个表逻辑删除的实现(全局指定):
  15. a:同上
  16. b:在配置文件(application.yml)中:配置
  17. mybatis-plus:
  18. global-config:
  19. db-config:
  20. logic-delete-field: deleted # 全局逻辑删除的实体属性名
  21. 注意:这种就不需要在类的属性名上 + @TableLogic
  22. 但是仍然需要在实体类中创建一个和列名deleted 对应的属性名;

代码演示:

  1. 以单个表实现逻辑删除为例:
  2. @TableLogic
  3. private Integer deleted;
  4. @SpringBootTest
  5. public class MybatisPlusTableLogicTest {
  6. @Autowired
  7. private UserMapper userMapper;
  8. public void test_01(){
  9. //a:之前是物理删除:delete from user where id=5;
  10. //b:现在:逻辑删除:相当于:update user set deleted=1 where id=5
  11. userMapper.deleteById(5);
  12. //eg:
  13. userMapper.selectList(null); -->之后在查询时:就只会查询deleted=0的了:!!!!!(自动在条件位置加上where deleted=0
  14. }

3.2乐观锁的实现

  1. 1.乐观锁 和悲观锁 都是在 并发编程 中用于处理并发访问和资源竞争的两种不同机制;
  2. 2.(1)悲观锁:
  3. 同步锁/互斥锁:线程在访问共享资源之前会获取到锁,在数据访问时只允许一个线程访问资源,只有当前线程访问完成只后,才会释放锁,让其它线程继续操作资源;
  4. (2)乐观锁:不需要提前加锁,而是在数据更新阶段进行检测
  5. 乐观锁和悲观锁是两种解决并发数据问题的思路,不是技术!!
  6. 3.具体的技术和方案:
  7. 1.乐观锁实现方案和技术
  8. 版本号/时间戳
  9. CAS
  10. 无锁数据结构
  11. 2.悲观锁的实现方案和技术
  12. 锁机制
  13. 数据库锁
  14. 信号量
  15. 4. 现在主要学习如何使用乐观锁(版本号)解决并发问题!!!!!!!
  16. (1)版本号:解决数据并发更新出现错误数据的问题;--->保证数据一致性;
  17. (2)乐观锁技术的实现流程:
  18. a:每条数据添加一个版本号字段version
  19. b:取出记录时,获取当前version
  20. c:更新时,检查获取版本号是不是数据库当前最新版本号
  21. d:如果是(代表没人修改过数据),执行更新:set数据更新,version=version+1
  22. e:如果不是(证明已经修改过了),更新失败
  23. 5.使用mybatis-plus数据使用乐观锁
  24. 步骤:
  25. 1.数据库插入一个version字段:alert table user add version int default 1 int类型 乐观锁字段)
  26. 2 实体类创建相应的属性: private Integer version; + 在属性上方使用@Version注解
  27. 3.添加拦截器(添加版本号更新插件)
  28. 之后在更新的时候就会检查版本,检查数据错误的问题;

乐观锁测试:

  1. 1.
  2. alter table user add version int default 1; #int 类型 乐观锁字段
  3. 2.
  4. public class User {
  5. @Version
  6. private Integer version; //版本号字段
  7. }
  8. //注意:之后在数据修改时都会检查乐观锁;
  9. 3.在配置类/Main类中加入拦截器
  10. public class Main {
  11. public static void main(String[] args) {
  12. SpringApplication.run(Main.class, args);
  13. }
  14. @Bean
  15. public MybatisPlusInterceptor plusInterceptor(){
  16. //拦截器2:乐观锁【版本号插件】 mybatis-plus在每次更新时候,每次帮我们对比版本号字段和增加版本号+1
  17. mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  18. return mybatisPlusInterceptor;
  19. }
  20. 4.
  21. /*
  22. 测试乐观锁实现
  23. */
  24. @SpringBootTest
  25. public class MybatisPlusVersionTest {
  26. private UserMapper userMapper;
  27. @Test
  28. public void testById(){
  29. //步骤1:先查询,再更新 获取version数据
  30. //同时查询两条,但是version唯一,最后更新的失败、
  31. User user=new User(); //user 版本号为:1
  32. User user1=new User(); //user1 版本号为:1
  33. user.setAge(20);
  34. user.setAge(30);
  35. userMapper.updateById(user); //20-->:此时数据库的version ->2
  36. //乐观锁生效:失败
  37. userMapper.updateById(user1);
  38. //因为user1的版本号为1,但是数据库的版本号为2,证明不是最新数据 -->1!=2,乐观锁生效,更新失败
  39. //所以最终age为:20
  40. }
  41. }

3.3防止全表更新和删除

  1. 在开发中一般不会出现全表的更新/删除:
  2. Mybatis-plus提供一种防御插件:一旦检测到是全表的update/delete:就会报异常;
  3. 实现方法:添加防止全表更新和删除的拦截器:

代码测试:

  1. 1.加入拦截器/插件:
  2. public class Main {
  3. public static void main(String[] args) {
  4. SpringApplication.run(Main.class, args);
  5. }
  6. @Bean
  7. public MybatisPlusInterceptor plusInterceptor(){
  8. //拦截器3:防止全表删除和更新的拦截器
  9. mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
  10. return mybatisPlusInterceptor;
  11. }
  12. 2.测试类中:
  13. public void test(){
  14. @Au..
  15. private UserMapper userMapper; //拿到mapper对象,进行数据库操作!!!;
  16. //a:全表删除!
  17. mapper.delete(null); ----->:null,代表没有写条件,代表:全表删除;
  18. //b:全表更新:
  19. mapper.update(null); ------>: null,代表没有条件,代表全表更新!
  20. ----------->:之后就会抛出异常:不允许全表delete/update!!!!!!!
  21. }

四:Mybatis-Plus代码生成器(MybatisX插件)!!!!!!!!!!!!!

  1. 学习目标:
  2. 1.如何使用MybatisX插件: 逆向工程 生成Mybatis-Plus代码;
  3. //逆向工程:根据表自动生成实体类、mapper、service;!!!!!!!!!!!!!!!!!!!!!!
  4. 2. 使用MybatisX插件 动态生成自定义的sql语句

4.1Mybatis插件逆向工程

  1. //逆向工程:根据表自动生成实体类、mapper、service;!!!!!!!!!!!!!!!!!!!!!!
  2. 步骤:
  3. 连接数据库;
  4. .....

4.2Mybatis-plus快速生成单表CRUD代码(自定义sql)!!!!!!!!

  1. 如果我们需要自己定义一些sql语句:
  2. eg:批量查询、根据id查询......
  3. //步骤:
  4. 1.直接在mapper接口中书写相应的 方法名 //按照mybatisX的方法命名规则)
  5. eg:批量插入:insertBatch
  6. 根据条件查询:selectByNameAndAgeAndAge
  7. 2.然后鼠标放在方法名上,点击MybatisX
  8. --->MybatisX 就会在mapper接口自动写好 mapper.xml文件中自动生成sql语句!!!!!!!!
  9. //之后有关单表的CRUD我们就不需要自己写了!!!!!!!!!!
  10. //我们可以看mybatisX的官方文档:介绍了如何写

原文链接:https://www.cnblogs.com/xw-01/p/18297351

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号