首页 > 其他分享 >MyBatisPlus

MyBatisPlus

时间:2022-10-24 08:46:36浏览次数:121  
标签:MyBatisPlus userDao wrapper User new id user

一、MyBatisPlus简介

  1. 概念

    MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率。

  2. 开发方式
    基于MyBatis使用MyBatisPlus
    基于Spring使用MyBatisPlus
    基于SpringBoot使用MyBatisPlus

  3. SpringBoot整合MyBatis开发过程(复习)

    ①创建SpringBoot工程
    ②勾选配置使用的技术:SQL —— MyBatisFramework和MySQLDriver
    ③设置dataSource相关属性(JDBC参数)

    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
        username: root
        password: 123
    

    ④定义数据层接口映射配置

    @Mapper
    public interface UserDao {
        @Select("select * from user where id=#{id}")
        public User getById(Long id);
    }
    
  4. MyBatisPlus项目

    ①创建新模块,选择SpringBoot初始化,并配置模块相关基础信息

    ②选择当前模块需要使用的技术集(仅保留JDBC):SQL —— MySQLDriver,不要其他的

    注意:由于mp并未被收录到idea的系统内置配置,无法直接选择加入

    ③手动添加mp起步依赖和数据源依赖

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.6</version>
    </dependency><dependency>
    

    ④设置Jdbc参数(application.yml)

    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
        username: root
        password: 123
    

    ⑤制作实体类与表结构(类名与表名对应,属性名与字段名对应)

    public class User {
        private int id;
        private String username;
        private String password;
    }
    

    ⑥定义数据接口,继承BaseMapper<User>

    @Mapper
    @Repository
    public interface UserDao extends BaseMapper<User> {}
    

    ⑦测试类中注入dao接口,测试功能

    @SpringBootTest
    class SpringbootMpApplicationTests {
        @Autowired
        private UserDao userDao;
    
        @Test
        void testGetAll() {
            List<User> list = userDao.selectList(null);
            System.out.println(list);
        }
    }
    
  5. MyBatisPlus介绍

  6. 特性

    • 无侵入:只做增强不做改变,不会对现有工程产生影响
    • 强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD 操作
    • 支持 Lambda:编写查询条件无需担心字段写错
    • 支持主键自动生成
    • 内置分页插件

二、标准CRUD制作

  1. 标准数据层CRUD功能
功能 自定义接口
新增 boolean save(T t)
删除 boolean delete(int id)
修改 boolean update(T t)
根据id查询 T getById(int id)
查询全部 List getAll()
分页查询 PageInfo getAll(int page, int size)
按条件查询 List getAll(Condition condition)
  1. 功能演示

    @SpringBootTest
    class SpringbootMpApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void testGetAll() {
            List<User> list = userDao.selectList(null);
            System.out.println(list);
        }
    
        @Test
        void testAdd() {
            User user = new User();
            user.setUsername("中国飞");
            user.setPassword("123");
            userDao.insert(user);
        }
    
        @Test
        void testDel() {
            userDao.deleteById("7");
        }
        @Test
        void testUpdate() {
            User user = new User();
            user.setId(5);
            user.setUsername("中国飞2");
            user.setPassword("123");
            userDao.updateById(user);
        }
    
        @Test
        void testGetById() {
            User user = userDao.selectById(3);
            System.out.println(user);
        }
    }
    
  2. 快速简化实体——lombok

    ①添加坐标

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    

    ②修改实体

    //@Setter
    //@Getter
    //@ToString
    //@NoArgsConstructor
    //@AllArgsConstructor
    //@EqualsAndHashCode
    
    @Data //包含了以上所有注解,不包含构造方法
    public class User {
        private int id;
        private String username;
        private String password;
    }
    

    ③注意

    问题:使用get等方法的时候报红,但是程序可以运行;

    原因:IDEA需要安装lombok插件

    解决:搜索安装插件即可,搜索不到直接本地安装,[下载地址](Versions: Lombok - IntelliJ IDEA & Android Studio Plugin | Marketplace (jetbrains.com))

