mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-08 09:38:26 +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.QueryCondition;
|
||||||
import com.mybatisflex.core.query.QueryTable;
|
import com.mybatisflex.core.query.QueryTable;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
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 com.mybatisflex.core.transaction.TransactionalManager;
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
import org.apache.ibatis.util.MapUtil;
|
import org.apache.ibatis.util.MapUtil;
|
||||||
@ -563,31 +563,12 @@ public class Db {
|
|||||||
* @param supplier
|
* @param supplier
|
||||||
*/
|
*/
|
||||||
public static boolean tx(Supplier<Boolean> supplier) {
|
public static boolean tx(Supplier<Boolean> supplier) {
|
||||||
//上一级事务的id,支持事务嵌套
|
return tx(supplier, Propagation.REQUIRED);
|
||||||
String higherXID = TransactionContext.getXID();
|
}
|
||||||
try {
|
|
||||||
String xid = TransactionalManager.startTransactional();
|
|
||||||
Boolean success = false;
|
public static boolean tx(Supplier<Boolean> supplier, Propagation propagation) {
|
||||||
boolean rollbacked = false;
|
Boolean result = TransactionalManager.exec(supplier, propagation);
|
||||||
try {
|
return result != null && result;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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) {
|
public static Connection getConnection(String xid, String ds) {
|
||||||
Map<String, Connection> connections = CONNECTION_HOLDER.get().get(xid);
|
Map<String, Connection> connections = CONNECTION_HOLDER.get().get(xid);
|
||||||
return connections == null || connections.isEmpty() ? null : connections.get(ds);
|
return connections == null || connections.isEmpty() ? null : connections.get(ds);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user