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)