【问题标题】:Spring @Transactional behaviour with only one transactional data sourceSpring @Transactional 行为只有一个事务数据源
【发布时间】:2016-06-02 04:21:31
【问题描述】:

我有一个访问两个数据库的应用程序。显然,如果我需要跨越两个数据库的事务,我需要使用类似两阶段提交的东西。但我现在不需要这个保证之王,我不需要一切都是交易性的。事情可以独立崩溃或成功,应用程序可以处理它,而不是最终处于不一致的状态。

现在我有这样的设置(删除了接口、代码等,以使其尽可能简单地解释):

两个数据源:

<bean id="firstDS" class="org.springframework.jndi.JndiObjectFactoryBean">
    <qualifier value="firstDS" />
    <property name="jndiName" value="java:comp/env/jdbc/firstDS" />
</bean>

<bean id="secondDS" class="org.springframework.jndi.JndiObjectFactoryBean">
    <qualifier value="secondDS" />
    <property name="jndiName" value="java:comp/env/jdbc/secondDS" />
</bean>

仅一个数据源的一个事务管理器:

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="firstDS" />
</bean>

一项服务:

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class Service {

    @Autowired
    private FirstDao firstDao;

    @Autowired
    private SecondDao secondDao;

    public void updateStuff() {
        firstDao.updateStuff();
        secondDao.updateStuff();
    }
}

还有两个 DAO:

@Transactional(propagation = Propagation.MANDATORY)
public class FirstDao {

    @Autowired
    @Qualifier("firstDS")
    private DataSource dataSource;

    public void updateStuff() {
        // updates stuff in the first database using dataSource
    }
}

@Transactional(propagation = Propagation.MANDATORY)
public class SecondDao {

    @Autowired
    @Qualifier("secondDS")
    private DataSource dataSource;

    public void updateStuff() {
        // updates stuff in the second database using dataSource
    }
}

现在,这运行没有问题(或者至少没有我能观察到的问题),但我的问题是:

  • 这是安全的还是有副作用?
  • 第二个 DAO 的行为如何,因为它是事务性的,但事务是针对另一个数据库的?
  • 我应该从第二个 DAO 中删除 @Transactional 注释吗?然后它的行为会像任何其他方法调用一样吗?

我已经阅读了参考资料和网上的各种帖子,但我仍然不确定这种行为。

【问题讨论】:

    标签: java mysql spring transactions spring-transactions


    【解决方案1】:

    安全吗?

    没有。 SecondDao.updateStuff 将在没有逻辑事务的情况下执行。这意味着在SecondDao.updateStuff 期间执行的每个查询都将在自动提交模式下在单独的物理事务中执行。换句话说:SecondDao.updateStuff 不是事务性的(甚至可能为每个查询使用一个单独的连接......这可能会导致性能问题)。

    你能做什么?

    首先为你的 secondDS 声明一个 transactionManager:

    <tx:annotation-driven/>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="firstDS" />
    </bean>
    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="secondDS" />
    </bean>
    

    然后指定 SecondDAO 使用 transactionManger2 :

    @Transactional(value="transactionManager2",propagation = Propagation.REQUIRED)
    public class SecondDao {
    
        @Autowired
        @Qualifier("secondDS")
        private DataSource dataSource;
    
        public void updateStuff() {
            // updates stuff in the second database using dataSource
        }
    }
    

    【讨论】:

    • 感谢 ben75 的回答。您能否详细说明一下您的回答。例如,为什么第二个 DAO 会为每个查询使用一个单独的连接?它配置了自己的数据源,因此它将从那里建立连接。两个数据源都是池化的,我没提过,还是会造成性能问题吗?此外,第二个事务管理器如何帮助修复它。我只是想了解您提出的解决方案。再次感谢!
    • 我没有说它总是需要一个新的连接,这取决于你的设置。您使用连接池的事实与此潜在问题无关。与连接释放方式有关。
    • 为 secondDS 定义一个 transationManger2 将简单地通知 spring 对 secondDS 的每个访问也必须在 逻辑事务 内,并用 @Transactional 注释分隔。请注意事务方法 secondDS 的重要属性 value="transactionManager2"。您还必须知道 value 属性的默认值是“transactionManager”。
    • 与连接释放方式有关。以什么方式?连接不释放?你的意思是泄漏?
    猜你喜欢
    • 2018-08-03
    • 2010-12-30
    • 2019-03-30
    • 2011-05-10
    • 2020-06-21
    • 2017-03-04
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多