首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > Java Web开发 >

Spring分布式事宜在service中无法动态切换数据源

2013-08-13 
Spring分布式事务在service中无法动态切换数据源Spring分布式事务在service中无法切换数据源项目采用的是s

Spring分布式事务在service中无法动态切换数据源
Spring分布式事务在service中无法切换数据源
项目采用的是struts2+spring+ibatis架构,下面是关键部分代码:

applicationContext.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
   default-autowire="byName" default-lazy-init="false">
    
<context:component-scan base-package="com.ssi.*" />
<!-- 属性文件读入 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value>
</list>
</property>
</bean>
<!-- JTA 数据源配置 -->
<bean id="center" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/center</value>
</property>
<property name="xaDataSourceClassName">
<value>${jta.driver.className}</value>
</property>
<property name="xaProperties">
<props>
<prop key="url">${center.jdbc.driver.url}</prop>
<prop key="user">${center.sql.user.name}</prop>
<prop key="password">${center.sql.user.password}</prop>
</props>
</property>
<property name="testQuery" value="select 1" />
<property name="poolSize">


<value>${poolsize}</value>
</property>
<property name="maxPoolSize">
<value>${maxPoolSize}</value>
</property>
<property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
</bean>

<bean id="db1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/db1</value>
</property>
<property name="xaDataSourceClassName">
<value>${jta.driver.className}</value>
</property>
<property name="xaProperties">
<props>
<prop key="url">${db1.jdbc.driver.url}</prop>
<prop key="user">${company.sql.user.name}</prop>
<prop key="password">${company.sql.user.password}</prop>
</props>
</property>
<property name="testQuery" value="select 1" />
<property name="poolSize">
<value>${poolsize}</value>
</property>
<property name="maxPoolSize">
<value>${maxPoolSize}</value>
</property>
<property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
</bean>
<bean id="db2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>mysql/db2</value>
</property>
<property name="xaDataSourceClassName">
<value>${jta.driver.className}</value>
</property>
<property name="xaProperties">
<props>
<prop key="url">${db2.jdbc.driver.url}</prop>
<prop key="user">${company.sql.user.name}</prop>
<prop key="password">${company.sql.user.password}</prop>
</props>
</property>
<property name="testQuery" value="select 1" />
<property name="poolSize">
<value>${poolsize}</value>
</property>
<property name="maxPoolSize">
<value>${maxPoolSize}</value>
</property>
<property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
</bean>

<bean id="dataSource" class="com.ssi.datasource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="db1" value-ref="db1" />


<entry key="db2" value-ref="db2" />
<entry key="center" value-ref="center" />
</map>
</property>
<property name="defaultTargetDataSource" ref="center" />
</bean>

<!-- 配置sqlMapclient -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:ibatis-sqlmap-config.xml" />
<property name="dataSource" ref="dataSource" />
</bean>

 

<!-- 支持 @AspectJ 标记-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

<!-- 配置JTA的事务管理器 -->   
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"    init-method="init" destroy-method="close">   
        <property name="forceShutdown" value="true" />   
    </bean>   
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">   
        <property name="transactionTimeout" value="300" />   
    </bean>   
    <bean id="springTransactionManager"  class="org.springframework.transaction.jta.JtaTransactionManager">   
        <property name="transactionManager" ref="atomikosTransactionManager" />   
        <property name="userTransaction" ref="atomikosUserTransaction" />   
    </bean>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="springTransactionManager">
<tx:attributes>
 <tx:method name="*" rollback-for="Exception,RuntimeException,com.ssi.exception.SystemException" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>



<!-- 以AspectJ方式 定义 AOP --> 

<aop:config>
<aop:advisor pointcut="execution(* com.ssi.service..*Service*.*(..))" advice-ref="txAdvice" />
</aop:config>

</beans>



UserServiceImpl.java:
public class UserServiceImpl implements IUserService {
@Resource


private IUserDao userDao;
public void addUser(User user) throws Exception{
DbContextHolder.setDbType("db1");   
userDao.addUser(user);
DbContextHolder.setDbType("db2");   
userDao.addUser(user);
DbContextHolder.setDbType("center");   
userDao.addUser(user);
}

public void addUser2(User user,int status)  throws Exception{
userDao.addUser(user);
if(status==1){
System.out.println(1/0);
}
}
}


UserDaoImpl.java:
@Repository("userDao")
public class UserDaoImpl extends SqlMapClientDaoSupport implements IUserDao {
@Override
public Integer addUser(User user) throws Exception{
return (Integer) this.getSqlMapClient().insert("User.insert", user);
}

}


DynamicDataSource.java:
public class DynamicDataSource extends AbstractRoutingDataSource {

static Logger log = Logger.getLogger(DynamicDataSource.class);

protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}

}


DbContextHolder.java:
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal();

public static void setDbType(String dbType) {
contextHolder.set(dbType);
}

public static String getDbType() {
return (String) contextHolder.get();
}

public static void clearDbType() {
contextHolder.remove();
}

}

三个数据库:dbcenter、db1、db2 表结构均相同 

脚本:
DROP TABLE IF EXISTS `tb_user`;

CREATE TABLE `tb_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(20) DEFAULT NULL,
  `password` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

单元测试:
public class JunitTest{  
public ApplicationContext cxt;
@Test
public void init() throws Exception{
cxt = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
testInsertUser1();
testInsertUser2();
}


private void testInsertUser1() throws Exception{


IUserService userService = (IUserService)cxt.getBean("userService");
User user = new User();
user.setUserName("user1");
user.setPassword("0");
userService.addUser(user);
}

private void testInsertUser2() throws Exception{
IUserService userService = (IUserService)cxt.getBean("userService");
User user = new User();
user.setUserName("user2");
user.setPassword("0");

DbContextHolder.setDbType("db1");   
userService.addUser2(user,0);
DbContextHolder.setDbType("db2");   
userService.addUser2(user,0);
DbContextHolder.setDbType("center");   
userService.addUser2(user,1);
}
}  



结果:

testInsertUser1中在service方法中切换数据源,结果不会切换,始终都会将数据保存在db1中(不是很明白)

testInsertUser2中在单元测试方法中切换数据源,会切换,但事务不会回滚,即db1和db2会保存成功,db3不会成功(这点会明白:英文事务配置在service中,在单元测试中切换数据源事务不会回滚)


疑问:如何在service方法中动态切换数据源,并且保证事务? spring分布式 动态切换数据源 atomikos? jta
[解决办法]
可以参考下这个文章
http://blog.csdn.net/boy00fly/article/details/4772066
[解决办法]
我觉得aop做数据源切换比较靠谱。

热点排行