我有2个客户端在tomcat中使用相同的基于Spring的REST应用程序。根据客户端,我需要在数据源和事务管理器之间进行选择。如何在运行时选择使用哪个事务管理器?
<bean id="First_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="${First_jdbc.url}" />
<property name="driverClassName" value="${First_jdbc.driverClassName}" />
<property name="username" value="${First_jdbc.username}" />
<property name="password" value="${First_jdbc.password}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<!-- <property name="defaultAutoCommit" value="false" /> -->
</bean>
<bean id="Second_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="${Second_jdbc.url}" />
<property name="driverClassName" value="${Second_jdbc.driverClassName}" />
<property name="username" value="${Second_jdbc.username}" />
<property name="password" value="${Second_jdbc.password}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<!-- <property name="defaultAutoCommit" value="false" /> -->
</bean>
<bean id="First_TransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
scope="singleton">
<property name="dataSource" ref="First_dataSource" />
<qualifier value="SC_TM"></qualifier>
</bean>
<bean id="Second_TransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
scope="singleton">
<property name="dataSource" ref="Second_dataSource" />
<qualifier value="Second_TM"></qualifier>
</bean>
在代码中如何在运行时选择@Transactional(&#34; ????&#34;)。 如果用org.springframework.jdbc.datasource.DataSourceTransactionManager不可能有其他方法吗?
答案 0 :(得分:0)
使用@Transactional
,您可以像这样指定事务管理器:
@Transactional("First_TransactionManager")
或
@Transactional("Second_TransactionManager")
取决于您要使用的是哪一个。确保在事务方法内部使用正确的实体管理器/会话工厂。那些您还必须使用@PersistenceContext("nameOfPersistenceUnit")
指定要注入的那个。
答案 1 :(得分:0)
我不知道你为什么要在2个事务管理器之间进行更改可能需要检查事务管理器链解决方案,但是如果你需要这个,你可以在Repo方法上添加@transactional并做2 Repos并管理它从服务层作为交换机,否则我相信可以使用AOP完成解决方案,但需要更多时间来考虑它。
答案 2 :(得分:0)
问题通过AOP解决。
根据您的业务规则选择以编程方式使用的数据源。就我而言,它是orgId
public class DataSourceProvider { @Autowired DataSource First_dataSource; @Autowired DataSource Second_dataSource;
public DataSource getDataSource(int orgId) {
if (orgId == Constants.BUSINESS_PARTY_1)
return Second_dataSource;
else
return First_dataSource;
}
public DataSource getFirst_dataSource() {
return First_dataSource;
}
public void setFirst_dataSource(DataSource First_dataSource) {
First_dataSource = First_dataSource;
}
public DataSource getSecond_dataSource() {
return Second_dataSource;
}
public void setSecond_dataSource(DataSource Second_dataSource) {
Second_dataSource = Second_dataSource;
}
}
AOP配置:
答案 3 :(得分:0)
<tx:advice id="First_txAdvice" transaction-manager="First_TransactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="First_daoimplOperation"
expression="execution(* in.company.common.service.CommonServiceImpl.*(..))" />
<aop:advisor advice-ref="First_txAdvice" pointcut-ref="First_daoimplOperation" />
</aop:config>
<tx:advice id="Second_txAdvice" transaction-manager="Second_TransactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="Second_daoimplOperation"
expression="execution(* in.company.common.service.CommonServiceImpl.*(..))" />
<aop:advisor advice-ref="Second_txAdvice" pointcut-ref="Second_daoimplOperation" />
</aop:config>
所有与数据库相关的服务都应该在匹配的切入点中,就像这样:in.company.common.service.CommonServiceImpl。*(..))
答案 4 :(得分:0)
考虑使用Spring提供的select case when c is null then p end as parent, c as child
from
(
select p, c from children
union all
select p, null from parents
)
order by p, c nulls first;
而不是沿着在多个事务管理器之间进行选择的路径。这将是一个更清洁的解决方案。
在此查看我对类似问题的回答:
https://stackoverflow.com/a/44167079/2200690