MyBatis-Plus 快速入門 – 入門篇鏈接
項目地址 :https://github.com/tyronczt/java-learn/tree/master/Tools/mybatis-plus-high
邏輯刪除的運用
1、在刪除字段上增加 @TableLogic
註解
/**
* 刪除標識,0未刪除,1已刪除
* @TableLogic 描述:表字段邏輯處理註解(邏輯刪除)
*/
@TableLogic
private Integer deleted;
2、配置文件中增加刪除標識的值,默認是 0 表示未刪除,1 表示已刪除
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 # 邏輯已刪除值(默認爲 1)
logic-not-delete-value: 0 # 邏輯未刪除值(默認爲 0)
3、測試方法
/**
* 邏輯刪除(TableLogic的使用)
*
* ==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
* ==> Parameters: 1094592041087729666(Long)
* <== Updates: 1
* 影響行數:1
*/
@Test
public void deleteById() {
int effectNum = userMapper.deleteById(1094592041087729666L);
System.out.println("影響行數:" + effectNum);
}
/**
* 根據id查詢用戶信息,會增加delete=0的條件
*
* ==> Preparing: SELECT id,deleted,create_time,name,update_time,manager_id,version,email,age FROM user WHERE id=? AND deleted=0
* ==> Parameters: 1094592041087729666(Long)
* <== Total: 0
* 用戶信息:null
*
* 在deleted字段上增加註解:@TableField(select = false) 不顯示deleted字段。
* ==> Preparing: SELECT id,create_time,name,update_time,manager_id,version,email,age FROM user WHERE id=? AND deleted=0
*/
@Test
public void selectById() {
User user = userMapper.selectById(1094592041087729666L);
System.out.println("用戶信息:" + user);
}
注意事項:自定義方法中 @TableLogic 不會起作用
自動填充的運用
1、在自動填充字段上增加 @TableField(fill = FieldFill.XXX)
註解
/**
* 創建時間
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新時間
*/
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
2、自定義表對象處理器 MyMetaObjectHandler,實現 MetaObjectHandler 接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("---insertFill---");
setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
System.out.println("---updateFill---");
setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}
3、測試方法
/**
* 新增用戶,會自動填充操作時間
*
* ---insertFill---
* ==> Preparing: INSERT INTO user ( id, create_time, name, manager_id, email, age ) VALUES ( ?, ?, ?, ?, ?, ? )
* ==> Parameters: 1260593237899411457(Long), 2020-05-13T23:28:14.124(LocalDateTime), 陳海華(String), 1088250446457389058(Long), [email protected](String), 23(Integer)
* <== Updates: 1
* 影響行數:1
*/
@Test
public void insert() {
User user = new User();
user.setAge(23);
user.setName("陳海華");
user.setEmail("[email protected]");
user.setManagerId(1088250446457389058L);
int effectNum = userMapper.insert(user);
System.out.println("影響行數:" + effectNum);
}
/**
* 更新用戶信息,會自動填充更新時間
*
* ---updateFill---
* ==> Preparing: UPDATE user SET update_time=?, age=? WHERE id=? AND deleted=0
* ==> Parameters: 2020-05-13T23:37:12.779(LocalDateTime), 24(Integer), 1260593237899411457(Long)
* <== Updates: 1
* 影響行數:1
*/
@Test
public void updateById() {
User user = new User();
user.setId(1260593237899411457L);
user.setAge(24);
int effectNum = userMapper.updateById(user);
System.out.println("影響行數:" + effectNum);
}
4、根據實際情況對處理器優化
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 優化1:當有自動填充字段時再進行自動填充
boolean hasSetter = metaObject.hasSetter("createTime");
if (hasSetter) {
System.out.println("---insertFill---");
setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
// 優化2:當字段值沒有設值時再自動填充
Object updateTime = getFieldValByName("updateTime", metaObject);
if (null == updateTime) {
System.out.println("---updateFill---");
setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}
}
樂觀鎖插件的運用
悲觀鎖(Pessimistic Locking),悲觀鎖是指在數據處理過程,使數據處於鎖定狀態,一般使用數據庫的鎖機制實現。適合在寫多讀少的併發環境中使用,雖然無法維持非常高的性能,但是在樂觀鎖無法提更好的性能前提下,可以做到數據的安全性。
樂觀鎖相對悲觀鎖而言,它認爲數據一般情況下不會造成衝突,所以在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,如果發現衝突了,則讓返回錯誤信息,讓用戶決定如何去做。
利用數據版本號(version)機制是樂觀鎖最常用的一種實現方式。
1、配置樂觀鎖插件
/**
* 樂觀鎖插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
2、在版本字段上增加 @Version
註解
@Version
private Integer version;
3、測試栗子
/**
* 樂觀鎖-更新用戶數據
*
* ==> Preparing: UPDATE user SET update_time=?, version=?, age=? WHERE id=? AND version=? AND deleted=0
* ==> Parameters: 2020-05-17T20:42:39.527(LocalDateTime), 2(Integer), 29(Integer), 1260593237899411457(Long), 1(Integer)
* <== Updates: 1
* 影響行數:1
*/
@Test
public void updateById() {
// 模擬從數據庫取出版本信息
int version = 1;
User user = new User();
user.setId(1260593237899411457L);
user.setVersion(version);
user.setAge(29);
int effectNum = userMapper.updateById(user);
System.out.println("影響行數:" + effectNum);
}
執行 SQL 分析打印
1、Maven:
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>最新版本</version>
</dependency>
2、application.yml 配置:
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:h2:mem:test
...
3、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
#日誌輸出到文件中
logfile=tyron.log
# 使用日誌系統記錄 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
Sql 注入器
1.1、創建定義方法的類
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
// 執行的SQL
String sql = "delete from " + tableInfo.getTableName();
// Mapper接口方法名
String method = "deleteAll";
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addDeleteMappedStatement(mapperClass, method, sqlSource);
}
1.2、創建注入器
@Component
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new DeleteAllMethod());
return methodList;
}
}
1.3、在Mapper中加入自定義方法
/**
* 刪除所有數據
*
* @return 影響的行數
*/
int deleteAll();
1.4、測試
/**
* 刪除所有行數
*
* ==> Preparing: delete from user
* ==> Parameters:
* <== Updates: 7
* 影響的行數:7
*/
@Test
public void deleteAll() {
int effectNums = userMapper.deleteAll();
System.out.println("影響的行數:" + effectNums);
}
2.1、將自帶批量插入注入器添加到methodList中
@Component
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new DeleteAllMethod());
methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete() && !t.getColumn().equals("age")));// 自帶批量插入注入器(邏輯刪除字段和年齡字段不填充)
return methodList;
}
}
2.2、在Mapper中加入自帶方法
/**
* 批量插入用戶
*
* @param list 列表
* @return
*/
int insertBatchSomeColumn(List<User> list);
2.3、測試
@Test
public void insertBatchSomeColumn() {
User user1 = new User();
user1.setName("黃呼呼");
user1.setEmail("[email protected]");
user1.setManagerId(1087982257332887553L);
user1.setAge(33);
User user2 = new User();
user2.setName("張云云");
user2.setEmail("[email protected]");
user2.setManagerId(1087982257332887553L);
user2.setAge(23);
int effectNums = userMapper.insertBatchSomeColumn(Arrays.asList(user1, user2));
System.out.println("影響的行數:" + effectNums);
}
同理的自帶注入器還有:
- LogicDeleteByIdWithFill:根據 id 邏輯刪除數據,並帶字段填充功能。注意入參是 entity !!! ,如果字段沒有自動填充,就只是單純的邏輯刪除;
- AlwaysUpdateSomeColumnById :根據 ID 更新固定的那幾個字段(但是不包含邏輯刪除)