【2】MyBatisPlus DML操作

 字段映射与表名映射

问题一:当数据库表字段与编码属性设计不同步 如password与pwd 

  可以用mp的TableField里面的value属性即可关联

问题二:编码添加了数据库中不存在的字段属性 如“是否在线”一类的属性明显不需要放入数据库,但是在查询时候java需要在数据库中查,此时sql会报错

  同样用TableField里面的exist=false即可

问题三:采用默认查询开放了更多的字段查看权限 如想要查整张表,但是命令会把密码也查了,操作不安全

  TableField使用select属性设定它为false 则在查询过程中就不会被查询

 

问题四:表名与编码开发设计不同步  

  与问题一相似解,在类上面加一个TableName(“数据库表名”) 

TableId见下面

如果觉得每次都要在属性上面一行加@TableXX不方便 可以在yml里面统一设置

1、yml文件

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: 123456
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: 123456
    mapper-locations:
      classpath:mybatis/mapper/*.xml
  main:
    banner-mode: off

mybatis-plus:
  global-config:
    banner: false
    db-config:
      id-type: assign_id
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0
  configuration:
    #开启mp的日志(输出到控制台)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#      table-prefix:

//增

    @Test
    void testSave(){
        User user = new User();
        user.setName("熊");
        user.setPassword("123456");
        user.setAge(10);
        user.setTel("400012");
        userDao.insert(user);
    }

//删

    @Test
    void testDelete(){
        userDao.deleteById(1618522903760699393L);
    }

//改

 void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setName("大笨蛋");
        userDao.updateById(user);
    }

//查

//查单个
 @Test
    void testGetById(){
        User user = new User();
        user = userDao.selectById(2L);
        System.out.println(user);
    }

//查全部
 @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);

    }

引入lombok

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
@Data
@NoArgsConstructor
@AllArgsConstructorc


查询

按条件查

   void testGetAll() {
        //方式一:按条件查询对应的操作
        QueryWrapper wrapper = new QueryWrapper();
        //可以对wrapper进行设置来添加条件
        wrapper.lt("age",18);
        List<User> userList = userDao.selectList(wrapper);
        System.out.println(userList);

    }

为防止字段的手动输入可能出错检查不出,则有lamda表达式第二种查询方式


        //方式二:按条件查询对应的操作
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        //可以对wrapper进行设置来添加条件
        wrapper.lambda().lt(User::getAge,10);
        List<User> userList = userDao.selectList(wrapper);
        System.out.println(userList);

方法二另一种写法

   //方式三:按条件查询对应的操作
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //可以对wrapper进行设置来添加条件
        lqw.lt(User::getAge,10);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

前面是and查询 下面是或查询

        //小于10岁或者大于30岁
        lqw.lt(User::getAge,10).or().gt(User::getAge,30);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

封装查询条件

1、null值处理

 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //先判断第一个条件是否为true 如果为true 则连接当前条件
        lqw.lt(null!=uq.getAge(),User::getAge,uq.getAge2())
           .gt(null!=uq.getAge2(),User::getAge,uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

2、设置查询字段,没被选中的查出来为空

   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.select(User::getId,User::getName,User::getAge);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

下面写法相同结果 

       QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("id","name","age","tel");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

3、统计有多少数据

  QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*)");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);
 QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*) as 行数");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);

 

4、分组(查询投影)

 QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*) as 行数","tel");
        lqw.groupBy("tel");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);

 假如有条件或者函数不支持查 则回到mybatis在userdao类里@select 以前写的设类型去

5、等匹配

     LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

如果像上面的只用查一条数据则可以用专门的selectOne

  LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
        User user = userDao.selectOne(lqw);
        System.out.println(user);

实际登陆业务中要做Md5加密

 //范围查询用到的:lt,le,gt,ge,eq,between(  这么记带等号的le=lt+equal)

//between 前面放左区间

  LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.between(User::getAge,10,30);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

//like 模糊查询 like=% likeleft=%_ likeright=_%、

非全文检索版,要是查不能单独这样

  LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.like(User::getName,"J");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

 还有其它的符号 条件构造器 | MyBatis-Plus (baomidou.com)

可以先点“.”先写一下,不行再去查 

分页查询

select * from ?????? limit 1,2 (忽略前1条数据,获取后2条数据)

注意limit后面参数和pageNum,pageSize不是一个

 所以不用转换:

在原有基础上追加功能

配置拦截器,开启分页拦截器

@Configuration
public class Mpconfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor(){
        //定义MP的拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //在拦截器中添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

//分页查询
    @Test
    void testGetByPage(){
        IPage page = new Page(1,2);
        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());
    }

DML编程控制

增加的主键生成问题 如发票,外卖单号

TableId

设置id生成策略 

原来是生成id是乱的默认是雪花算法生成唯一的ID 下面代码就可以设置成数据库我们设置的自增策略

  @TableId(type = IdType.AUTO)

 None是没有指定,Input是自己指定Id否则报错(已设置ID不能为空)ASSIGN_ID 64位2进制

所以ID最好用bigInt来存

如果觉得每次都要在属性上面一行加@TableXX不方便 可以在yml里面统一设置

其它的比如表的前缀统一设置等等:

 多数据查询-删除与查询

多数据删除

1、利用集合实现

 @Test
    void testDelete(){
        List<Long>list=new ArrayList<>();
        list.add(1618963665719726084L);
        list.add(1618963665719726083L);
        list.add(1618963665719726082L);
        userDao.deleteBatchIds(list);
    }

多数据查询

     List<Long>list=new ArrayList<>();
        list.add(1L);
        list.add(2L);
        list.add(4L);
        userDao.selectBatchIds(list);

mp支持多数据删除和查询,只需要提供id

逻辑删除

为了避免多表删除造成业务无法查询统计,部分记录无法读取或者脏数据,最好在表中加一个字段来标明是否删除来代替真正从表中删除

此时再删除就不会删除表中的数据,且deleted字段的值由默认的0变成1

userDao.deleteById(1L)

此时mp接口删除实际上是执行update的sql语句操作, 并且在查询时候mp会在每次查询的条件中增加where deleted = 0 这个条件

在全局配置里设置逻辑操作的设定,使得不需要在实体类里加,只需要提供字段即可

 如果想要查询被删字段,则需要通过编写sql语句查询

乐观锁

 避免并发操作,2000个访问以下可以来尝试

加一个字段来保存

 这个@Version会使得每次更改都会让version+1

开个拦截器(乐观锁拦截器)

执行update操作,如果没有version则不会执行mp额外的sql语句操作

 

 加上version后

验证version是否为1,验证正确

 此时自动将version+1存入

以下两种方法同理,后者是自动获取了version

  @Test
    void testUpdate(){
//        User user = new User();
//        user.setId(3L);
//        user.setName("Jock666");
//        user.setVersion(1);
//        userDao.updateById(user);
        //1、先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(3L);
        //2.将要修改的属性逐一设置进去
        user.setName("Jock888");
        userDao.updateById(user);
    }

模拟A、B用户进行并发访问

        //模拟A、B用户秒杀
        User user = userDao.selectById(3L);  //version=3
        User user2 = userDao.selectById(3L); //version=3
        //先让B用户修改完成
        user2.setName("Jockbbb");
        userDao.updateById(user2);           //version->4

        //再让A用户进行修改
        user.setName("Jockaaa");
        userDao.updateById(user);           //version=3?条件会成立吗 不成立

结果为先修改的B用户设置的结果

总结乐观锁的步骤:

1、加个字段设置默认值

2、在实体类中设置属性

3、到MP拦截器中加一个拦截器

 

猜你喜欢

转载自blog.csdn.net/qq_53478650/article/details/128765662