2010-01-05 4 views
3

Je commence tout juste à jeter un oeil à la persistance java (actuellement avec le fournisseur par défaut d'eclipselink d'eclipse). Fondamentalement, il suffit de créer un objet et de tenter de le conserver dans la base de données (Oracle). J'ai cru comprendre que la transactionnalité par défaut devrait valider le nouvel objet dans la base de données quand la méthode revient mais rien ne semble se produire. Des idées?Eclipselink JPA, Oracle, Weblogic, Calling Persist ne s'engage pas dans la base de données

@Stateless 
public class RegisterUser implements RegisterUserLocal { 

@PersistenceContext 
private EntityManager entityManager; 

    public void registerNewUser(String username, String password){ 
    User user = new User(); 
    user.setPassword(password); 
    user.setUsername(username); 
    entityManager.persist(user); 
    entityManager.getTransaction().commit(); 
    } 
} 

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> 
<persistence-unit name="SCBCDEntities" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 
    <class>examples.persistence.User</class> 
    <properties> 
    <property name="eclipselink.target-server" value="WebLogic_10"/> 
    <property name="eclipselink.jdbc.driver" value="oracle.jdbc.OracleDriver"/> 
    <property name="eclipselink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:db4"/> 
    <property name="eclipselink.jdbc.user" value="SCBCD"/> 
    <property name="eclipselink.jdbc.password" value="123456"/> 
    <property name="eclipselink.logging.level" value="FINEST"/> 
    </properties> 
</persistence-unit> 
</persistence> 

Classe Entité:

@Entity 
@Table(name="USERS") 
public class User implements Serializable { 
private static final long serialVersionUID = 1L; 

@Id 
private String username; 

private String password; 

    public User() { 
    } 

public String getUsername() { 
    return this.username; 
} 

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

public String getPassword() { 
    return this.password; 
} 

public void setPassword(String password) { 
    this.password = password; 
} 

} 

En outre, pour répondre aux réponses à cette question, avec le code que j'ai énuméré les journaux montrent un commit exécution (quelques détails ont été supprimés par souci de concision)

