文章参考:https://www.cnblogs.com/shuaiandjun/p/8667815.html
项目框架是jdbcTemplat+spring+struts2,项目需求是需要在一个方法中实现多个数据库的访问,并实现多数据源的事务控制。可直接复制使用。
下面直接贴代码和解决方案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="datasource2016" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@*:1521/orcl" />
<property name="username" value="****" />
<property name="password" value="***" />
</bean>
<bean id="datasource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@*:1521/orcl" />
<property name="username" value="***" />
<property name="password" value="***" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource2016" />
</bean>
<bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource1" />
</bean>
<bean id="bgdDataSource1" class="com.bgd.platform.util.dao.BgdDataSource">
<property name="jdbcTemplate" ref="jdbcTemplate" />
<property name="transactionTemplate" ref="transactionTemplate" />
<property name="abstractBgdDBSql" ref="abstractBgdDBSql" />
</bean>
<bean id="bgdDataSourcefk" class="com.bgd.platform.util.dao.BgdDataSource">
<property name="jdbcTemplate" ref="jdbcTemplate1" />
<property name="transactionTemplate" ref="transactionTemplate1" />
<property name="abstractBgdDBSql" ref="abstractBgdDBSql" />
</bean>
<bean id="bgdDataSource" class="com.bgd.platform.util.dao.BgdDataSourceMulti">
<property name="defaultDataSource">
<ref bean="bgdDataSource1" />
</property>
<property name="dataSources">
<map>
<entry key="ql">
<ref bean="bgdDataSource1" />
</entry>
<entry key="fk">
<ref bean="bgdDataSourcefk" />
</entry>
</map>
</property>
</bean>
<bean id="bgdDataSourceKylin" class="com.bgd.platform.util.dao.BgdDataSourceKylin">
<property name="dataSourceKylin" ref="dataSourcekylin"/>
</bean>
<bean id="abstractBgdDBSql" class="com.bgd.platform.util.dao.BgdDBSqlOracle">
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource2016"/>
</bean>
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource1"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="transactionTemplate1" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager1" />
</bean>
<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="bgdDataSource"/>
<property name="transactionAttributes">
<props>
<!--
transactionAttributes属性可以设置事务处理的方式,事务隔离级别,是否只读三个属性,用逗号隔开
事务隔离级别各数据库系统不完全支持,一般不设置,用默认的即可
事务处理选项有如下几个:(前面2个常用)
PROPAGATION_REQUIRED - 需要事务处理。如果当前不存在事务环境,则创建一个
PROPAGATION_SUPPORTS - 如果当前存在事务环境,则作为其中的一部分。如果不存在,则按非事务方式执行
PROPAGATION_REQUIRES_NEW - 需要事务处理。并总是开启一个新事务。如果已经存在事务环境,则挂起之
PROPAGATION_MANDATORY - 执行到指定方法时,必须已经存在事务环境,否则出错
PROPAGATION_NEVER - 不支持事务操作,如果存在事务环境会出错
PROPAGATION_NOT_SUPPORTED - 不支持事务操作。如果存在事务,则挂起
-->
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="transactionProxy1" class="com.bgd.platform.util.dao.TransactionManagerIntercetor">
<property name="transactionManagerBeanNames">
<list>
<value>transactionManager</value>
<value>transactionManager1</value>
</list>
</property>
<property name="target" ref="bgdDataSource1"/>
</bean>
<bean id="transactionProxyMulti" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name="interceptorNames">
<list>
<value>transactionProxy1</value>
</list>
</property>
</bean>
</beans>
<bean name="menuManageBo" class="com.bgd.platform.sys.user.service.MenuManageService">
<property name="bgdDataSource" ref="bgdDataSource" />
</bean>
<bean id="menuManageService" parent="transactionProxyMulti">
<property name="target">
<ref bean="menuManageBo" />
</property>
</bean>
<bean name="menuManageAction" class="com.bgd.platform.sys.user.action.MenuManageAction">
<property name="menuManageService" ref="menuManageService"/>
</bean>
代理多个数据源代码:
package com.bgd.platform.util.dao;
import com.bgd.platform.util.service.SpringContextUtil;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.List;
import java.util.Stack;
public class TransactionManagerIntercetor implements MethodInterceptor {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
private List<String> transactionManagerBeanNames;
public void setTransactionManagerBeanNames(List transactionManagerBeanNames) {
this.transactionManagerBeanNames = transactionManagerBeanNames;
}
private boolean openTransaction(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,
Stack<TransactionStatus> transactionStatuStack) {
for (String beanName : transactionManagerBeanNames) {
DataSourceTransactionManager dataSourceTransactionManager = (DataSourceTransactionManager) SpringContextUtil.getBean(beanName);
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
transactionStatuStack.push(transactionStatus);
dataSourceTransactionManagerStack.push(dataSourceTransactionManager);
}
return true;
}
private void commit(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack, Stack<TransactionStatus> transactionStatuStack){
while (!dataSourceTransactionManagerStack.isEmpty()) {
dataSourceTransactionManagerStack.pop().commit(
transactionStatuStack.pop());
}
}
private void rollback(Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack,
Stack<TransactionStatus> transactionStatuStack){
while (!dataSourceTransactionManagerStack.isEmpty()) {
dataSourceTransactionManagerStack.pop().rollback(
transactionStatuStack.pop());
}
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Stack<DataSourceTransactionManager> dataSourceTransactionManagerStack = new Stack<DataSourceTransactionManager>();
Stack<TransactionStatus> transactionStatuStack = new Stack<TransactionStatus>();
Object retVal = null;
try {
if (!openTransaction(dataSourceTransactionManagerStack, transactionStatuStack)) {
return null;
}
retVal = invocation.proceed();
commit(dataSourceTransactionManagerStack, transactionStatuStack);
} catch(Exception e) {
rollback(dataSourceTransactionManagerStack, transactionStatuStack);
throw e;
}
return retVal;
}
}