三、标准分页功能制作

  1. 使用selectPage即可S

    @SpringBootTest
    class SpringbootMpApplicationTests {
    
        @Autowired
        private UserDao userDao;
        
        @Test
        void testGetByPage() {
            IPage ipage = new Page(1,3);
            userDao.selectPage(ipage,null);
            System.out.println("当前页码值:"+ipage.getCurrent());
            System.out.println("当前显示数:"+ipage.getSize());
            System.out.println("一共多少页:"+ipage.getPages());
            System.out.println("一共多少条数据:"+ipage.getTotal());
            System.out.println("数据:"+ipage.getRecords());
        }
    }
    

    问题:以上打印数据,没有实现分页功能

    当前页码值:1
    当前显示数:3
    一共多少页:0
    一共多少条数据:0
    数据:[User(id=1, username=zhangsan, password=123), User(id=2, username=lisi, password=123), User(id=3, username=wangwu, password=123), User(id=4, username=zhaoliu, password=123), User(id=5, username=中国飞3, password=123456), User(id=6, username=大飞, password=567)]
    
  2. 解决:添加分页拦截器

    @Configuration
    public class MPConfig {
        @Bean
        public MybatisPlusInterceptor myMPIntercepter(){
            //1. 定义mp拦截器
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
    
            //2. 添加具体的拦截器
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            
            return mybatisPlusInterceptor;
        }
    }
    

    运行结果——实现了真正的分页

    当前页码值:1
    当前显示数:3
    一共多少页:2
    一共多少条数据:6
    数据:[User(id=1, username=zhangsan, password=123), User(id=2, username=lisi, password=123), User(id=3, username=wangwu, password=123)]
    
  3. 开启mp日志——application.yaml

    # 开启mp的日志
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    

    运行结果:

    Creating a new SqlSession
    SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c15e8c7] was not registered for synchronization because synchronization is not active
    2022-10-22 21:32:20.669  INFO 27572 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
    JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@60783105] will not be managed by Spring
    ==>  Preparing: SELECT COUNT(*) FROM user
    ==> Parameters: 
    <==    Columns: COUNT(*)
    <==        Row: 6
    <==      Total: 1
    ==>  Preparing: SELECT id,username,password FROM user LIMIT ?
    ==> Parameters: 3(Long)
    <==    Columns: id, username, password
    <==        Row: 1, zhangsan, 123
    <==        Row: 2, lisi, 123
    <==        Row: 3, wangwu, 123
    <==      Total: 3
    Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c15e8c7]
    当前页码值:1
    当前显示数:3
    一共多少页:2
    一共多少条数据:6
    数据:[User(id=1, username=zhangsan, password=123), User(id=2, username=lisi, password=123), User(id=3, username=wangwu, password=123)]
    

四、DQL编程控制

(一)条件查询一

  1. MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合

  2. 小技巧

    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
        username: root
        password: 123
      # 去掉springboot的banner
      main:
        banner-mode: off
    
    # 开启mp的日志
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      # 去掉info debug等信息
      global-config:
        banner: false
    
  3. 条件查询

    @Test
    void testGetCondition() {
        //方式一:按条件查询——容易出错
        //QueryWrapper wrapper = new QueryWrapper();
        //wrapper.lt("age",18);
    
        //方式二:Lambda格式按条件查询
        //QueryWrapper<User> wrapper = new QueryWrapper<>();
        //wrapper.lambda().lt(User::getAge,18);
    
        //方式三:Lambda格式查询
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //14-50岁之间
        //wrapper.lt(User::getAge,50).gt(User::getAge,14);
        //小于14或大于50
        wrapper.lt(User::getAge,14).or().gt(User::getAge,50);
    
        List<User> list = userDao.selectList(wrapper);
        for (User user : list) {
            System.out.println(user);
        }
    }
    

    条件查询null判断:

    //创建一个查询的实体类
    public class UserQuery extends User {
        private Integer age2;
    }
    
    @Test
    void testGetByNull() {
        //模拟页面传递过来的查询数据
        UserQuery userQuery = new UserQuery();
        userQuery.setAge(14);
    	//userQuery.setAge2(50);
    
        //null判断
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //先判断第一个参数是否为ture,如果为ture连接当前条件
        wrapper.lt(null != userQuery.getAge2(), User::getAge, userQuery.getAge2())
               .gt(null!=userQuery.getAge(),User::getAge, userQuery.getAge());
        List<User> userList = userDao.selectList(wrapper);
        for (User user : userList) {
            System.out.println(user);
        }
    }
    

