Spring Data JPA repositories use in EJB timer causes TransactionRequiredException

前端 未结 2 1929
醉话见心
醉话见心 2020-12-15 01:15

I would like to use spring data repositories in my Java EE project. I use:

  • WildFly 10.0.0
  • Hibernate 5.0.7
  • Spring Data JPA 1.10.6
  • C
相关标签:
2条回答
  • 2020-12-15 01:48

    ATTENTION! When you use a Timer with a database there is an important requirement. See https://javaee.github.io/glassfish/doc/5.0/application-development-guide.pdf at the chapter "EJB Timer Service" :

    Using the EJB Timer Service is equivalent to interacting with a single JDBC resource manager. If an EJB component or application accesses a database either directly through JDBC or indirectly (for example, through an entity bean's persistence mechanism), and also interacts with the EJB Timer Service, its data source must be configured with an XA JDBC driver.

    So for example on GlassFish 5.0 on the admin console you must have for your pool on the "JDBC Connection Pools" the ressource type with "java.sql.XADatasource". If you don't do that you will have error issue when the method annoted with @TimeOut will be called and will try to use an Entity.

    0 讨论(0)
  • 2020-12-15 01:49

    Short answer

    The repository initialization breaks the transaction. Initialize the repository beforehand, in a different Thread/transaction by adding @Eager to your repository instances.

    Explanation

    Spring Data repository instances are @ApplicationScoped and initialized on demand. The Thread (and transaction) that performs the first access to the repository is used for initialization.

    Spring Data JPA repository initialization does a couple of things, one of them is trying to figure out, whether you have provided named queries for repository query methods. Unfortunately, JPA does not provide an API to check whether a named query exists, so we rely on EntityManager.createNamedQuery(…). If there's no named query, EntityManager throws an exception and aborts the transaction.

    In a later stage, your EJB method uses the EntityManager within the same Thread (and transaction). It checks for an active transaction. Because the transaction is marked for rollback-only, you see the exception.

    Workaround

    Add @Eager to your repository declaration. The Spring Data CDI extension will initialize the repository on startup:

    @Eager
    public interface TestRepository extends CrudRepository<TestEntity, Long> {
        // …
    }
    

    Hint

    You don't require @Repository on TestRepository. Spring Data picks up the repository by picking up beans that are descendants from org.springframework.data.repository.Repository or plain interfaces annotated with @RepositoryDefinition.

    The transaction manager properties in your persistence.xml are not required, WildFly already configures the persistence context with the required settings.

    References:

    • DATAJPA-724
    • DATAJPA-617
    • Strange exception on inital request to Repository when using Spring Data JPA with EJB/CDI
    0 讨论(0)
提交回复
热议问题