【问题标题】:Declarative spring transactions not being committed声明性春季事务未提交
【发布时间】:2012-04-21 15:48:56
【问题描述】:

我有以下服务类别:

public class UserLoginServiceImpl implements UserLoginService {

  private UserDAO dao;

  public UserLoginServiceImpl(UserDAO dao) {this.dao = dao; }

  public User login(String userName, String password) {
     User u = dao.findUserByCredentials(userName, password);
     if (u == null) {
         throw new UserNotFoundException();
     }
     return u;
}

public class UserManagementServiceImpl implements UserManagementService {

  private UserDAO dao;

  public UserManagementServiceImpl(UserDAO dao) { this.dao = dao; }

  public void createUser(User u) {
     dao.save(u);
  }
}

我的服务接口位于 com.mysystem.services 包下,我的服务实现位于 com.mysystem.services.impl 包下。

我在 spring 中使用 hibernate 作为我的 jpa 实现和声明性事务。我的配置文件如下:

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

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="serviceMethod" expression="execution(* com.mysystem.services.impl.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>

<!--
    Beans
 -->
<bean id="userDao" class="com.mysystem.dao.UserDAOImpl">
    <constructor-arg ref="entityManagerFactory" />
</bean>

<bean id="userLoginService" class="com.mysystem.services.impl.UserLoginServiceImpl">
    <constructor-arg ref="userDao" />
</bean>
<bean id="userManagementService" class="com.mysystem.services.impl.UserManagementServiceImpl">
    <constructor-arg ref="userDao" />
</bean>

最后,在我的代码中某处我运行以下内容:

UserManagementService userManagementService = context.getBean(UserManagementService.class);
userManagementService.createUser(new User("test", "test"));

UserLoginService userLogginService = context.getBean(UserLoginService.class);
User user = userLogginService.login("test", "test");

这会导致 login() 方法抛出 UserNotFoundException,因为它无法找到之前由 createUser() 插入的用户,这意味着hibernate 不会刷新方法调用之间的会话。我可以从控制台输出验证这个表单(我可以看到 hibernate 的 createselect 语句,但看不到 insert)。

为什么在调用 createUser() 后没有立即提交事务?我在这里做错了什么?

编辑:

使用@Transactional 注释而不是声明性事务有效。但是,使用 @Transactional 对我来说不是一个选择。我需要实现声明式事务。

下面是spring的调试输出:

13:03:18,174 DEBUG [main] jpa.JpaTransactionManager     - Creating new transaction with name [com.mysystem.services.impl.UserManagementServiceImpl.createUser]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
13:03:18,175 DEBUG [main] jpa.JpaTransactionManager     - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@1af6a711] for JPA transaction
Hibernate: 
    select
        nextval ('hibernate_sequence')
13:03:18,255 DEBUG [main] jpa.JpaTransactionManager     - Initiating transaction commit
13:03:18,255 DEBUG [main] jpa.JpaTransactionManager     - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1af6a711]
13:03:18,256 DEBUG [main] jpa.JpaTransactionManager     - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@1af6a711] after transaction

    13:03:18,263 DEBUG [main] jpa.JpaTransactionManager     - Creating new transaction with name [com.mysystem.services.impl.UserLoginServiceImpl.login]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
    13:03:18,263 DEBUG [main] jpa.JpaTransactionManager     - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@1533badd] for JPA transaction
    Hibernate: 
        /* 
    from
        com.mysystem.domain.User u 
    where
        u.userName = :userName 
        and u.password = :password */ select
            user0_.id as id0_,
            user0_.password as password0_,
            user0_.userName as userName0_ 
        from
            Users user0_ 
        where
            user0_.userName=? 
            and user0_.password=? limit ?
    13:03:18,374 TRACE [main] sql.BasicBinder     - binding parameter [1] as [VARCHAR] - test
    13:03:18,374 TRACE [main] sql.BasicBinder     - binding parameter [2] as [VARCHAR] - test
    13:03:18,379 DEBUG [main] jpa.JpaTransactionManager     - Initiating transaction commit
    13:03:18,379 DEBUG [main] jpa.JpaTransactionManager     - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1533badd]
    13:03:18,379 DEBUG [main] jpa.JpaTransactionManager     - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@1533badd] after transaction

【问题讨论】:

  • 您可以执行刷新(EntityManager.flush()),如果您在服务方法中的创建调用之后执行此操作,那么用户将可以看到获取方法而无需实际提交事务。

标签: java spring hibernate spring-transactions


【解决方案1】:

你能试试这个吗?

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>

        <tx:method name="createUser" propagation="REQUIRES_NEW" />
    </tx:attributes>
</tx:advice>

【讨论】:

  • 你需要一个新的交易。这将为您提供所需的传播=“REQUIRES_NEW。您可以尝试提供反馈吗。
  • 不...也没有用。有趣的是,当我改用 @Transactional 注释时它可以工作。我想这一定是我的配置中的某些东西,但我目前无法弄清楚。
  • himm.. 好的.. 你能更新你的切入点表达式 com.mysystem.services.impl.*.*(..) 我猜问题就在那里。
  • 问题:我应该在实现类的方法还是接口上定义我的事务?
  • 我设法解决了这个问题(终于)。在我的设计中,我选择使用构造函数注入来注入 EntityManagerFactory。然后在我的 dao 的构造函数中使用 emf 创建一个 EntityManager 并将其设置为 dao 实例的成员变量。当我将注入策略更改为使用 @PersistenceContext 注释时,我设法使其工作。我仍然不确定为什么我最初的策略不起作用,但最终结果是它起作用了。如果有人能解释一下,我会很感兴趣。
猜你喜欢
  • 2014-08-10
  • 2013-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多