如何在多租户 spring 引导程序中使用事务拦截器?
How to use transaction interceptor in a multi-tenant spring boot program?
我有一个 Spring Boot 2 + Hibernate 5 多租户应用程序,它连接到多个 oracle 数据库。当我使用 JpaRepository 时,一切正常,即在收到 http 请求后,'Interceptor' 检测到数据源并且 'MultiTenantConnectionProvider' 实现选择正确的数据源供 TransactionManager 使用。
问题是什么?
我想使用 TransactionInterceptor 来处理来自特定 bean(扩展 JdbcDaoSupport 或注入 JdbcDaoSupport 实现)的某些方法(带有方法名称)的事务。对不起,如果我解释得有点混乱。
但是对于每个 http 请求,该 bean 的数据源是不可变的(默认数据源)。而注入的存储库在正确的事务中对正确的数据源进行操作。
<bean id="txProxyTemplate" abstract="true"
depends-on="transactionManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="genericJdbcDao" parent="txProxyTemplate">
<property name="target">
<bean class="org.broker.dao.impl.BaseGenericJdbcDAOImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</property>
</bean>
谁能帮忙解决这个问题?
我终于解决了这个问题。按照代码部分:
@Bean("jdbcTemplate")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public JdbcTemplate jdbcTemplate(
@Qualifier("tenantIdentifierResolver") TenantIdentifierResolverImpl tenantResolver,
@Qualifier("tenantConnectionProvider") DataSourceMultiTenantConnectionProviderImpl dataSourceProvider) {
return new RhaJdbcTemplate(dataSourceProvider.selectDataSource(tenantResolver.resolveCurrentTenantIdentifier()));
}
@Bean(value = "transactionInterceptor")
public TransactionInterceptor transactionInterceptor(
@Qualifier("txProxyTemplateConfig") Properties txProxyTemplateConfig,
@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionAttributes(txProxyTemplateConfig);
transactionInterceptor.setTransactionManager(transactionManager);
return transactionInterceptor;
}
@Bean("genericJdbcDAO")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public ProxyFactoryBean genericJdbcDAO(
@Qualifier("jdbcTemplate") JdbcTemplate jdbcTemplate) throws ClassNotFoundException {
BaseGenericJdbcDAOImpl genericJdbcDAO = new BaseGenericJdbcDAOImpl();
genericJdbcDAO.setJdbcTemplate(jdbcTemplate);
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(genericJdbcDAO);
proxyFactoryBean.setProxyInterfaces(new Class[] {BaseGenericJdbcDAO.class});
proxyFactoryBean.setInterceptorNames("transactionInterceptor");
return proxyFactoryBean;
}
然后将BaseGenericJdbcDAO注入controller,作为示例:
@RestController
public class VoucherLineRest {
@Resource(name = "genericJdbcDAO")
private BaseGenericJdbcDAO genericJdbcDAO;
}
您会看到对于每个请求都选择了正确的数据源,并且 TransactionInterceptor 拦截从 BaseGenericJdbcDAO bean 调用的每个方法并应用正确的交易传播。
希望您喜欢这次体验。
我有一个 Spring Boot 2 + Hibernate 5 多租户应用程序,它连接到多个 oracle 数据库。当我使用 JpaRepository 时,一切正常,即在收到 http 请求后,'Interceptor' 检测到数据源并且 'MultiTenantConnectionProvider' 实现选择正确的数据源供 TransactionManager 使用。 问题是什么? 我想使用 TransactionInterceptor 来处理来自特定 bean(扩展 JdbcDaoSupport 或注入 JdbcDaoSupport 实现)的某些方法(带有方法名称)的事务。对不起,如果我解释得有点混乱。 但是对于每个 http 请求,该 bean 的数据源是不可变的(默认数据源)。而注入的存储库在正确的事务中对正确的数据源进行操作。
<bean id="txProxyTemplate" abstract="true"
depends-on="transactionManager"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="genericJdbcDao" parent="txProxyTemplate">
<property name="target">
<bean class="org.broker.dao.impl.BaseGenericJdbcDAOImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</property>
</bean>
谁能帮忙解决这个问题?
我终于解决了这个问题。按照代码部分:
@Bean("jdbcTemplate")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public JdbcTemplate jdbcTemplate(
@Qualifier("tenantIdentifierResolver") TenantIdentifierResolverImpl tenantResolver,
@Qualifier("tenantConnectionProvider") DataSourceMultiTenantConnectionProviderImpl dataSourceProvider) {
return new RhaJdbcTemplate(dataSourceProvider.selectDataSource(tenantResolver.resolveCurrentTenantIdentifier()));
}
@Bean(value = "transactionInterceptor")
public TransactionInterceptor transactionInterceptor(
@Qualifier("txProxyTemplateConfig") Properties txProxyTemplateConfig,
@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionAttributes(txProxyTemplateConfig);
transactionInterceptor.setTransactionManager(transactionManager);
return transactionInterceptor;
}
@Bean("genericJdbcDAO")
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public ProxyFactoryBean genericJdbcDAO(
@Qualifier("jdbcTemplate") JdbcTemplate jdbcTemplate) throws ClassNotFoundException {
BaseGenericJdbcDAOImpl genericJdbcDAO = new BaseGenericJdbcDAOImpl();
genericJdbcDAO.setJdbcTemplate(jdbcTemplate);
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(genericJdbcDAO);
proxyFactoryBean.setProxyInterfaces(new Class[] {BaseGenericJdbcDAO.class});
proxyFactoryBean.setInterceptorNames("transactionInterceptor");
return proxyFactoryBean;
}
然后将BaseGenericJdbcDAO注入controller,作为示例:
@RestController
public class VoucherLineRest {
@Resource(name = "genericJdbcDAO")
private BaseGenericJdbcDAO genericJdbcDAO;
}
您会看到对于每个请求都选择了正确的数据源,并且 TransactionInterceptor 拦截从 BaseGenericJdbcDAO bean 调用的每个方法并应用正确的交易传播。
希望您喜欢这次体验。