2011-09-05 132 views
1

对不起,我的英文不好。我写的实施AbstractRoutingDataSource:动态数据源路由

public class DatabaseRoutingDataSource extends AbstractRoutingDataSource{ 

    @Override 
    protected Object determineCurrentLookupKey() {  
     return DatabaseContextHolder.getDatabaseType(); 
    } 

} 

我创造了新的类的数据库之间进行切换:

public class DatabaseContextHolder { 

    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<DatabaseType>(); 

    public static void setDatabaseType(DatabaseType databaseType) { 
     contextHolder.set(databaseType); 
    } 

    public static DatabaseType getDatabaseType() { 
     return (DatabaseType) contextHolder.get(); 
    } 

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

其中数据库类型是:

public enum DatabaseType { 
    MAIN, 
    BACKUP 
} 
在我的beans.xml

<bean id="mainDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="java:/jdbc/DBMIDS"/> 
</bean> 
<bean id="backupDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="java:/jdbc/DBMIDS2"/> 
</bean> 
<bean id="dataSource" class="DatabaseRoutingDataSource"> 
    <property name="targetDataSources"> 
     <map key-type="DatabaseType"> 
      <entry key="MAIN" value-ref="mainDataSource"/> 
      <entry key="BACKUP" value-ref="backupDataSource"/> 
     </map> 
    </property> 
    <property name="defaultTargetDataSource" ref="mainDataSource"/> 
</bean> 
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
<bean id="databaseTarget" class="DatabaseBean"> 
    <property name="dataSource" ref="dataSource"/> 
</bean> 
<bean id="database" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="transactionManager"/> 
    <property name="target" ref="databaseTarget"/> 
    <property name="proxyInterfaces"> 
     <value>Database</value> 
    </property> 
    <property name="transactionAttributes"> 
     <props> 
      <prop key="*">PROPAGATION_REQUIRED,-MyException</prop> 
     </props> 
    </property> 
</bean> 

现在,当我试图改变数据源在我的DAO:

public class DatabaseBean extends JdbcDaoSupport implements Database 
    public void myMethod() { 
     DatabaseContextHolder.setDatabaseType(DatabaseType.MAIN); 
     getJdbcTemplate().execute("INSERT INTO test(test) VALUES('test')");  
     DatabaseContextHolder.setDatabaseType(DatabaseType.BACKUP); 
     getJdbcTemplate().execute("INSERT INTO test(test) VALUES('test')");   
} 

determineCurrentLookupKey()被调用一次,第一次执行时getJdbcTemplate(),和数据源不切换。

回答

5

Spring的JDBC事务处理管理的一部分是在事务启动时将连接绑定到线程。在事务结束并且连接未被绑定之前,在同一数据源上的每个持久性操作将使用相同的连接。由于您使用单个数据源来屏蔽其他两个数据源,因此您只能获得一个连接。如果明确使用了两个单独的数据源,则每个数据源都将被视为单独的资源,并且将启动一个单独的连接并绑定到每个线程。参考指南中的"Synchronizing resources with transactions"至少暗示了当您使用JdbcDaoSupport和JdbcTemplate进行事务时隐藏的内容。

+1

这可能与一个AbstractRoutingDataSource有关吗?有同样的问题。 – Vedran

1

在方法调用之前,您应该调用DatabaseContextHolder.setDatabaseType(DatabaseType.MAIN)。一旦事务开始,Hibernate会查找连接。在你的情况下,事务是在DatabaseContextHolder.setDatabaseType(DatabaseType.MAIN)执行之前启动的。而且一旦事务已经开始架构就不能改变。您的实现是正确的尝试在方法调用之前设置DatabaseType,即在事务启动之前。