[EL Finest]: 2010-01-05 22:58:07.468--UnitOfWork(25499586)--Thread(Thread[[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel. 
Default (self-tuning)',5,Pooled Threads])--PERSIST operation called on: [email protected] 
<Jan 5, 2010 10:58:07 PM EST> <Debug> <JTA2PC> <BEA-000000> <BEA1-001959ECF50B251A451D: [EJB examples.session.stateless.RegisterUs 
er.registerNewUser(java.lang.String,java.lang.String)]: ServerTransactionImpl.commit()> 
<Jan 5, 2010 10:58:07 PM EST> <Debug> <JTA2PC> <BEA-000000> <BEA1-001959ECF50B251A451D: [EJB examples.session.stateless.RegisterUs 
er.registerNewUser(java.lang.String,java.lang.String)]: TX[BEA1-001959ECF50B251A451D] active-->pre_preparing 
<Jan 5, 2010 10:58:07 PM EST> <Debug> <JTA2PC> <BEA-000000> <SC[mr_domain+AdminServer] active-->pre-preparing 
er.registerNewUser(java.lang.String,java.lang.String)]: TX[BEA1-001959ECF50B251A451D] prepared-->committing 
<Jan 5, 2010 10:58:07 PM EST> <Debug> <JTA2PC> <BEA-000000> <SC[mr_domain+AdminServer] pre-prepared-->committed 
er.registerNewUser(java.lang.String,java.lang.String)]: TX[BEA1-001959ECF50B251A451D] committing-->committed 
... 
... 

mais si j'ajoute « flush » après la PERSISTENT, je reçois « notransaction » ...

[EL Finest]: 2010-01-05 22:44:55.218--UnitOfWork(113017)--Thread(Thread[[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.De 
fault (self-tuning)',5,Pooled Threads])--PERSIST operation called on: [email protected] 
<Jan 5, 2010 10:44:55 PM EST> <Info> <EJB> <BEA-010227> <EJB Exception occurred during invocation from home or business: weblogic. 
[email protected] threw exception: javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active> 
<Jan 5, 2010 10:44:55 PM EST> <Debug> <JTA2PC> <BEA-000000> <BEA1-001859ECF50B251A451D: [EJB examples.session.stateless.RegisterUs 
er.registerNewUser(java.lang.String,java.lang.String)]: TX[BEA1-001859ECF50B251A451D] active-->rolling back 
... 
... 

Répondre

8

Après de nombreuses recherches, y compris l'essai de transactions gérées par un conteneur et gérées par l'utilisateur, il apparaît que le problème est que le type de transaction est spécifié comme RESOURCE_LOCAL. Dans ce cas, les règles suivantes:

* You must use the EntityManagerFactory to get an EntityManager 
* The resulting EntityManager instance is a PersistenceContext/Cache 
* An EntityManagerFactory can be injected via the @PersistenceUnit annotation only (not @PersistenceContext) 
* You are not allowed to use @PersistenceContext to refer to a unit of type RESOURCE_LOCAL 
* You must use the EntityTransaction API to begin/commit around every call to your EntityManger 
* Calling entityManagerFactory.createEntityManager() twice results in two separate EntityManager instances and therefor two separate PersistenceContexts/Caches. 
* It is almost never a good idea to have more than one instance of an EntityManager in use (don't create a second one unless you've destroyed the first) 

Dans mon cas, je avais besoin d'utiliser l'usine de gestionnaire pour accéder au entitymanager, et utiliser un persistenceUnit au lieu d'un persistenceContext. Le code suivant fonctionne très bien:

@Stateless 
@TransactionManagement(TransactionManagementType.CONTAINER) 

public class RegisterUser implements RegisterUserLocal { 

@PersistenceUnit(unitName = "SCBCDEntities") 
private EntityManagerFactory factory; 

public void registerNewUser(String username, String password) { 

    EntityManager entityManager = factory.createEntityManager(); 
    EntityTransaction entityTransaction = entityManager.getTransaction(); 
    entityTransaction.begin(); 

    User user = new User(); 
    user.setPassword(password); 
    user.setUsername(username); 

    entityManager.persist(user); 
    entityTransaction.commit(); 
} 
} 

Informations supplémentaires sur la configuration des transactions et les paramètres de la persistance.xml peut être trouvé ici: http://openejb.apache.org/3.0/jpa-concepts.html

1

Cela pourrait être parce que vous ne l'avez pas commencé une transaction. Essayez:

public void registerNewUser(String username, String password){ 
    entityManager.getTransaction().begin(); 
    User user = new User(); 
    user.setPassword(password); 
    user.setUsername(username); 
    entityManager.persist(user); 
    entityManager.getTransaction().commit(); 
} 

Bien que je préfère ne pas effectuer la gestion des transactions de cette façon. Au lieu de cela, je tendance à utiliser des transactions déclaratives de printemps, qui se présente comme suit:

@Transactional 
public void registerNewUser(String username, String password){ 
    User user = new User(); 
    user.setPassword(password); 
    user.setUsername(username); 
    entityManager.persist(user); 
} 

quand il est configuré.

Edit: Une autre possibilité est un problème que j'ai eue avec EclipseLink où il n'a pas été écrit tout à la base de données quand je courais dans un environnement J2SE (une application console pour charger des fichiers dans une base de données). Dans ce cas, je devais explicitement flush() le EntityManager pour obtenir tous les enregistrements écrits.

+0

Je crois comprendre que vous pouvez utiliser des transactions gérées par conteneur de la même manière que votre 2ème exemple le fait, mais en utilisant java normal au lieu de spring. Je pense que ceci est supposé être la valeur par défaut (si vous ne spécifiez rien), et que vous pouvez utiliser l'annotation @TransactionManagement (TransactionManagementType.BEAN) pour spécifier la gestion manuelle. –

+0

Avec votre 1er exemple, j'ai l'exception suivante: Exception lors de l'enregistrement de l'utilisateur javax.ejb.EJBException: EJB Exception:: java.lang.IllegalStateException: La méthode public abstrait javax.persistence.EntityTransaction javax.persistence.EntityManager.getTransaction () ne peut pas être invoqué dans le contexte d'un EntityManager JTA. –

3

Vous ne pouvez pas utiliser EntityTransaction (em.getTransaction()) car vous utilisez un gestionnaire d'entité gestionnaire de conteneur (injecté), vous devez donc vous fier au conteneur pour les transactions. Avez-vous défini des paramètres transactionnels pour le bean Stateless Session en XML? Si ce n'est pas le cas, cela devrait fonctionner comme la valeur par défaut "Obligatoire". Vous pouvez essayer d'annoter 'registerNewUser' avec @TransactionAttribute (TransactionAttributeType.REQUIRED)

Vous pouvez également créer une transaction utilisateur avant d'accéder à EM mais une transaction Container Managed serait préférable.

Questions connexes