(二)查询投影——设置查询结果的样子

  1. 查询投影

    @Test
    void testGetByShowFiled() {
        //查询投影Lambda方式——查到的结果只看哪些字段,其他字段为空
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getUsername,User::getPassword);
    
        //查询投影传统方式——查到的结果只看哪些字段,其他字段为空
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("username");
        List<User> userList = userDao.selectList(wrapper);
        for (User user : userList) {
            System.out.println(user);
        }
    
        //查询投影——查询总个数
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("count(*) as 总数,password");
        //查询投影——分组
        wrapper.groupBy("password");
    
        List<Map<String, Object>> maps = userDao.selectMaps(wrapper);
        System.out.println(maps);
    }
    

(三)条件查询二

  1. 常见条件

    范围匹配(> 、 = 、between)
    模糊匹配(like)
    空判定(null)
    包含性匹配(in)
    分组(group)
    排序(order)

  2. 案例

    @Test
    void testGetByCondition() {
        //条件查询——等于=查询一个
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,"lisi");
        wrapper.eq(User::getPassword,"123");
    
        User user = userDao.selectOne(wrapper);
        System.out.println(user);
    
        //条件查询——范围查询
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(User::getAge,10,50);
        List<User> users = userDao.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    
        //条件查询——模糊匹配
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //wrapper.like(User::getUsername,"i");
        //百分号在右边:i%
        wrapper.likeRight(User::getUsername,"i");
        wrapper.likeLeft(User::getUsername,"i");
        List<User> users = userDao.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
    

(三)字段映射与表名映射

  1. 问题一:表字段与编码属性设计不同步

    解决:给实体属性添加注解

    public class User {   
        @TableField(value="pwd")
        private String password;
    }
    
  2. 问题二:编码中添加了数据库中未定义的属性

    解决:exist:设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用

  3. 问题三:采用默认查询开放了更多的字段查看权限,即全查,但是如密码这些是不可以开放的

    解决:设置当前属性对应的数据库表中的字段关系,select:设置属性是否参与查询,此属性与select()映射配置不冲突

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

    解决:设置当前类对应与数据库表关系

五、DML编程控制

(一)id生成策略控制

  1. 不同的表应用不同的id生成策略

    应用 策略
    日志 自增(1,2,3,4,……)
    购物订单 特殊规则(FQ23948AK3843)
    外卖单 关联地区日期等信息(10 04 20200314 34 91)
    关系表 可省略id
  2. 常见id生成策略值

    AUTO(0):使用数据库id自增策略控制id生成
    NONE(1):不设置id生成策略
    INPUT(2):用户手工输入id
    ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
    ASSIGN_UUID(4):以UUID生成算法作为id生成策略

    雪花算法:

    0			00100110111011010101100001101010011000110   10000   10001   		000000000010
    占位符:0  	 				时间戳(41)						 机器码(5+5)				序列号(12)
    
  3. 演示

    @Data
    public class User {
        @TableId(type = IdType.ASSIGN_ID)
        private Long id;
        private Integer age;
        private String username;
        private String password;
    }
    

    全局设置:——不需要在实体类中设置,在spring配置文件application.yaml中设置

    mybatis-plus:
      global-config:
        db-config:
          id-type: assign_id # 全局配置id生成策略
          table-prefix: tbl_ #全局配置实体表前缀
    

(二)多条操作——删除、查询

  1. 按照主键删除多条记录

    ArrayList<Long> list = new ArrayList<>();
    list.add(1L);
    list.add(8888L);
    list.add(9L);
    userDao.deleteBatchIds(list);
    
  2. 根据主键查询多条记录

    ArrayList<Long> list = new ArrayList<>();
    list.add(1L);
    list.add(8888L);
    list.add(9L);
    List<User> userList = userDao.selectBatchIds(list);
    

(三)逻辑删除

  1. 删除操作业务问题:业务数据从数据库中丢弃

  2. 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中

    ①数据库表中添加逻辑删除标记字段:

    名字		类型		长度	
    deleted  int       1 
    默认值为0
    

    ②实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    @Data
    public class User {
    //    @TableLogic(value = "0",delval = "1")
        private Integer deleted;
    }
    

    ③配置逻辑删除字面值

    //方式一:单独配置,容易出错
    @Data
    public class User {
    	@TableLogic(value = "0",delval = "1")
        private Integer deleted;
    }
    //方式二:全局配置
    mybatis-plus:
      global-config:
        db-config:
          logic-delete-field: deleted
          logic-not-delete-value: 0
          logic-delete-value: 1
    

    注意事项:全局配置,必须把文件后缀改成yaml,否则报错

    org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1
    

