mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-08 09:38:26 +08:00
!492 新增 OptimisticLockManager,用于处理跳过乐观锁的场景,测试类就文档补充
Merge pull request !492 from tiankafei/optimisticlock
This commit is contained in:
commit
6ffc6694ac
@ -418,7 +418,7 @@ public class ClickhouseDialectImpl extends CommonsDialectImpl {
|
||||
|
||||
// 乐观锁字段
|
||||
String versionColumn = tableInfo.getVersionColumn();
|
||||
if (StringUtil.isNotBlank(versionColumn)) {
|
||||
if (StringUtil.isNotBlank(tableInfo.getOptimisticLockColumnOrSkip())) {
|
||||
stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 ");
|
||||
}
|
||||
|
||||
@ -491,7 +491,7 @@ public class ClickhouseDialectImpl extends CommonsDialectImpl {
|
||||
|
||||
// 乐观锁字段
|
||||
String versionColumn = tableInfo.getVersionColumn();
|
||||
if (StringUtil.isNotBlank(versionColumn)) {
|
||||
if (StringUtil.isNotBlank(tableInfo.getOptimisticLockColumnOrSkip())) {
|
||||
stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 ");
|
||||
}
|
||||
|
||||
|
||||
@ -842,7 +842,7 @@ public class CommonsDialectImpl implements IDialect {
|
||||
|
||||
// 乐观锁字段
|
||||
String versionColumn = tableInfo.getVersionColumn();
|
||||
if (StringUtil.isNotBlank(versionColumn)) {
|
||||
if (StringUtil.isNotBlank(tableInfo.getOptimisticLockColumnOrSkip())) {
|
||||
stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 ");
|
||||
}
|
||||
|
||||
@ -868,7 +868,7 @@ public class CommonsDialectImpl implements IDialect {
|
||||
tableInfo.buildTenantCondition(sql, tenantIdArgs, this);
|
||||
|
||||
// 乐观锁条件
|
||||
if (StringUtil.isNotBlank(versionColumn)) {
|
||||
if (StringUtil.isNotBlank(tableInfo.getOptimisticLockColumnOrSkip())) {
|
||||
Object versionValue = tableInfo.buildColumnSqlArg(entity, versionColumn);
|
||||
if (versionValue == null) {
|
||||
throw FlexExceptions.wrap(LocalizedFormats.ENTITY_VERSION_NULL, entity);
|
||||
@ -915,7 +915,7 @@ public class CommonsDialectImpl implements IDialect {
|
||||
|
||||
// 乐观锁字段
|
||||
String versionColumn = tableInfo.getVersionColumn();
|
||||
if (StringUtil.isNotBlank(versionColumn)) {
|
||||
if (StringUtil.isNotBlank(tableInfo.getOptimisticLockColumnOrSkip())) {
|
||||
stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 ");
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.core.optimisticlock;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 乐观锁管理器。
|
||||
*/
|
||||
public class OptimisticLockManager {
|
||||
|
||||
private OptimisticLockManager() {
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Boolean> skipFlags = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 跳过乐观锁字段处理,直接进行数据库物理操作。
|
||||
*/
|
||||
public static <T> T execWithoutOptimisticLock(Supplier<T> supplier) {
|
||||
try {
|
||||
skipOptimisticLock();
|
||||
return supplier.get();
|
||||
} finally {
|
||||
restoreOptimisticLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过乐观锁字段处理,直接进行数据库物理操作。
|
||||
*/
|
||||
public static void execWithoutOptimisticLock(Runnable runnable) {
|
||||
try {
|
||||
skipOptimisticLock();
|
||||
runnable.run();
|
||||
} finally {
|
||||
restoreOptimisticLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过乐观锁字段处理。
|
||||
*/
|
||||
public static void skipOptimisticLock() {
|
||||
skipFlags.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复乐观锁字段处理。
|
||||
*/
|
||||
public static void restoreOptimisticLock() {
|
||||
skipFlags.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取乐观锁列,返回 {@code null} 表示跳过乐观锁。
|
||||
*
|
||||
* @param optimisticLockColumn 乐观锁列
|
||||
* @return 乐观锁列
|
||||
*/
|
||||
public static String getOptimisticLockColumn(String optimisticLockColumn) {
|
||||
if (optimisticLockColumn == null) {
|
||||
return null;
|
||||
}
|
||||
Boolean skipFlag = skipFlags.get();
|
||||
if (skipFlag == null) {
|
||||
return optimisticLockColumn;
|
||||
}
|
||||
return skipFlag ? null : optimisticLockColumn;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 乐观锁相关功能。
|
||||
*/
|
||||
package com.mybatisflex.core.optimisticlock;
|
||||
@ -30,6 +30,7 @@ import com.mybatisflex.core.exception.FlexExceptions;
|
||||
import com.mybatisflex.core.exception.locale.LocalizedFormats;
|
||||
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
|
||||
import com.mybatisflex.core.mybatis.TypeHandlerObject;
|
||||
import com.mybatisflex.core.optimisticlock.OptimisticLockManager;
|
||||
import com.mybatisflex.core.query.Brackets;
|
||||
import com.mybatisflex.core.query.CPI;
|
||||
import com.mybatisflex.core.query.Join;
|
||||
@ -241,6 +242,10 @@ public class TableInfo {
|
||||
this.logicDeleteColumn = logicDeleteColumn;
|
||||
}
|
||||
|
||||
public String getOptimisticLockColumnOrSkip() {
|
||||
return OptimisticLockManager.getOptimisticLockColumn(versionColumn);
|
||||
}
|
||||
|
||||
public String getVersionColumn() {
|
||||
return versionColumn;
|
||||
}
|
||||
@ -884,7 +889,7 @@ public class TableInfo {
|
||||
}
|
||||
|
||||
// 添加乐观锁条件,只有在 update 的时候进行处理
|
||||
if (StringUtil.isNotBlank(versionColumn) && entity != null) {
|
||||
if (StringUtil.isNotBlank(getOptimisticLockColumnOrSkip()) && entity != null) {
|
||||
Object versionValue = buildColumnSqlArg(entity, versionColumn);
|
||||
if (versionValue == null) {
|
||||
throw FlexExceptions.wrap(LocalizedFormats.ENTITY_VERSION_NULL, entity);
|
||||
|
||||
@ -54,6 +54,9 @@ public class Account extends BaseEntity implements Serializable, AgeAware {
|
||||
// @Column(isLogicDelete = true)
|
||||
private Boolean isDelete;
|
||||
|
||||
@Column(version = true)
|
||||
private Integer version;
|
||||
|
||||
private List<Article> articles;
|
||||
|
||||
@Column(ignore = true)
|
||||
@ -125,6 +128,14 @@ public class Account extends BaseEntity implements Serializable, AgeAware {
|
||||
isDelete = delete;
|
||||
}
|
||||
|
||||
public Integer getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public List<Article> getArticles() {
|
||||
return articles;
|
||||
}
|
||||
@ -152,6 +163,7 @@ public class Account extends BaseEntity implements Serializable, AgeAware {
|
||||
", birthday=" + birthday +
|
||||
", options=" + options +
|
||||
", isDelete=" + isDelete +
|
||||
", version=" + version +
|
||||
", articles=" + articles +
|
||||
", title='" + title + '\'' +
|
||||
'}';
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.test;
|
||||
|
||||
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||
import com.mybatisflex.core.audit.AuditManager;
|
||||
import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||
import com.mybatisflex.core.audit.MessageCollector;
|
||||
import com.mybatisflex.core.optimisticlock.OptimisticLockManager;
|
||||
import javax.sql.DataSource;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
|
||||
public class OptimisticLockTestStarter {
|
||||
|
||||
public static void main(String[] args) {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema_optimisticlock.sql")
|
||||
.addScript("data_optimisticlock.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
.setDataSource(dataSource)
|
||||
.addMapper(AccountMapper.class)
|
||||
.start();
|
||||
|
||||
//开启审计功能
|
||||
AuditManager.setAuditEnable(true);
|
||||
|
||||
//设置 SQL 审计收集器
|
||||
MessageCollector collector = new ConsoleMessageCollector();
|
||||
AuditManager.setMessageCollector(collector);
|
||||
|
||||
|
||||
AccountMapper accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||
accountMapper.selectAll().forEach(System.out::println);
|
||||
|
||||
System.out.println(">>>>>>>>>>>>>>>update id=1 user_name from 张三 to 张三1");
|
||||
|
||||
Account account = new Account();
|
||||
account.setId(1L);
|
||||
account.setUserName("张三1");
|
||||
OptimisticLockManager.execWithoutOptimisticLock(() -> accountMapper.update(account));
|
||||
accountMapper.selectAll().forEach(System.out::println);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
INSERT INTO tb_account
|
||||
VALUES (1, '张三', 18, 0,'2020-01-11', '{"key":"value1"}',0,0),
|
||||
(2, '王麻子叔叔', 19, 1, '2021-03-21', '{"key":"value2"}',0,0);
|
||||
@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS `tb_account`
|
||||
(
|
||||
`id` INTEGER auto_increment,
|
||||
`user_name` VARCHAR(100),
|
||||
`age` Integer,
|
||||
`sex` Integer,
|
||||
`birthday` DATETIME,
|
||||
`options` VARCHAR(1024),
|
||||
`is_delete` Integer,
|
||||
`version` Integer
|
||||
);
|
||||
34
readme_zh.md
34
readme_zh.md
@ -451,6 +451,40 @@ QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
|
||||
> 更多关于 MyBatis-Flex APT 的配置,请点击 [这里](./docs/zh/others/apt.md)。
|
||||
|
||||
## 乐观锁
|
||||
|
||||
### 乐观锁配置
|
||||
|
||||
```java
|
||||
@Table(value = "tb_account", dataSource = "ds2", onSet = AccountOnSetListener.class)
|
||||
public class Account extends BaseEntity implements Serializable, AgeAware {
|
||||
|
||||
......
|
||||
|
||||
@Column(version = true)
|
||||
private Integer version;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 跳过乐观锁的使用
|
||||
|
||||
```java
|
||||
AccountMapper accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||
accountMapper.selectAll().forEach(System.out::println);
|
||||
|
||||
System.out.println(">>>>>>>>>>>>>>>update id=1 user_name from 张三 to 张三1");
|
||||
|
||||
Account account = new Account();
|
||||
account.setId(1L);
|
||||
account.setUserName("张三1");
|
||||
// 跳过乐观锁
|
||||
OptimisticLockManager.execWithoutOptimisticLock(() -> accountMapper.update(account));
|
||||
accountMapper.selectAll().forEach(System.out::println);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Db + Row 工具类
|
||||
|
||||
Db + Row 工具类,提供了在 Entity 实体类之外的数据库操作能力。使用 Db + Row 时,无需对数据库表进行映射, Row 是一个 HashMap 的子类,相当于一个通用的 Entity。以下为 Db + Row 的一些示例:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user