zoukankan      html  css  js  c++  java
  • mybatis-plus-3(MP)-进阶

    mybatis-plus-3(MP)-进阶

    一、准备

    1、数据库脚本

    -- 创建用户表
    CREATE TABLE user (
        id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键',
        name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
        age INT(11) DEFAULT NULL COMMENT '年龄',
        email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
        manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
        create_time DATETIME DEFAULT NULL COMMENT '创建时间',
    	update_time DATETIME DEFAULT NULL COMMENT '修改时间',
    	version INT(11) DEFAULT '1' COMMENT '版本',
    	deleted INT(1) DEFAULT '0' COMMENT '逻辑删除标识(0.未删除,1.已删除)',
        CONSTRAINT manager_fk FOREIGN KEY (manager_id)
            REFERENCES user (id)
    )  ENGINE=INNODB CHARSET=UTF8;
    
    -- 初始化数据:
    INSERT INTO user (id, name, age, email, manager_id
    	, create_time)
    VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
    		, '2019-01-11 14:20:20'),
    	(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553
    		, '2019-02-05 11:12:22'),
    	(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385
    		, '2019-02-14 08:31:16'),
    	(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
    		, '2019-01-14 09:15:15'),
    	(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385
    		, '2019-01-14 09:48:16');
    

    2、实体类

    @Data
    public class User {
        
        private Long id;  // 主键
        private String name;  // 姓名
        private Integer age;  // 年龄
        private String email;  // 邮箱
        private Long managerId;  // 直属上级
        private LocalDateTime createTime;  // 创建时间
        private LocalDateTime updateTime;  // 创建时间
        private Integer version;	// 版本
        private Integer deleted;	// 逻辑删除。0:未删除,1:已删除
    }
    

    3、Mapper

    public interface UserMapper extends BaseMapper<User> {
        
    }
    

    4、启动类

    @MapperScan("com.demo.dao")
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    5、application.yml

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/mp?useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
    

    二、高级功能

    1、逻辑删除

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/mp?useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
    mybatis-plus:
      global-config:
        db-config:
          logic-not-delete-value: 0 # 全局配置。如需局部配置可在实体类@TableLogic注解后配置
          logic-delete-value: 1
    
    @Configuration
    public class MybatisPlusConfiguration{
        
        // V3.1.1及一下版本需要配置这个Bean
        // v3.1.2不需要配置
        @Bean
        public ISqlInjector sqlInjector(){
            // 已经过时
            return new LogicSqlInjector();
        }
    }
    
    @Data
    public class User {
        
        private Long id;  // 主键
        private String name;  // 姓名
        private Integer age;  // 年龄
        private String email;  // 邮箱
        private Long managerId;  // 直属上级
        private LocalDateTime createTime;  // 创建时间
        private LocalDateTime updateTime;  // 创建时间
        private Integer version;	// 版本
        @TableLogic	// 全局逻辑删除
        @TableField(select=false) // 查询时,不查询该字段
        private Integer deleted;	// 逻辑删除。0:未删除,1:已删除
    }
    
    public interface UserMapper extends BaseMapper<User> {    
        @Select("select * from user ${ew.customSqlSegment}")
        List<User> mySelectList(@Param(Constants.WRAPPER) Wrapper<User> wrapper);  
    }
    

    测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SimpleTest{
        
        @Autowired
        private UserMapper userMapper;
        
        @Test
        public void deleteById(){
            // 返回影响行数
           int rows = userMapper.deleteById(id);
           System.out.println("影响行数:" + rows);
        }
        
        // 查询时加入了 where deleted = 0
        // 查询时会将deleted查询出来。解决办法是在实体类注解@TableField(select=false)
        @Test
        public void select(){
           List<User> users = userMapper.selectList(null);
           users.forEach(System.out::println);
        }
        
        // 更新时加入了 where deleted = 0
        @Test
        public void updateById(){
           User user = new User();
           user.setId(id);
           user.setAge(26);
           int rows = userMapper.updateById(user);
           System.out.println("影响记录数:" + rows);
        }
        
        // 在Mapper自定义的查询中,查询时不会出现where deleted = 0
        // 解决:
        // 		方法一:如下面方法。
        //		方法二:在Mapper的select中加入条件
        @Test
        public void mySelect(){
           List<User> users = userMapper.mySelectList(
               // age > 25 and deleted = 0
               Wrappers.<User>lambdaQuery().gt(User::getAge,25).eq(User::getDeleted,0)
           );
        }
    }
    

    2、自动填充

    @Data
    public class User {
        
        private Long id;  // 主键
        private String name;  // 姓名
        private Integer age;  // 年龄
        private String email;  // 邮箱
        private Long managerId;  // 直属上级
        @TableField(fill=FieldFill.INSERT)
        private LocalDateTime createTime;  // 创建时间
        @TableField(fill=FieldFill.UPDATE)
        private LocalDateTime updateTime;  // 创建时间
        private Integer version;	// 版本
        private Integer deleted;	// 逻辑删除。0:未删除,1:已删除
    }
    
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        
        @Override
        public void insertFill(MetaObject metaObject){
            // 优化1
            // 有些实体没有createTime。每次都自动填充,浪费了性能
            // 判断一下是否有createTime再自动填充
            boolean hasSetter = metaObject.hasSetter("createTime");
            if(hasSetter){
                // 优化2
                // 达到效果。已设置值,要已设置的值。未设置值,自动填充
                Object val = getFieldValByName("createTime",metaObject);
                if(val == null){
                    System.out.println("insertFill~~");
                    // createTime 为实体参数的名称
                    setInsertFieldValByName("createTime",LocalDateTime.now(),metaObject);
                }
            }
        }
        
        @Override
        public void updateFill(MetaObject metaObject){
            System.out.println("updateFill~~");
            // createTime 为实体参数的名称
            setUpdateFieldValByName("updateTime",LocalDateTime.now(),metaObject);
        }
    }
    

    测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SimpleTest{
        
        @Autowired
        private UserMapper userMapper;
        
        @Test
        public void insert(){
            User user = new User();
            user.setName("小明");
            user.setAge("23");
            user.setManagerId("1");
            int rows = userMapper.insert(user);
           System.out.println("影响行数:" + rows);
        }
        
        @Test
        public void updateById(){
           User user = new User();
           user.setId(id);
           user.setAge(26);
           int rows = userMapper.updateById(user);
           System.out.println("影响记录数:" + rows);
        }
    }
    

    3、乐观锁插件

    @Configuration
    public class MybatisPlusConfig {
    	/**
    	 *   乐观锁
    	 */
    	@Bean 
    	public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    	    return new OptimisticLockerInterceptor();
    	}
    }
    
    @Data
    public class User {
        
        private Long id;  // 主键
        private String name;  // 姓名
        private Integer age;  // 年龄
        private String email;  // 邮箱
        private Long managerId;  // 直属上级
        private LocalDateTime createTime;  // 创建时间
        private LocalDateTime updateTime;  // 创建时间
        @Version // 支持的数据类型:int Integer long Long Date Timestamp LocalDateTime
        private Integer version;	// 版本
        private Integer deleted;	// 逻辑删除。0:未删除,1:已删除
    }
    

    测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SimpleTest{
        
        @Autowired
        private UserMapper userMapper;
        
        @Test
        public void updateById(){
           int version = 1;
            
           User user = new User();
           user.setId(id);
           user.setAge(26);
           user.setVersion(version);
            // 查询后版本号+1
           int rows = userMapper.updateById(user);
           System.out.println("影响记录数:" + rows);
        }
    }
    

    4、性能分析插件

    @Configuration
    public class MybatisPlusConfig {
        @Bean
        @Profile({"dev","test"})// 设置 dev test 环境开启
    	public PerformanceInterceptor performanceInterceptor() {
            PerformanceInterceptor performanceInterceptor =  new PerformanceInterceptor();
            performanceInterceptor.setFormat(true);// 格式化语句
            //performanceInterceptor.setMaxTime(5);// 执行时间超过多少秒会抛出异常
            return  performanceInterceptor;
    }
    

    4.1、执行sql分析打印

    参考文档

    <dependency>
      <groupId>p6spy</groupId>
      <artifactId>p6spy</artifactId>
      <version>3.8.2</version>
    </dependency>
    
    spring:
      datasource:
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver
        url: jdbc:p6spy:h2:mem:test
    

    spy.properties:

    #3.2.1以上使用
    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
    #3.2.1以下使用或者不配置
    #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
    # 自定义日志打印
    logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
    #日志输出到控制台
    appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
    # 使用日志系统记录 sql
    #appender=com.p6spy.engine.spy.appender.Slf4JLogger
    # 设置 p6spy driver 代理
    deregisterdrivers=true
    # 取消JDBC URL前缀
    useprefix=true
    # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
    excludecategories=info,debug,result,commit,resultset
    # 日期格式
    dateformat=yyyy-MM-dd HH:mm:ss
    # 实际驱动可多个
    #driverlist=org.h2.Driver
    # 是否开启慢SQL记录
    outagedetection=true
    # 慢SQL记录标准 2 秒
    outagedetectioninterval=2
    

    5、多租户SQL解析器

    项目

    @Configuration
    public class MybatisPlusConfig {
        /**
         * mybatis-plus分页插件<br>
         * 文档:http://mp.baomidou.com<br>
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            /*
             * 【测试多租户】 SQL 解析处理拦截器<br>
             * 这里固定写成住户 1 实际情况你可以从cookie读取,因此数据看不到 【 麻花藤 】 这条记录( 注意观察 SQL )<br>
             */
            List<ISqlParser> sqlParserList = new ArrayList<>();
            TenantSqlParser tenantSqlParser = new TenantSqlParser();
            tenantSqlParser.setTenantHandler(new TenantHandler() {
                @Override
                public Expression getTenantId() {
                    return new LongValue(1L);
                }
    
                @Override
                public String getTenantIdColumn() {
                    return "tenant_id";
                }
    
                @Override
                public boolean doTableFilter(String tableName) {
                    // 这里可以判断是否过滤表
                    /*if ("user".equals(tableName)) {
                        return true;
                    }*/
                    return false;
                }
            });
    
            sqlParserList.add(tenantSqlParser);
            paginationInterceptor.setSqlParserList(sqlParserList);
    //        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
    //            @Override
    //            public boolean doFilter(MetaObject metaObject) {
    //                MappedStatement ms = PluginUtils.getMappedStatement(metaObject);
    //                // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
    //                if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
    //                    return true;
    //                }
    //                return false;
    //            }
    //        });
            return paginationInterceptor;
        }
    }
    

    6、动态表名 SQL 解析器

    项目

    @Configuration
    @MapperScan("com.baomidou.mybatisplus.samples.dytablename.mapper")
    public class MybatisPlusConfig {
    
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
            dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{
                put("user", (metaObject, sql, tableName) -> {
                    // metaObject 可以获取传入参数,这里实现你自己的动态规则
                    String year = "_2018";
                    int random = new Random().nextInt(10);
                    if (random % 2 == 1) {
                        year = "_2019";
                    }
                    return tableName + year;
                });
            }});
            paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
            return paginationInterceptor;
        }
    }
    

    7、Sql 注入器

    /**
     * 删除全部
     */
    public class DeleteAll extends AbstractMethod {
    
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, 
                                                     Class<?> modelClass, TableInfo tableInfo) {
            /* 执行 SQL ,动态 SQL 参考类 SqlMethod */
            String sql = "delete from " + tableInfo.getTableName();
            /* mapper 接口方法名一致 */
            String method = "deleteAll";
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
            return this.addDeleteMappedStatement(mapperClass, method, sqlSource);
        }
    }
    
    @Component
    public class MySqlInjector extends DefaultSqlInjector{
        @Override
        public List<AbstractMethod> getMethodList(Class<?> mapperClass){
            List<AbstractMethod> methodList = super.getMethodList(mapperClass);
            methodList.add(new DeleteAll());
            return methodList;
        }
    }
    
    public interface UserMapper extends BaseMapper<User> {
        int deleteAll(); // 返回影响行数
    }
    

    以上学习自 慕课网 -- MyBatis-Plus进阶

    视频地址

  • 相关阅读:
    佛洛依德
    Python2.7利用Tesseract进行中英文图像识别
    批量生成二维码打包成exe文件
    python基础5—文件 | json序列化
    python基础6—(高阶,匿名,偏)函数 | 装饰器
    python基础4—面向对象
    python基础2—集合框架
    一不小心翻车了-(angularjs 1.6X) 由Eventbus使用异常说起
    简单说下js闭包之setTimeout
    html5上传本地图片,在线预览及裁剪(filereader,canvas)
  • 原文地址:https://www.cnblogs.com/luckyzs/p/13258342.html
Copyright © 2011-2022 走看看