最近項目中需要用到多數(shù)據(jù)源管,數(shù)據(jù)訪問層采用的是JDBCTemplate去做的,一開始是在數(shù)據(jù)源這塊做了一個多數(shù)據(jù)源的操作類,通過攔截器注解去動態(tài)賦值指定的數(shù)據(jù)源操作,這種做法在查詢中是沒有問題的,但是DML操作時,會出現(xiàn)問題:事物中無法動態(tài)操作數(shù)據(jù)源,導(dǎo)致很多操作指針對第一個庫崭倘。查詢資料的時候發(fā)現(xiàn):
DataSourceTransactionManager這個事物管理類只針對單個數(shù)據(jù)源進行事物控制.
解決的方案也有多種,這里只提及我實踐過的兩種:
- 開啟多個數(shù)據(jù)源去進行操作,這種是可以自己去實現(xiàn)的.
- 利用JTA和Atomikos的多數(shù)據(jù)源分布事物管理
方案一:
思路:
- 自定義一個注解類,通過傳遞參數(shù)告訴這個業(yè)務(wù)需要用到哪幾個數(shù)據(jù)源
- 然后仿照Spring中的@Transactional的實現(xiàn)模式,去構(gòu)建一個集合來開啟多個事物
- 然后通過攔截器去動態(tài)分配業(yè)務(wù)給這個集合告訴他,要開幾個事物
代碼:
applicationContext-datasource.xml
<!-- 數(shù)據(jù)源1 -->
<bean id="mvp" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${mvp.driverClassName}"></property>
<property name="url" value="${mvp.url}"></property>
<property name="username" value="${mvp.username}"></property>
<property name="password" value="${mvp.password}"></property>
<property name="filters" value="${mvp.filters}"/>
<!-- 配置初始化大小翼岁、最小、最大 -->
<property name="initialSize" value="${mvp.initialSize}"/>
<property name="minIdle" value="${mvp.minIdle}"/>
<property name="maxActive" value="${mvp.maxActive}"/>
<!-- 配置獲取連接等待超時的時間 -->
<property name="maxWait" value="${mvp.maxWait}"/>
<!-- 配置間隔多久才進行一次檢測司光,檢測需要關(guān)閉的空閑連接琅坡,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${mvp.timeBetweenEvictionRunsMillis}"/>
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${mvp.minEvictableIdleTimeMillis}"/>
<property name="testWhileIdle" value="${mvp.testWhileIdle}"/>
<property name="testOnBorrow" value="${mvp.testOnBorrow}"/>
<property name="testOnReturn" value="${mvp.testOnReturn}"/>
<!-- 打開PSCache残家,并且指定每個連接上PSCache的大小 -->
<property name="poolPreparedStatements" value="${mvp.poolPreparedStatements}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
<property name="removeAbandoned" value="${mvp.removeAbandoned}" />
<property name="removeAbandonedTimeout" value="${mvp.removeAbandonedTimeout}" />
<property name="maxOpenPreparedStatements" value="${mvp.maxOpenPreparedStatements}" />
<property name="logAbandoned" value="${mvp.logAbandoned}"/>
<property name="queryTimeout" value="${mvp.querytimeout}"/>
<property name="validationQuery" value="${mvp.validationQuery}"/>
</bean>
<!-- 數(shù)據(jù)源2 -->
<bean id="system" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${system.driverClassName}"></property>
<property name="url" value="${system.url}"></property>
<property name="username" value="${system.username}"></property>
<property name="password" value="${system.password}"></property>
<property name="filters" value="${system.filters}"/>
<!-- 配置初始化大小榆俺、最小、最大 -->
<property name="initialSize" value="${system.initialSize}"/>
<property name="minIdle" value="${system.minIdle}"/>
<property name="maxActive" value="${system.maxActive}"/>
<!-- 配置獲取連接等待超時的時間 -->
<property name="maxWait" value="${system.maxWait}"/>
<!-- 配置間隔多久才進行一次檢測坞淮,檢測需要關(guān)閉的空閑連接茴晋,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${system.timeBetweenEvictionRunsMillis}"/>
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${system.minEvictableIdleTimeMillis}"/>
<property name="testWhileIdle" value="${system.testWhileIdle}"/>
<property name="testOnBorrow" value="${system.testOnBorrow}"/>
<property name="testOnReturn" value="${system.testOnReturn}"/>
<!-- 打開PSCache回窘,并且指定每個連接上PSCache的大小 -->
<property name="poolPreparedStatements" value="${system.poolPreparedStatements}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
<property name="removeAbandoned" value="${system.removeAbandoned}" />
<property name="removeAbandonedTimeout" value="${system.removeAbandonedTimeout}" />
<property name="maxOpenPreparedStatements" value="${system.maxOpenPreparedStatements}" />
<property name="logAbandoned" value="${system.logAbandoned}"/>
<property name="queryTimeout" value="${system.querytimeout}"/>
<property name="validationQuery" value="${system.validationQuery}"/>
</bean>
<!-- dao層訪問處理工具 分別指定兩個不同的datasource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="default"/>
</bean>
<bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="system"/>
</bean>
applicationContext-service.xml 業(yè)務(wù)層配置文件
<!-- 一些掃描包或者其他定義的業(yè)務(wù)類 我這邊就不列入了 -->
<!-- 多數(shù)據(jù)源切面類 -->
<bean id="multiTransactionalAspect" class="com.elab.execute.utils.MultiTransactionalAspect"/>
多數(shù)據(jù)Aop配置
<aop:config proxy-target-class="true">
<!-- 定義一個切入點表達式: 攔截哪些方法 -->
<aop:aspect ref="multiTransactionalAspect">
<aop:pointcut id="pointUserMgr" expression="execution(* com.test.execute.services..*(..))"/>
<aop:around method="around" pointcut-ref="pointUserMgr" />
</aop:aspect>
</aop:config>
注解類 :
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MultiTransactional {
String[] values() default "";
// TODO 當(dāng)然你如果想做的更完善一點,可以參考@Transactional這個類,自己去做,什么傳播機制啊,隔離級別啊 等等,思路是一樣的
}
注解實現(xiàn)類 - 其實這里差不多都是沿用Spring的事物實現(xiàn)方式:
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.lang.reflect.Method;
import java.util.Stack;
/**
* @Description: 多數(shù)據(jù)源動態(tài)管理
* @Author: Liukx on 2017/7/28 - 16:41
*/
@Component("multiTransactionalAspect")
public class MultiTransactionalAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private SpringUtils springUtils;
/**
* 切入點
*
* @param point
* @return
* @throws Throwable
*/
public Object around(ProceedingJoinPoint point) throws Throwable {
Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack = new Stack<DataSourceTransactionManager>();
Stack<TransactionStatus> transactionStatuStack = new Stack<TransactionStatus>();
try {
Object target = point.getTarget();
String method = point.getSignature().getName();
Class classz = target.getClass();
Class[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
Method m = classz.getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(MultiTransactional.class)) {
MultiTransactional multiTransactional = m.getAnnotation(MultiTransactional.class);
if (!openTransaction(dataSourceTransactionManagerStack, transactionStatuStack, multiTransactional)) {
return null;
}
Object ret = point.proceed();
commit(dataSourceTransactionManagerStack, transactionStatuStack);
return ret;
}
Object ret = point.proceed();
return ret;
} catch (Exception e) {
rollback(dataSourceTransactionManagerStack, transactionStatuStack);
logger.error(String.format(
"MultiTransactionalAspect, method:%s-%s occors error:", point
.getTarget().getClass().getSimpleName(), point
.getSignature().getName()), e);
throw e;
}
}
/**
* 打開一個事物方法
*
* @param dataSourceTransactionManagerStack
* @param transactionStatuStack
* @param multiTransactional
* @return
*/
private boolean openTransaction(
Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,
Stack<TransactionStatus> transactionStatuStack,
MultiTransactional multiTransactional) {
// 獲取注解中要打開的事物類型
String[] transactionMangerNames = multiTransactional.values();
if (ArrayUtils.isEmpty(multiTransactional.values())) {
return false;
}
for (String beanName : transactionMangerNames) {
// 創(chuàng)建一個新的事物管理器,用來管理接下來要用到的事物
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
// 根據(jù)注解中獲取到的數(shù)據(jù)標(biāo)識,從spring容器中去查找對應(yīng)的數(shù)據(jù)源
DruidDataSource dataSource = (DruidDataSource) springUtils.getBean(beanName);
//然后交給事物管理器去管理
dataSourceTransactionManager.setDataSource(dataSource);
// 定義一個新的事物定義
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
// 設(shè)置一個默認的事物傳播機制,注意的是這里可以拓展注解中沒有用到的屬性
// defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(defaultTransactionDefinition);
// 將這個事物的定義放入Stack中
/**
* 其中為什么要用Stack來保存TransactionManager和TransactionStatus呢诺擅?
* 那是因為Spring的事務(wù)處理是按照LIFO/stack behavior的方式進行的。
* 如若順序有誤啡直,則會報錯:
*/
transactionStatuStack.push(transactionStatus);
dataSourceTransactionManagerStack
.push(dataSourceTransactionManager);
}
return true;
}
/**
* 提交事物方法實現(xiàn)
*
* @param dataSourceTransactionManagerStack
* @param transactionStatuStack
*/
private void commit(
Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,
Stack<TransactionStatus> transactionStatuStack) {
while (!dataSourceTransactionManagerStack.isEmpty()) {
dataSourceTransactionManagerStack.pop().commit(
transactionStatuStack.pop());
}
}
/**
* 回滾事物方法實現(xiàn)
*
* @param dataSourceTransactionManagerStack
* @param transactionStatuStack
*/
private void rollback(
Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,
Stack<TransactionStatus> transactionStatuStack) {
while (!dataSourceTransactionManagerStack.isEmpty()) {
dataSourceTransactionManagerStack.pop().rollback(
transactionStatuStack.pop());
}
}
}
service 1 - 2 :
/**
* 一些實驗性Demo接口
*
* @author Liukx
* @create 2017-07-28 10:11
* @email liukx@elab-plus.com
**/
public interface IDemoService {
public void mvpManage() throws Exception;
}
/**
* 一些實驗性Demo接口
*
* @author Liukx
* @create 2017-07-28 10:11
* @email liukx@elab-plus.com
**/
public interface IDemoService2 {
public void beidouMange() throws CoreException;
}
service實現(xiàn)類:
/**
* 實現(xiàn)性Demo接口實現(xiàn)
*
* @author Liukx
* @create 2017-07-28 10:12
* @email liukx@elab-plus.com
**/
@Service("demoService")
public class DemoServiceImpl implements IDemoService {
@Autowired
@Qualifier("demoTestDao")
private IDemoTestDao testDao;
@Autowired
private IDemoService2 demoService2;
// @Autowired
// private DataSourceTransactionManager transactionManager;
//TODO 這個注解很關(guān)鍵 - 必須是這個注解才能被攔截器攔截到
@MultiTransactional(values = {DataSource.mvp, DataSource.system})
public void mvpManage() throws CoreException {
System.out.println("=====================開始處理MVP");
testDao.insert();
List<Map<String, Object>> select = testDao.select();
System.out.println("===============>>>>>>>>>>>>>>>>>" + select.size());
System.out.println("=====================結(jié)束處理MVP");
demoService2.beidouMange();
// System.out.println("業(yè)務(wù)處理完成,開始報錯");
int i = 1 / 0;
}
}
service 2實現(xiàn)
/**
* @author Liukx
* @create 2017-07-28 11:07
* @email liukx@elab-plus.com
**/
@Service("demo2")
public class DemoServiceImpl2 implements IDemoService2 {
@Autowired
@Qualifier("beidouTestDao")
private IDemoTestDao testDao;
@MultiTransactional(values = DataSource.system)
public void beidouMange() throws CoreException {
System.out.println("=====================開始處理北斗");
testDao.insert();
List<Map<String, Object>> select = testDao.select();
System.out.println("========================================>" + select.size());
System.out.println("=====================結(jié)束處理北斗");
}
}
dao實現(xiàn): 這里就只列入實現(xiàn)類
@Repository("beidouTestDao")
public class BeiDouTestDaoImpl extends BaseDao implements IDemoTestDao {
/**
* 我們這塊目前是有一些封裝的,不過你不用太關(guān)注;
* 你只要把對應(yīng)的數(shù)據(jù)源指定好就行了
*/
@Autowired
@Qualifier("jdbcTemplate2")
public JdbcTemplate jdbcTemplate;
public int insert() throws CoreException {
LinkedHashMap<String, Object> params = new LinkedHashMap<>();
params.put("name", "某某某" + RandomUtils.randomNum(3));
params.put("created", new Date());
return executeInsert("test.insert", params);
}
@Override
public List<Map<String, Object>> select() throws CoreException {
return findList("test.findAll", new LinkedHashMap<String, Object>());
}
}
@Repository("demoTestDao")
public class DemoTestDaoImpl extends BaseDao implements IDemoTestDao {
/**
* 我們這塊目前是有一些封裝的,不過你不用太關(guān)注;
* 你只要把對應(yīng)的數(shù)據(jù)源指定好就行了
*/
@Autowired
@Qualifier("jdbcTemplate")
public JdbcTemplate jdbcTemplate;
public int insert() throws CoreException {
LinkedHashMap<String, Object> params = new LinkedHashMap<>();
params.put("name", "某某某" + RandomUtils.randomNum(2));
params.put("created", new Date());
return executeInsert("test.insert", params);
}
public List<Map<String, Object>> select() throws CoreException {
return findList("test.findAll", new LinkedHashMap<String, Object>());
}
}
另外有一個動態(tài)獲取bean的工具類:
@Component
public class SpringUtils implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public Object getBean(String beanId) {
return applicationContext.getBean(beanId);
}
}
PS : 這個方案會存在一定的問題 -> 就是如果你下一個另一個數(shù)據(jù)庫操作的業(yè)務(wù)serivce方法中如果定義了@Transactional它將會又開啟一個事物去執(zhí)行...
方案2 : 利用JTA+Atomikios實現(xiàn)事物管理,業(yè)務(wù)層代碼和上面差不多,主要是配置文件這塊.
applicationContext-datasource.xml
<!-- 父配置 -->
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close" abstract="true">
<property name="xaDataSourceClassName"
value="com.alibaba.druid.pool.xa.DruidXADataSource"/> <!-- SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana] -->
<property name="poolSize" value="10"/>
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="30"/>
<property name="borrowConnectionTimeout" value="60"/>
<property name="reapTimeout" value="20"/>
<property name="maxIdleTime" value="60"/>
<property name="maintenanceInterval" value="60"/>
<property name="loginTimeout" value="60"/>
<property name="testQuery" value="${default.validationQuery}"/>
</bean>
<!-- 主配置 -->
<bean id="masterDataSource" parent="abstractXADataSource">
<property name="uniqueResourceName" value="masterDB"/>
<property name="xaProperties">
<props>
<prop key="driverClassName">${default.driverClassName}</prop>
<prop key="url">${default.url}</prop>
<prop key="password">${default.password}</prop>
<!-- <prop key="user">${jdbc.username}</prop> --> <!-- mysql -->
<prop key="username">${default.username}</prop> <!-- durid -->
<prop key="initialSize">0</prop>
<prop key="maxActive">20</prop> <!-- 若不配置則代碼執(zhí)行"{dataSource-1} inited"此處停止 -->
<prop key="minIdle">0</prop>
<prop key="maxWait">60000</prop>
<prop key="validationQuery">${default.validationQuery}</prop>
<prop key="testOnBorrow">false</prop>
<prop key="testOnReturn">false</prop>
<prop key="testWhileIdle">true</prop>
<prop key="removeAbandoned">true</prop>
<prop key="removeAbandonedTimeout">1800</prop>
<prop key="logAbandoned">true</prop>
<prop key="filters">mergeStat</prop>
</props>
</property>
</bean>
<bean id="slaveDataSource" parent="abstractXADataSource">
<property name="uniqueResourceName" value="slaveDB"/>
<property name="xaProperties">
<props>
<prop key="driverClassName">${system.driverClassName}</prop>
<prop key="url">${system.url}</prop>
<prop key="password">${system.password}</prop>
<!-- <prop key="user">${jdbc.username}</prop> -->
<prop key="username">${system.username}</prop>
<prop key="initialSize">0</prop>
<prop key="maxActive">20</prop>
<prop key="minIdle">0</prop>
<prop key="maxWait">60000</prop>
<prop key="validationQuery">${system.validationQuery}</prop>
<prop key="testOnBorrow">false</prop>
<prop key="testOnReturn">false</prop>
<prop key="testWhileIdle">true</prop>
<prop key="removeAbandoned">true</prop>
<prop key="removeAbandonedTimeout">1800</prop>
<prop key="logAbandoned">true</prop>
<prop key="filters">mergeStat</prop>
</props>
</property>
</bean>
<!-- 將數(shù)據(jù)源交給數(shù)據(jù)庫操作模版工具 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="masterDataSource"/>
</bean>
<bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="slaveDataSource"/>
</bean>
applicationContext-atomikos.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd" default-lazy-init="true">
<description>配置事物</description>
<!-- atomikos事務(wù)管理器 -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
destroy-method="close">
<property name="forceShutdown">
<value>true</value>
</property>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300"/>
</bean>
<!-- spring 事務(wù)管理器 -->
<bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager"/>
<property name="userTransaction" ref="atomikosUserTransaction"/>
<!-- 必須設(shè)置烁涌,否則程序出現(xiàn)異常 JtaTransactionManager does not support custom isolation levels by default -->
<property name="allowCustomIsolationLevels" value="true"/>
</bean>
<aop:config proxy-target-class="true">
<aop:pointcut id="pointUserMgr" expression="execution(* com.elab.execute.services..*(..))"/>
<aop:advisor pointcut-ref="pointUserMgr" advice-ref="txAdvice"/>
</aop:config>
<!-- 通過切入點去實現(xiàn)事物觸發(fā)機制 -->
<tx:advice id="txAdvice" transaction-manager="springTransactionManager">
<tx:attributes>
<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
<tx:method name="has*" propagation="REQUIRED" read-only="true"/>
<tx:method name="locate*" propagation="REQUIRED" read-only="true"/>
<tx:method name="mvp*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="beidou*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<!--<tx:annotation-driven transaction-manager="springTransactionManager"-->
<!--proxy-target-class="true"></tx:annotation-driven>-->
</beans>
pom.xml
<!-- JTA -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>atomikos-util</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.2</version>
</dependency>
業(yè)務(wù)層代碼和方案一的差不多,看了一下大概的思路:
在調(diào)用被攔截器匹配的方法時,開啟一個新的事物
當(dāng)執(zhí)行到DML操作時,會獲取他對應(yīng)的數(shù)據(jù)源,并且會和當(dāng)前線程的事物管理器中的數(shù)據(jù)源進行匹配,如果不存在,則到連接池中獲取一個新的連接,并把這個連接放入當(dāng)前線程的事物管理器中進行管理
-
當(dāng)所有業(yè)務(wù)執(zhí)行完畢,并且沒有報錯的時候,會執(zhí)行一個兩階段提交的方式
PREPARE TRANSACTION transaction_id PREPARE TRANSACTION 為當(dāng)前事務(wù)的兩階段提交做準(zhǔn)備。 在命令之后酒觅,事務(wù)就不再和當(dāng)前會話關(guān)聯(lián)了撮执;它的狀態(tài)完全保存在磁盤上, 它提交成功有非常高的可能性舷丹,即使是在請求提交之前數(shù)據(jù)庫發(fā)生了崩潰也如此抒钱。這條命令必須在一個用BEGIN顯式開始的事務(wù)塊里面使用。
COMMIT PREPARED transaction_id 提交已進入準(zhǔn)備階段的ID為transaction_id的事務(wù)
ROLLBACK PREPARED transaction_id 回滾已進入準(zhǔn)備階段的ID為transaction_id的事務(wù)
推薦使用第二種方式,因為它有比較好的連接池以及相對完善的機制,第一種考慮的情況比較少,會出現(xiàn)問題,當(dāng)然,你如果愿意折騰自己寫一套,可以參考一下..
以上為個人學(xué)習(xí)參考,有什么不足的地方歡迎指正.
參考博客:
Mybatis + JTA http://blog.csdn.net/zmx729618/article/details/54344296
分布式事物提交以及JTA的概念 : http://www.jasongj.com/big_data/two_phase_commit/
JTA一些實現(xiàn)原理:https://www.ibm.com/developerworks/cn/java/j-lo-jta/
兩階段事物提交:http://m635674608.iteye.com/blog/2322853