当前位置: 首页 > 面试题库 >

Spring / JTA / JPA单元测试:回滚不起作用

巫墨一
2023-03-14
问题内容

我正在尝试使用Spring测试实体EJB3。

EJB本身不使用Spring,并且我想使生产JPA配置的重复保持最少(例如,不重复persistence.xml)。

我的单元测试似乎可以正常工作,但是即使我的单元测试应该是事务性的,数据仍会在各种测试方法之间持久存在……

这是我的实体:

package sample;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Ejb3Entity {

    public Ejb3Entity(String data) {
        super();
        this.data = data;
    }
    private Long id;
    private String data;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }

}

我的单元测试:

package sample;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/appContext.xml"})
@Transactional
public class Ejb3EntityTest {

    @PersistenceContext
    EntityManager em;

    @Before
    public void setUp() throws Exception {
        Ejb3Entity one = new Ejb3Entity("Test data");
        em.persist(one);
    }

    @Test
    public void test1() throws Exception {

        Long count = (Long) em.createQuery("select count(*) from Ejb3Entity").getSingleResult();
        assertEquals(Long.valueOf(1l), count);
    }

    @Test
    public void test2() throws Exception {

        Long count = (Long) em.createQuery("select count(*) from Ejb3Entity").getSingleResult();
        assertEquals(Long.valueOf(1l), count);
    }

}

和我的appContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />

    <bean id="transactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="userTransaction" ref="jotm" />
        <property name="allowCustomIsolationLevels" value="true" />
    </bean>

    <bean id="dataSource" class="org.enhydra.jdbc.standard.StandardXADataSource">
        <property name="driverName" value="org.h2.Driver" />
        <property name="url" value="jdbc:h2:mem:unittest;DB_CLOSE_DELAY=-1" />
        <property name="user" value="" />
        <property name="password" value="" />
        <property name="transactionManager" ref="jotm" />
    </bean>

    <bean id="emf"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitPostProcessors">
            <bean class="sample.JtaDataSourcePersistenceUnitPostProcessor">
                <property name="jtaDataSource" ref="dataSource" />
            </bean>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false" />
                <property name="generateDdl" value="true" />
                <property name="database" value="H2" />
                <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            </bean>
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.transaction.manager_lookup_class"
                    value="org.hibernate.transaction.JOTMTransactionManagerLookup" />
                <entry key="hibernate.transaction.auto_close_session" value="false" />
                <entry key="hibernate.current_session_context_class" value="jta" />
            </map>
        </property>

    </bean>


</beans>

当我运行测试时,test2失败,因为它找到了两个我只希望有一个实体的实体(因为第一个实体应该已经回滚了……)

我尝试了很多不同的配置,而这似乎是我能得到的最全面的配置。你做 ?


问题答案:

我设法使用Bitronix而不是JOTM
使其工作。Bitronix提供了一个LrcXADataSource,它允许非XA数据库参与JTA事务。

我认为问题在于H2不符合XA且enhydra StandardXADataSource并非如此神奇(我也结束了使用HSQLDB的工作,但这与问题无关)。

这是我的spring上下文有效:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

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

    <!--  Bitronix Transaction Manager embedded configuration -->
    <bean id="btmConfig" factory-method="getConfiguration"
        class="bitronix.tm.TransactionManagerServices">
        <property name="serverId" value="spring-btm" />
        <property name="journal" value="null" />
    </bean>

    <!-- create BTM transaction manager -->
    <bean id="BitronixTransactionManager" factory-method="getTransactionManager"
        class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource"
        destroy-method="shutdown" />

    <bean id="transactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager" ref="BitronixTransactionManager" />
        <property name="userTransaction" ref="BitronixTransactionManager" />
        <property name="allowCustomIsolationLevels" value="true" />
    </bean>


    <!-- DataSource definition -->

    <bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
        init-method="init" destroy-method="close">
        <property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource" />
        <property name="uniqueName" value="unittestdb" />
        <property name="minPoolSize" value="1" />
        <property name="maxPoolSize" value="3" />
        <property name="allowLocalTransactions" value="true" />
        <property name="driverProperties">
            <props>
                <prop key="driverClassName">org.hsqldb.jdbcDriver</prop>
                <prop key="url">jdbc:hsqldb:mem:unittestdb</prop>
                <prop key="user">sa</prop>
                <prop key="password"></prop>
            </props>
        </property>
    </bean>

    <!-- Entity Manager Factory -->
    <bean id="emf"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="database" value="HSQL" />
            </bean>
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.transaction.manager_lookup_class"
                    value="org.hibernate.transaction.BTMTransactionManagerLookup" />
                <entry key="hibernate.transaction.auto_close_session" value="false" />
                <entry key="hibernate.current_session_context_class" value="jta" />
            </map>
        </property>

    </bean>


 类似资料:
  • 在spring boot中,我试图创建我的第一个事务性测试,但trasaction不起作用。 null 我需要的是: 将数据插入事务。 从事务中读取数据。 测试返回的数据。 回滚事务。

  • 我使用@Transactional与Spring引导和jpa。但它不起作用。有人能帮忙吗? 我的插件在myDAO中,它是在服务类中自动生成的。下面的代码是实现服务接口的服务类的方法

  • 我是JPA新手,正在使用spring数据。我想建立一个多单单向关系。我的表格是国家和地区,正如预期的那样,关系是许多国家属于一个地区。我尝试从Country实体获取所有数据,但失败了,出现以下错误。 错误 区域类别 国家/地区级 存储库 测试用例 错误-异常 堆栈跟踪 导致此问题的原因是什么?无法转换为内部表示是什么意思?如何克服这个问题?

  • 我的项目遇到了Spring JPA事务无法回滚的问题。项目框架为spring MVC+spring+spring data JPA+Oracle。我在网上搜索了很多信息,但仍然不能解决我的问题。 我尝试了许多方法,例如将方法设置为public或在中添加,但仍然无法解决这个问题。 这是我的代码 控制器 服务 刀 我的方法加载我的实现类服务,它编写一个容易出错的1/0。我期望事务在出错后回滚,但它没有

  • 我对SonarRunner有以下问题。 SonarQube 以及 Sonar 运行器无法拉取 junit 格式的 xml 报告 “单元测试”或“测试覆盖率”小组件不显示。它说没有数据。我正在按照此处描述的说明进行操作 我按照描述手动创建了XML格式的报告文件,但是仍然没有成功。 下面是 XML 文件 - TEST-Firefox_210_Mac_OS.com.company.BarTest.xml

  • 我正在使用spring test运行JUnit测试,我的代码如下所示: 我想在所有测试之前回滚处于状态的数据库。表会回滚,但id生成的顺序会随着每次测试而增加。 请帮我找到在每次测试前设置起始值顺序的方法。 我正在使用Spring、Hibernate和HsqlDb