Spring 只有一个交易数据源的@Transactional 行为

Spring @Transactional behaviour with only one transactional data source

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

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

两个数据源:

<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
    }
}

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

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

Is it safe ?

没有。 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
    }
}