Mybatis-plus学习笔记,基于springboot

1、依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>

2、自动生成代码

public class CodeBuilder {
    public static void main(String[] args) {
        AutoGenerator autoGenerator = new AutoGenerator();

        // 数据库表名
        String[] tableList = {
                ""
        };

        // 作者
        String author = "";
        // 数据库乐观锁字段名
        String version = "version";
        // 数据库逻辑删除字段名
        String deleted = "deleted";
        // 数据库表前缀
        String tablePrefix = "";
        // 字段前缀
        String columnPrefix = "";
        // 包名
        String packageName = "";

        // JDBC
        String dataBaseUrl = "";
        String dataBaseDriverName = "";
        String dataBaseUsername = "";
        String dataBasePassword = "";

        // 自动填充配置
        // 根据自己的表结构修改
        // 创建时间
        TableFill createTime = new TableFill("f_create_time", FieldFill.INSERT);
        // 修改时间
        TableFill updateTime = new TableFill("f_update_time", FieldFill.INSERT_UPDATE);
        // 经办人ID
        TableFill operatorId = new TableFill("f_operator_id", FieldFill.INSERT_UPDATE);
        // 经办人名字
        TableFill operator = new TableFill("f_operator", FieldFill.INSERT_UPDATE);

        ArrayList<TableFill> list = new ArrayList<>();

        list.add(createTime);
        list.add(updateTime);
        list.add(operatorId);
        list.add(operator);

        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        String path = System.getProperty("user.dir");
        globalConfig.setOutputDir(path + "/src/main/java");
        globalConfig.setAuthor(author);
        globalConfig.setOpen(false);
        globalConfig.setServiceName("%sService");
        globalConfig.setControllerName("%sController");
        globalConfig.setEntityName("%sPO");
        globalConfig.setMapperName("%sDao");
        globalConfig.setFileOverride(true);
        globalConfig.setBaseResultMap(true);
        globalConfig.setBaseColumnList(true);
        globalConfig.setActiveRecord(true);
        globalConfig.setSwagger2(true);
        globalConfig.setIdType(IdType.AUTO);
        globalConfig.setDateType(DateType.ONLY_DATE);
        autoGenerator.setGlobalConfig(globalConfig);

        // 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl(dataBaseUrl);
        dataSourceConfig.setDbType(DbType.MYSQL);
        dataSourceConfig.setDriverName(dataBaseDriverName);
        dataSourceConfig.setUsername(dataBaseUsername);
        dataSourceConfig.setPassword(dataBasePassword);
        autoGenerator.setDataSource(dataSourceConfig);

        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setMapper("dao");
        packageConfig.setController("controller");
        packageConfig.setEntity("entity.po");
        packageConfig.setService("service");
        packageConfig.setParent(packageName);
        autoGenerator.setPackageInfo(packageConfig);

        // 策略设置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude(tableList);
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setEntitySerialVersionUID(false);
        strategy.setEntityTableFieldAnnotationEnable(true);
        strategy.setVersionFieldName(version);
        strategy.setLogicDeleteFieldName(deleted);
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityColumnConstant(true);
        strategy.setChainModel(true);
        strategy.setTablePrefix(tablePrefix);
        strategy.setFieldPrefix(columnPrefix);


        strategy.setTableFillList(list);

        // RestFull 风格
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);

        autoGenerator.setStrategy(strategy);

        autoGenerator.execute();

    }


}

3、springboot注解添加mapperscan

@MapperScan("com.hong.mapper")//可以写在MybatisplusConfig中

4、注解

@TableName

  • 表名注解

    属性 类型 必须指定 默认值 描述
    value String "" 表名
    schema String "" schema
    keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)
    resultMap String "" xml 中 resultMap 的 id
    autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)

@TableId

  • 主键注解

    属性 类型 必须指定 默认值 描述
    value String "" 主键字段名
    type Enum IdType.NONE 主键类型
  • IdType

    描述
    AUTO 数据库ID自增
    NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
    INPUT insert前自行set主键值
    ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

