【问题标题】:Spring + Hibernate: using transactional and non-transactional datasources togetherSpring + Hibernate:一起使用事务和非事务数据源
【发布时间】:2012-01-29 04:33:14
【问题描述】:

在我的 Spring 2.5.6 + Hibernate 应用程序中,我需要从具有不同模式的多个数据库读取/写入数据。该应用程序在 Tomcat 上,因此我暂时不想使用 JTA,这样我就不需要迁移到成熟的应用程序服务器。

所以我决定只使用一个事务性数据源。我可以和其他不交易的人一起生活。

但不知何故,我无法让它工作。你能帮我看看我可能做错了什么吗?

这是我的 applicationContext.xml:

 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- ..configuration.. -->
</bean>

<bean id="nonTransactionalSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="nonTransactionalDataSource" />
    <!-- ..configuration.. -->
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <!-- ..configuration.. -->
</bean>

<bean id="nonTransactionalDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <!-- ..configuration.. -->
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="daoHolder" class="com.app.services.TransactionTest$DaoHolder"/>

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

<bean id="transactionalDao" class="com.app.services.TransactionalDaoImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="nonTransactionalDao" class="com.app.services.NonTransactionalDaoImpl">
        <property name="sessionFactory" ref="nonTransactionalSessionFactory" />
</bean>

如您所见,上面只是对两个会话工厂的定义,每个工厂都使用自己的数据源。事务管理器仅使用这些会话工厂之一,并且配置了注释驱动的 tx-management。

这是我试图测试事务行为的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/applicationContext.xml"})
public class TransactionTest {

@Autowired
private DaoHolder daoHolder;

@Test
public void testTransactions() throws Exception {

    try {
        daoHolder.runTransactionalMethod();
    } catch (Exception exception) {
        System.out.println("Exception caught");
    }
}

public static class DaoHolder {

    @Autowired
    private TransactionalDao transactionalDao;
    @Autowired
    private NonTransactionalDao nonTransactionalDao;

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor={Exception.class})
    private void runTransactionalMethod() throws Exception {
        transactionalDao.insertRow();
        nonTransactionalDao.insertRow();
        throw new Exception();
    }

}

作为上述测试的结果,我希望在非事务性数据源中插入一个新行,因为事务性数据源上的更改应该回滚,因为抛出了异常。但是,在此测试通过后,我看到两个数据源中都插入了行。

编辑:我走得更远了。我已经将 DaoHolder 变成了一个接口,将上述逻辑移到了一个实现接口的类(DaoHolderImpl)中,并用@Transactional 标记了这个类(不仅仅是方法)。我还将此类添加为 Spring Bean。所以现在 Spring 处理我的事务。但是这一次,当抛出异常时,新行会从两个数据源中回滚,而不仅仅是事务性的。这仍然不是我所期望的:/

有人看到我做错了吗? 提前致谢,

彼得

【问题讨论】:

    标签: hibernate spring transactional


    【解决方案1】:

    如何在“抛出异常”行放置断点,以便查看一个或两个数据库是否有该行?

    它不能解决您奇怪的回滚未出现问题,但可能会告诉您您的非事务性数据源是否运行良好。

    您宁愿启用 spring/hibernate 日志记录以查看事务发生了什么...

    【讨论】:

    • 没问题,尽管感谢您的尝试 :) 我已经达到了在抛出异常后得到回滚的地步(必须将 @Transactional 添加到整个 DaoHolder 类),但是这一次,两个 DAO 的更改似乎都已回滚,因为没有插入任何内容。这让我感到惊讶,因为我只期望事务 dao 被回滚。无论如何 - 这仍然不是我需要的行为。
    • 也许您应该配置非事务数据库的刷新模式。该行可能被插入到您的非事务会话中,但刷新根本没有发生。您在休眠 SQL 日志(show_sql 属性)中看到任何内容吗?你的数据库配置呢?您是否设置了类似 autocommit=true 或类似的设置?
    • 好吧,如果我不抛出异常,我会在休眠 SQL 日志中看到两个插入。如果我抛出异常,我看不到任何插入。嗯.. 在日志中我看到:Opened new Session [org.hibernate.impl.SessionImpl@1517997] for Hibernate transaction 仅一次。所以我想我的问题是由于实际上这两个操作都是在同一个 Hibernate 会话上完成的。为什么会这样,我该如何改变它?
    • 对不起,我真的不知道。但通常 Spring 将 @Transactionnal 注释打开的会话绑定到当前线程,因此如果您使用 spring dao 支持/休眠模板或类似的东西,它会看到会话绑定到线程并简单地使用它......在两个你的 dao,尝试做“getSession()”或其他东西,并检查日志是否是同一个对象
    • 好主意,谢谢 :) 我马上试试。你知道spring事务管理有什么好的资源吗?我想更详细地了解当您使用 @Transactional 注释某些内容时,幕后究竟发生了什么。 Spring 文档很有帮助,但它们没有为我提供足够的信息......再次感谢。
    猜你喜欢
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    • 2011-05-19
    • 2016-06-29
    • 2018-09-05
    • 2014-11-20
    • 1970-01-01
    相关资源
    最近更新 更多