【问题标题】:Spring 4, JBoss 7, @Configuration Bean equivalent XML - Spring TransactionsSpring 4,JBoss 7,@Configuration Bean 等效 XML - Spring Transactions
【发布时间】:2014-06-20 14:10:28
【问题描述】:

似乎 EntityManager 没有刷新对数据库的更改。使这个问题更难的是没有抛出异常。我正在使用声明性事务来定义我的事务边界,流程如下:

SignUpController --> @Transactional: Tx.Start --> AccountServiceImpl.createAccount --> AccountDAOImpl.createAccount --> Tx.Commit --> SignUpController

从我的调查看来:

1.Spring 使用@Transactional 正确定义事务边界。因此正在创建事务

2.另外请注意我使用的是 SharedEntityManagerBean,这意味着我不能明确定义我的事务边界,例如:

em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();

以上代码导致以下异常:Not allowed to create transaction on shared EntityManager - 请改用 Spring 事务或 EJB CMT

下面是相关代码和配置。任何帮助将不胜感激。谢谢。

MainConfig.java:

@Configuration
@ComponentScan(basePackages="com",excludeFilters=                {@Filter(Configuration.class)})
@EnableTransactionManagement
public class MainConfig  {

@Bean
public DataSource dataSource() {
DataSource ds = (DataSource)getFromInitialContext("java:jboss/datasources/PrimaryDB");
return ds;
}

@Bean
public PlatformTransactionManager transactionManager() {
 return new DataSourceTransactionManager(dataSource());
}

@Bean
public EntityManagerFactory entityManagerFactory() {
   EntityManagerFactory emf = (EntityManagerFactory) getFromInitialContext("java:jboss/entityManagerFactory");
return emf;
}

private Object getFromInitialContext(String jndiValue) {
    Context ctx = null;
    Object object = null;
try {
  ctx = new InitialContext();
  object = ctx.lookup(jndiValue);
} catch (NamingException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}
return object;
}
}

persistance.xml:

<persistence-unit name="PrimaryDB" transaction-type="JTA">
    <jta-data-source>java:jboss/datasources/PrimaryDB</jta-data-source>
    <class>com.domain.entities.Account</class>
    <properties>
        <!-- Bind entity manager factory to JNDI at java:jboss/myEntityManagerFactory -->
        <property name="jboss.entity.manager.factory.jndi.name"
            value="java:jboss/entityManagerFactory" />

        <!-- Properties for Hibernate -->
        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.use_sql_comments" value="true" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
</persistence-unit>

AccountServiceImpl:

@Service
public class AccountServiceImpl implements AccountService {

  @Inject
  AccountDAO accountDAOImpl;

  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public Account createAccount(SignupForm form, BindingResult formBinding) {
               TransactionDebugUtil.transactionRequired("AccountServiceImpl.createAccount");
   Account account =
        new Account(form.getUsername(), form.getPassword(),form.getFirstName(), form.getLastName());
    try {
      accountDAOImpl.createAccount(account);
    } catch (Exception ex) {
      formBinding.rejectValue("username", "user.duplicateUsername",
          "already in use: " + ex.getMessage());
      return null;
    }
    return account;
  }
}

AccountDAOImpl.java:

@Repository
public class AccountDAOImpl extends GenericJpaDAO<Account> implements    AccountDAO {

  @Override
  @PersistenceContext
  public void setEntityManager(EntityManager entityManager) {
   this.entityManager = entityManager;
   entityManager.setFlushMode(FlushModeType.COMMIT);
  }

 @Override
 public void createAccount(Account account) throws     UsernameAlreadyInUseException {
    entityManager.persist(account);
 }

【问题讨论】:

  • 为什么你认为信息没有被刷新?
  • 我在日志中看不到正在生成的 sql 并确认我运行:select * from account;不返回任何结果。
  • 您使用了错误的事务管理器。您正在使用 JPA,因此您应该使用 JpaTransactionManager 而不是 DataSourceTransactionManager。此外,您的代码存在缺陷并且会破坏正确的 td 管理,您正在捕获异常并设置值,这将使异常对 tx 支持不可见,并且会尝试提交而不是回滚。

标签: java spring spring-mvc jboss7.x spring-transactions


【解决方案1】:

这种行为通常发生在我们没有@transactional 时 关于持久化方法。

所以在下面的方法顶部添加@Transactional

@Override
@Transactional
 public void createAccount(Account account) throws     UsernameAlreadyInUseException {
    entityManager.persist(account);
 }

【讨论】:

  • 您好,感谢您的贡献,但这是不正确的。只要持久化方法存在于事务的范围内,一旦事务提交,entityManager 应该自动将更改刷新到数据库中。在服务层中定义 @transactional 注释通常是最佳实践。
【解决方案2】:

您没有正确处理事务管理。将您的事务管理器 bean 替换为:

@Bean
public PlatformTransactionManager transactionManager() {
   final JpaTransactionManager txManager = new JpaTransactionManager();
   txManager.setEntityManagerFactory(entityManagerFactory());
   return txManager;
}

【讨论】:

  • 我正在使用 JTA EntityManager,因此无法使用您在上面定义的 JPA TransactionManager,因为它给了我以下期望:org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 org.springframework.transaction.CannotCreateTransactionException:无法打开 JPA EntityManager 进行事务处理;嵌套异常是 java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction() 。但是,您确实引导我朝着正确的方向解决我的问题。
【解决方案3】:

您好,混淆是由于使用注释来配置事务管理器而不是 XML。

SpringTransaction 的典型 XML 配置:

1.

<tx:annotation-driven /> 

^它扫描应用程序上下文中的所有bean并为那些被注释的bean创建AOP拦截器。这是通过TransactionInterceptor使用的SpringTransactionAnnotationParser完成的。

@EnableTransactionManagement

^这是允许事务支持的等效配置 bean 注释

2 . JTA 数据源在persistence.xml 中定义。 JBoss 7 自动创建一个 JTA 事务管理器并将其绑定到以下 JNDI 位置:默认情况下是 java:/TransactionManager。这个事务管理器是在 spring 中自动发现的,具有以下 xml 配置:

<tx:jta-transaction-manager />

对此的等效注解配置为:

@Bean
public PlatformTransactionManager transactionManager() {
   JtaTransactionManager txManager = new JtaTransactionManager();
   return txManager;
}

这解决了我的问题。感谢@geoand 的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 2018-01-14
    • 1970-01-01
    相关资源
    最近更新 更多