【问题标题】:How to use transaction interceptor in a multi-tenant spring boot program?如何在多租户 Spring Boot 程序中使用事务拦截器?
【发布时间】:2022-01-05 15:18:21
【问题描述】:

我有一个连接到多个 oracle 数据库的 Spring Boot 2 + Hibernate 5 多租户应用程序。当我使用 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>

谁能帮忙解决这个问题?

【问题讨论】:

    标签: java spring-boot hibernate spring-data-jpa spring-transactions


    【解决方案1】:

    我终于解决了这个问题。按照代码部分:

    @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 注入到控制器中,作为样本:

    @RestController
    public class VoucherLineRest {
        @Resource(name = "genericJdbcDAO")
        private BaseGenericJdbcDAO genericJdbcDAO;
    }
    

    您将看到,对于每个请求,都选择了正确的数据源,TransactionInterceptor 拦截了从 BaseGenericJdbcDAO bean 调用的每个方法,并对其应用正确的事务传播。

    希望您喜欢这次体验。

    【讨论】:

      猜你喜欢
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2017-11-17
      • 2017-11-28
      相关资源
      最近更新 更多