2017-03-31 2 views
1

J'ai projet Java EE où je veux utiliser un JTA injecté EntityManager dans la méthode @PostConstruct. EntityManager.persist échoue en raison de javax.persistence.TransactionRequiredException. Il réussit lorsqu'il est appelé via une instance EJB injectée dans un bean géré JSF. Démarrage manuel d'une transaction avec @Resource UserTransaction et UserTransaction.begin/commit ou EntityManager.getTransaction.begin/commit parce que c'est un JTA EntityManager.Pourquoi est-ce que j'obtiens une exception TransactionRequiredException dans la méthode @PostConstruct dans JTA EJB?

L'interface 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; 
    } 

L'implémentation 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> 

Je ne savais pas comment fournir la source de données jdbc/example1 (il est GlassFish 4.1 Ressource JDBC basée sur un pool de connexions JDBC faisant référence à un Derby d atabase avec le pilote réseau). Tout le reste est disponible au https://github.com/krichter722/javaee-persist-in-postconstruct.

Je lis Persisting in @PostConstruct: javax.persistence.TransactionRequiredException qui dépasse l'exemple d'un simple appel EntityManager.persist dans @PostConstruct et http://www.tikalk.com/java/doing-transactional-work-spring-service-using-postconstruct-method/ qui fait référence au printemps que je ne suis pas à l'aide. J'ai trouvé aucune déclaration que @PersistenceContext EntityManager se comporte différemment dans @PostConstruct.

Répondre

1

§8.6.2 des états de spécification EJB 3.2:

Le terme « un contexte de transaction non spécifiée » est utilisée dans la spécification EJB de se référer aux cas où l'architecture EJB ne définit pas complètement la sémantique de transaction d'une exécution de méthode de bean d'entreprise.
Cela inclut les cas suivants:
...
• L'exécution d'une méthode de rappel PostConstruct ou PreDestroy d'un bean de session sans état avec une démarcation de transaction gérée par conteneur.

Une autre solution peut être de préciser la propriété javax.persistence.sql-load-script-source dans votre fichier persistence.xml. Il pointe vers un script SQL qui va précharger votre base de données. Cela peut être une ressource intégrée dans votre application ou une URL de fichier.

3

il ne garantit pas que @PostConstruct et @PreDestroy font partie de la transaction. Par conséquent, aucune opération DB ne doit être effectuée dans la méthode PostConstruct ainsi que dans la méthode PreDestroy.