(四)乐观锁——只能针对小型企业

  • 问题:业务并发现象带来的问题:秒杀

  • 解决

    ①数据库表中添加锁标记字段

    ②实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    @Data
    public class User {
        @Version
        private Integer version;
    }
    

    ③配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

    @Configuration
    public class MPConfig {
        @Bean
        public MybatisPlusInterceptor myMPIntercepter(){
            //1. 定义mp拦截器
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            //2. 添加具体的拦截器
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            //3. 添加乐观锁拦截器
            mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return mybatisPlusInterceptor;
        }
    }
    

    ④使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行

    @Test
    void testUpdate() {
        //方式一
        /*User user = new User();
            user.setId(3L);
            user.setUsername("中国");
            user.setPassword("123456");
            user.setVersion(1);
            userDao.updateById(user);*/
    
        //方式二
        //1. 先通过要修改的数据id将当前的额数据查询出来
        /*User user = userDao.selectById(3L);
    
            //2. 将要修改的属性设置进去
            user.setUsername("中国大飞");
            userDao.updateById(user);*/
    
        //模拟两个用户同时操作一个动作
        //SELECT id,name,age,tel,deleted,version FROM tbl_user WHERE id=? 
        User user1 = userDao.selectById(3L); 			//通过要修改的数据id将当前的额数据查询出来 version=3
        User user2 = userDao.selectById(3L);			//通过要修改的数据id将当前的额数据查询出来 version=3
    
        user1.setUsername("中国大飞111111");			 //将要修改的属性设置进去 
        userDao.updateById(user1);						//更新数据  version = 4
    
        user2.setUsername("中国大飞22222222");			 //将要修改的属性设置进去 
        userDao.updateById(user2);						//更新数据的时候version=3条件已经不成立,无法操作
        //最终只有user1修改成功了
    }
    

六、代码生成器

  1. 创建项目

  2. 添加坐标

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.5</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.anfly</groupId>
        <artifactId>springboot_mp</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot_mp</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
    
            <!--spring webmvc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.6</version>
            </dependency><dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.4.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.24</version>
                <scope>provided</scope>
            </dependency>
    
            <!--代码生成器-->
            <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>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  3. 编写代码生成器——com.anfly.CodeGenerator

    public class CodeGenerator {
        public static void main(String[] args) {
            //1. 获取代码生成器的对象
            AutoGenerator autoGenerator = new AutoGenerator();
    
            //设置数据库相关配置
            DataSourceConfig dataSource = new DataSourceConfig();
            dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("123");
            autoGenerator.setDataSource(dataSource);
    
            //设置全局变量
            GlobalConfig globalConfig = new GlobalConfig();
            globalConfig.setOutputDir(System.getProperty("user.dir")+"/springboot_mp_generator/src/main/java/");
            globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
            globalConfig.setAuthor("anfly");    //设置作者
            globalConfig.setFileOverride(false);     //设置是否覆盖原始生成的文件
            globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
            globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
            autoGenerator.setGlobalConfig(globalConfig);
    
            //设置包名相关配置
            PackageConfig packageInfo = new PackageConfig();
            packageInfo.setParent("com.anfly");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
            packageInfo.setEntity("domain");    //设置实体类包名
            packageInfo.setMapper("dao");   //设置数据层包名
            autoGenerator.setPackageInfo(packageInfo);
    
            //策略设置
            StrategyConfig strategyConfig = new StrategyConfig();
            strategyConfig.setInclude("tbl_user");  //设置当前参与生成的表名,参数为可变参数
            strategyConfig.setTablePrefix("tbl_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
            strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
            strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
            strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
            strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
            autoGenerator.setStrategy(strategyConfig);
    
            //2. 执行
            autoGenerator.execute();
        }
    }
    
  4. 执行代码生成器main方法

标签:MyBatisPlus,userDao,wrapper,User,new,id,user
From: https://www.cnblogs.com/chinabigfly/p/16819965.html

相关文章