为啥我在 JTA EJB 的 @PostConstruct 方法中收到 TransactionRequiredException?

Posted

技术标签:

【中文标题】为啥我在 JTA EJB 的 @PostConstruct 方法中收到 TransactionRequiredException?【英文标题】:Why am I getting a TransactionRequiredException in @PostConstruct method in JTA EJB?为什么我在 JTA EJB 的 @PostConstruct 方法中收到 TransactionRequiredException? 【发布时间】:2017-03-31 18:54:37 【问题描述】:

我有一个 Java EE 项目,我想在 @PostConstruct 方法中使用注入的 JTA EntityManagerEntityManager.persist 由于javax.persistence.TransactionRequiredException 而失败。当通过注入 JSF 托管 bean 的 EJB 实例调用时,它会成功。使用 @Resource UserTransactionUserTransaction.begin/commitEntityManager.getTransaction.begin/commit 手动启动事务,因为它是 JTA EntityManager

EJB 接口

@Local
public interface UserService extends Serializable 

    public void saveUser(AUser user);


@Entity
public class AUser implements Serializable 
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    private Long id;
    private String username;

    public AUser() 
    

    public AUser(String username) 
        this.username = username;
    

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    

EJB 实现:

@Stateless
public class DefaultUserService implements UserService 
    private static final long serialVersionUID = 1L;
    @PersistenceContext
    private EntityManager entityManager;

    public DefaultUserService() 
    

    @PostConstruct
    private void init() 
        AUser user = new AUser("initUser");
        saveUser(user);
    

    @Override
    public void saveUser(AUser user) 
        entityManager.persist(user);
    

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="richtercloud_javaee-persist-in-postconstruct-jar_jar_1.0-SNAPSHOTPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/example1</jta-data-source>
    <class>richtercloud.javaee.persist.in.postconstruct.jar.entities.AUser</class>
    <properties>
      <property name="eclipselink.target-database" value="Derby"/>
      <!-- necessary in order to avoid syntax errors -->
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
      <property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
      <property name="eclipselink.target-server" value="Glassfish"/>
      <!-- avoid non-severe NullPointerException being logged in GlasFish
            <ref>https://java.net/jira/browse/GLASSFISH-21468f</ref>-->
    </properties>
  </persistence-unit>
</persistence>

我不知道如何提供jdbc/example1 数据源(它是基于 JDBC 连接池的 GlassFish 4.1 JDBC 资源,该连接池引用带有网络驱动程序的 Derby 数据库)。 https://github.com/krichter722/javaee-persist-in-postconstruct 提供的所有其他内容。

我读到了Persisting in @PostConstruct: javax.persistence.TransactionRequiredException,它超过了@PostConstruct 和http://www.tikalk.com/java/doing-transactional-work-spring-service-using-postconstruct-method/ 中的简单EntityManager.persist 调用示例,http://www.tikalk.com/java/doing-transactional-work-spring-service-using-postconstruct-method/ 指的是我没有使用的 Spring。我没有发现 @PersistenceContext EntityManager@PostConstruct 中的行为不同的声明。

【问题讨论】:

【参考方案1】:

它不保证@PostConstruct 和@PreDestroy 是事务的一部分。所以不要在 PostConstruct 方法和 PreDestroy 方法中进行数据库操作。

【讨论】:

【参考方案2】:

EJB 3.2 规范第 8.6.2 节规定:

术语“未指定的事务上下文”在 EJB 规范中用于指 EJB 架构没有完全定义企业 bean 方法执行的事务语义的情况。 这包括以下情况: ... • 执行具有容器管理的事务划分的无状态会话 bean 的 PostConstruct 或 PreDestroy 回调方法。

另一种解决方案可能是在您的 persistence.xml 文件中指定 javax.persistence.sql-load-script-source 属性。它指向将预加载数据库的 SQL 脚本。这可以是嵌入在您的应用程序中的资源或文件 URL。

【讨论】:

以上是关于为啥我在 JTA EJB 的 @PostConstruct 方法中收到 TransactionRequiredException?的主要内容,如果未能解决你的问题,请参考以下文章

带 JDBC 的 EJB 3

当容器管理的 tx EJB 提交时,如何捕获和包装 JTA 抛出的异常?

JTA和JTS

weblogic 下如何配置 JTA事务管理??

为啥要使用 EJB? [关闭]

Spring对JTA的支持