@TableField

  • 字段注解

    属性 类型 必须指定 默认值 描述
    value String "" 数据库字段名
    el String "" 映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
    exist boolean true 是否为数据库表字段
    condition String "" 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考
    update String "" 字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
    insertStrategy Enum N DEFAULT 举例:NOT_NULL: insert into table_a(column) values (#{columnProperty})
    updateStrategy Enum N DEFAULT 举例:IGNORED: update table_a set column=#{columnProperty}
    whereStrategy Enum N DEFAULT 举例:NOT_EMPTY: where column=#{columnProperty}
    fill Enum FieldFill.DEFAULT 字段自动填充策略
    select boolean true 是否进行 select 查询
    keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
    jdbcType JdbcType JdbcType.UNDEFINED JDBC类型 (该默认值不代表会按照该值生效)
    typeHandler Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
    numericScale String "" 指定小数点后保留的位数

@Version

  • 乐观锁

@TableLogic

  • 逻辑删除注解

    属性 类型 必须指定 默认值 描述
    value String "" 逻辑未删除值
    delval String "" 逻辑删除值

5、配置插件

1、日志(控制台输出)

#配置日志输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2、自动填充策略

  • 数据库添加对应字段

    • create_time

    • update_time

    • datetime 类型

  • 对应属性需要加上注解

        @TableField(fill = FieldFill.INSERT)
        private Date creatTime;
    
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updateTime;
    
  • 编写MybatisPlusConfig类

    @Configuration
    public class MybatisPlusConfig {
    
    
        /**
         * 注册字段自动填充
         *
         * @return
         */
        @Bean
        public MetaObjectHandler getMetaObjectHandler() {
    
            return new MetaObjectHandler() {
                @Override
                public void insertFill(MetaObject metaObject) {
                    this.setFieldValByName("createTime", new Date(), metaObject);
                    this.setFieldValByName("updateTime", new Date(), metaObject);
    
    
                }
    
                @Override
                public void updateFill(MetaObject metaObject) {
                    this.setFieldValByName("updateTime", new Date(), metaObject);
                }
            };
        }
    
        /**
         * 乐观锁插件
         *
         * @return
         */
        @Bean
        public OptimisticLockerInterceptor getOptimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    
        /**
         * 分页插件
         *
         * @return
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
    }
    
    

3、乐观锁version

  • 数据库添加对应字段,默认值为1

    • version
  • 实体类添加对应注解

        @Version
        private Integer version;
    

4、逻辑删除

  • 解释:在逻辑上实现删除,实际上数据库没有被删除,但是普通用户查询不到,只有管理员能查询

  • 在数据库添加对应字段,默认0为没有删除,1为逻辑删除

    • deleted
  • 实体类中添加对应注解

        @TableLogic
        private Integer deleted;
    

5、分页

  • 查询测试

        @Test
        void selectPageTest() {
            //参数一:当前页
            //参数二:页面大小
            Page<TUser> objectPage = new Page<>(1,2);
            tUserMapper.selectPage(objectPage,null);
            objectPage.getRecords().forEach(System.out::println);
        }
    

6、性能分析插件(P6spy)

  • 导入依赖

    <dependency>
        <groupId>p6spy</groupId>
        <artifactId>p6spy</artifactId>
        <version>3.9.0</version>
    </dependency>
    
  • 接着编辑 application.properties 文件,更换数据库连接驱动:

    #数据库信息配置
    spring.datasource.username=
    spring.datasource.password=
    spring.datasource.url=jdbc:p6spy:mysql:
    spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
    
  • 最后创建 spy.properties 配置文件即可

    #3.2.1以上使用
    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,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
    

7、多数据源

  • 导入依赖
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>3.2.0</version>
</dependency>
  • 数据源配置文件
spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
          schema: db/schema.sql # 配置则生效,自动初始化表结构
          data: db/data.sql # 配置则生效,自动初始化数据
          continue-on-error: true # 默认true,初始化失败是否继续
          separator: ";" # sql默认分号分隔符
          
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
  • 使用@DS注解切换数据源
@Service
@DS("slave")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }
  
  @Override
  @DS("slave_1")
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

6、CRUD(service层)

save

// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);

remove

// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

update

// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereEntity 条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);

get

// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

7、整合redis使用二级缓存

  • 编写application.properties配置文件,引入redis地址
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0
  • 编写MybatisRedisConfig配置文件
    • 引入StringRedisTemplate防止数据在redis中显示乱码
    • 传入redis时转为JSON字符串,从redis中获得时解析JSON字符串
package com.hong.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


@Slf4j
public class MybatisRedisConfig implements Cache {
    //失效时间
    private static final long EXPIRE_TIME_IN_MINUTES = 30;
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
    // cache instance id
    private final String id;
    //redis操作工具类

    @Autowired
    private StringRedisTemplate redisTemplate;


    public MybatisRedisConfig(String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
    }


    @Override
    public String getId() {
        return id;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void putObject(Object key, Object value) {
        this.redisTemplate.opsForValue().set(key.toString(), JSON.toJSONString(value), EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
        log.info("Put query result to redis");
    }

    /**
     * Get cached query result from redis
     *
     * @param key
     * @return
     */
    @Override
    public Object getObject(Object key) {
        log.info("Get cached query result from redis");
        if (this.redisTemplate == null) {
            this.redisTemplate = SpringContextUtil.getBean("stringRedisTemplate");
        }
        return JSON.parse(this.redisTemplate.opsForValue().get(key.toString()));
    }

    /**
     * Remove cached query result from redis
     *
     * @param key
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object removeObject(Object key) {
        this.redisTemplate.delete(key.toString());
        log.info("Remove cached query result from redis");
        return null;
    }

    /**
     * Clears this cache instance
     */
    @Override
    public void clear() {
        this.redisTemplate.execute((RedisCallback) connection -> {
            connection.flushDb();
            return null;
        });
        log.info("Clear all the cached query result from redis");
    }

    @Override
    public int getSize() {
        return 0;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

}

  • 在mapper上加上注解
@CacheNamespace(implementation = MybatisRedisConfig.class,eviction = MybatisRedisConfig.class)
posted @ 2020-08-28 14:35  吴志鸿  阅读(262)  评论(0编辑  收藏  举报