【问题标题】:Spring, JPA transactions works only in JUnit test but not in applicationSpring,JPA 事务仅适用于 JUnit 测试,但不适用于应用程序
【发布时间】:2012-05-24 21:12:12
【问题描述】:

我在交易方面有一点问题。我将 Spring 3.1.1.RELEASE、Spring Data 1.0.3.RELEASE JPA 与 Hibernate 提供程序一起使用。当我开始一个 junit 测试时,哪里是一个用 @Transactional 注释的方法,它看起来很好,但是当我启动整个应用程序时,没有错误,但事务不起作用。 这是我的配置和示例代码:

applicationContext.xml

<context:annotation-config />
    <context:component-scan base-package="com.sheedo.upload" />
    <jpa:repositories base-package="com.sheedo.upload.repository" />
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath*:messages/*.properties</value>
                <value>classpath*:*.properties</value>
            </list>
        </property>
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="persistenceUnit" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <bean id="dataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
        <property name="url" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

persistence.xml

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
        <property name="hibernate.connection.charSet" value="UTF-8" />
        <property name="hibernate.show_sql" value="true" />
    </properties>
</persistence-unit>

UserRepository.java

公共接口 UserRepository 扩展 CrudRepository{ }

UserServiceImpl.java

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public void addUser(String name, String surname) {
        User u = new User(name, surname);
        userRepository.save(u);
        throw new RuntimeException(); // to invoke a rollback
    }
}

UserServiceTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/root-context.xml" })
public class UserServiceTest {

    Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private UserService userService;

    @Test
    public void testUserAdd() {
        userService.addUser("John", "Doe");
    }

}

在这种 JUnit 测试的情况下,尽管服务方法用 @Transactional 注释,但事务不起作用事件。当我将此注释添加到testUserAdd() 方法时,我在控制台中得到了这个:

2012-05-17 11:17:54,208 INFO [org.springframework.test.context.transaction.TransactionalTestExecutionListener] - Rolled back transaction after test execution for test context [[TestContext@23ae2a testClass = UserRepositoryTest, testInstance = com.sheedo.upload.repository.UserRepositoryTest@7f52c1, testMethod = testUserAdd@UserRepositoryTest, testException = java.lang.RuntimeException, mergedContextConfiguration = [MergedContextConfiguration@111fd28 testClass = UserRepositoryTest, locations = '{classpath:/META-INF/spring/root-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]

我想这是正确的。那么,@Transactional 注解怎么可能只在 Junit 测试类中有效,而在其他 Spring bean 中无效呢?

我的理论是SpringJUnit4ClassRunner 以某种方式提供了这个交易。我的 Spring 配置中是否有问题,即事务在我的应用程序中不起作用,而仅在 Junit 测试类中起作用? appContext 中缺少什么?

编辑: 日志:

2012-05-17 12:46:10,770 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2012-05-17 12:46:10,770 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@e4080] for JPA transaction
2012-05-17 12:46:10,979 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@e4080] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@1f87491] does not support JDBC Connection retrieval
Hibernate: insert into user (name, surname) values (?, ?)
2012-05-17 12:46:11,062 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Initiating transaction commit
2012-05-17 12:46:11,062 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@e4080]
2012-05-17 12:46:11,142 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@e4080] after transaction
2012-05-17 12:46:11,142 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils] - Closing JPA EntityManager

【问题讨论】:

  • 您如何诊断交易“不起作用”?
  • 当我在 UserService 中调试此事务方法时,它在“userRepository.save(user)”之后将实体保存到数据库中,即使该方法以异常结束。而且我没有登录控制台,交易开始了。
  • 启用“org.springframework.transaction”记录器。发布相同的。这将有助于进一步分析。
  • 我在启动时得到的只是这个:2012-05-17 12:41:10,386 DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - Adding transactional method 'addUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 调用该方法时没有日志..
  • Not exposing JPA transaction.. 应该不是问题。描述使用的环境(服务器、休眠版本等)。在2012-05-17 12:46:10,770 之前登录可能会提供更多信息。尝试附加 stackoverflow.com/questions/9051721/…中所述

标签: spring web-applications transactions junit spring-data-jpa


【解决方案1】:

我遇到了完全相同的问题。另外,请阅读在我的 Web 配置中添加 &lt;tx:annotation-driven/&gt; 标签的解决方案(spring-servlet.xml,而不是 applicationContext.xml),并为我工作。

但我不认为这是一个好的解决方案,所以我试图理解为什么会发生这种情况......

好吧,事实证明,我在spring-servlet.xml 中的&lt;context:component-scan&gt; 标签也在其扫描中包含@Service 类(base-package 规范过于笼统)。这很奇怪,因为我有一个 include-filter 引用 @Controller 注释......但无论如何,似乎 Web 层的应用程序上下文是创建 @Service 实例而不是创建的应用程序上下文的那个对于applicationContext.xml——这是定义业务层的那个——并且由于前者没有启用事务性......我没有任何事务。

解决方案(好一个):更好(更具体)component-scan 配置spring-servlet.xml

【讨论】:

  • 遇到了同样的问题。即使定义了包含过滤器,Web 应用程序上下文仍在加载错误的 bean。显然,Web 应用程序上下文中没有 。检查您的日志以了解何时加载 spring-servlet.xml(或任何您命名的 Web 层应用程序上下文)并在日志中查找以下语句:“WebApplicationContext 的 Bean factory” - 您可以搜索这些 bean 以查看 Web 应用程序是否上下文加载它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多