mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-08 01:28:24 +08:00
TransactionalManager add Propagation support
This commit is contained in:
parent
745c89683e
commit
9f433566be
@ -22,7 +22,7 @@ import com.mybatisflex.core.query.CPI;
|
||||
import com.mybatisflex.core.query.QueryCondition;
|
||||
import com.mybatisflex.core.query.QueryTable;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.transaction.TransactionContext;
|
||||
import com.mybatisflex.core.transaction.Propagation;
|
||||
import com.mybatisflex.core.transaction.TransactionalManager;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.util.MapUtil;
|
||||
@ -563,31 +563,12 @@ public class Db {
|
||||
* @param supplier
|
||||
*/
|
||||
public static boolean tx(Supplier<Boolean> supplier) {
|
||||
//上一级事务的id,支持事务嵌套
|
||||
String higherXID = TransactionContext.getXID();
|
||||
try {
|
||||
String xid = TransactionalManager.startTransactional();
|
||||
Boolean success = false;
|
||||
boolean rollbacked = false;
|
||||
try {
|
||||
success = supplier.get();
|
||||
} catch (Exception e) {
|
||||
rollbacked = true;
|
||||
TransactionalManager.rollback(xid);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (success != null && success) {
|
||||
TransactionalManager.commit(xid);
|
||||
} else if (!rollbacked) {
|
||||
TransactionalManager.rollback(xid);
|
||||
}
|
||||
}
|
||||
return success != null && success;
|
||||
} finally {
|
||||
//恢复上一级事务
|
||||
if (higherXID != null) {
|
||||
TransactionContext.hold(higherXID);
|
||||
}
|
||||
}
|
||||
return tx(supplier, Propagation.REQUIRED);
|
||||
}
|
||||
|
||||
|
||||
public static boolean tx(Supplier<Boolean> supplier, Propagation propagation) {
|
||||
Boolean result = TransactionalManager.exec(supplier, propagation);
|
||||
return result != null && result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, 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.transaction;
|
||||
|
||||
/**
|
||||
* 事务的传递方式,参考 spring
|
||||
*/
|
||||
public enum Propagation {
|
||||
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则创建新的事务
|
||||
REQUIRED(0),
|
||||
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则已非事务的方式运行
|
||||
SUPPORTS(1),
|
||||
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则抛出异常
|
||||
MANDATORY(2),
|
||||
|
||||
//始终以新事物的方式运行,若存在当前事务,则暂停(挂起)当前事务。
|
||||
REQUIRES_NEW(3),
|
||||
|
||||
//以非事物的方式运行,若存在当前事务,则暂停(挂起)当前事务。
|
||||
NOT_SUPPORTED(4),
|
||||
|
||||
//以非事物的方式运行,若存在当前事务,则抛出异常。
|
||||
NEVER(5),
|
||||
|
||||
//如果存在当前事务,则在嵌套事务中执行,否则行为类似于 PROPAGATION_REQUIRED
|
||||
NESTED(6),
|
||||
;
|
||||
|
||||
private int value;
|
||||
|
||||
Propagation(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023, 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.transaction;
|
||||
|
||||
public class TransactionException extends RuntimeException {
|
||||
|
||||
public TransactionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TransactionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,6 +23,7 @@ import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 事务管理器
|
||||
@ -59,6 +60,90 @@ public class TransactionalManager {
|
||||
}
|
||||
|
||||
|
||||
public static Boolean exec(Supplier<Boolean> supplier, Propagation propagation) {
|
||||
//上一级事务的id,支持事务嵌套
|
||||
String currentXID = TransactionContext.getXID();
|
||||
try {
|
||||
switch (propagation) {
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则创建新的事务
|
||||
case REQUIRED:
|
||||
if (currentXID != null) {
|
||||
return supplier.get();
|
||||
} else {
|
||||
return execNewTransactional(supplier);
|
||||
}
|
||||
|
||||
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则已非事务的方式运行
|
||||
case SUPPORTS:
|
||||
return supplier.get();
|
||||
|
||||
|
||||
//若存在当前事务,则加入当前事务,若不存在当前事务,则已非事务的方式运行
|
||||
case MANDATORY:
|
||||
if (currentXID != null) {
|
||||
return supplier.get();
|
||||
} else {
|
||||
throw new TransactionException("No existing transaction found for transaction marked with propagation 'mandatory'");
|
||||
}
|
||||
|
||||
|
||||
//始终以新事物的方式运行,若存在当前事务,则暂停(挂起)当前事务。
|
||||
case REQUIRES_NEW:
|
||||
return execNewTransactional(supplier);
|
||||
|
||||
|
||||
//以非事物的方式运行,若存在当前事务,则暂停(挂起)当前事务。
|
||||
case NOT_SUPPORTED:
|
||||
if (currentXID != null) {
|
||||
TransactionContext.release();
|
||||
}
|
||||
return supplier.get();
|
||||
|
||||
|
||||
//以非事物的方式运行,若存在当前事务,则抛出异常。
|
||||
case NEVER:
|
||||
if (currentXID != null) {
|
||||
throw new TransactionException("Existing transaction found for transaction marked with propagation 'never'");
|
||||
}
|
||||
return supplier.get();
|
||||
|
||||
|
||||
//暂时不支持这种事务传递方式
|
||||
//default 为 nested 方式
|
||||
default:
|
||||
throw new TransactionException("Transaction manager does not allow nested transactions");
|
||||
|
||||
}
|
||||
} finally {
|
||||
//恢复上一级事务
|
||||
if (currentXID != null) {
|
||||
TransactionContext.hold(currentXID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean execNewTransactional(Supplier<Boolean> supplier) {
|
||||
String xid = TransactionalManager.startTransactional();
|
||||
Boolean success = false;
|
||||
boolean rollbacked = false;
|
||||
try {
|
||||
success = supplier.get();
|
||||
} catch (Exception e) {
|
||||
rollbacked = true;
|
||||
TransactionalManager.rollback(xid);
|
||||
throw new TransactionException(e.getMessage(), e);
|
||||
} finally {
|
||||
if (success != null && success) {
|
||||
TransactionalManager.commit(xid);
|
||||
} else if (!rollbacked) {
|
||||
TransactionalManager.rollback(xid);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
public static Connection getConnection(String xid, String ds) {
|
||||
Map<String, Connection> connections = CONNECTION_HOLDER.get().get(xid);
|
||||
return connections == null || connections.isEmpty() ? null : connections.get(ds);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user