Java – eclipse link, JPA, Oracle, Weblogic, calling persist do not commit the database
I'm just starting to look at Java persistence (currently using eclipse's eclipse link default provider) Basically just create an object and try to persist it to DB (Oracle) My understanding is that when the method returns, the default transactional should commit the new object to the database, but nothing seems to happen Any ideas?
@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. In 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>
Entity class:
@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; } }
In addition, in order to reply to this question, use the code I listed, and the log shows the execution commit (some details have been deleted for brevity)
[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: examples.persistence.User@191ed96. <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,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 ... ...
But if I add 'flush' after insisting, I will get '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)',Pooled Threads])--PERSIST operation called on: examples.persistence.User@1717dea. <Jan 5,2010 10:44:55 PM EST> <Info> <EJB> <BEA-010227> <EJB Exception occurred during invocation from home or business: weblogic. ejb.container.internal.StatelessEJBLocalHomeImpl@1509b8 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 ... ...
Solution
After a lot of investigation, including attempting container managed and user managed transactions, it seems that the problem is that the transaction type is specified as resource_ LOCAL. In this case, the following rules apply:
* 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)
In my example, I need to use the manager factory to access entitymanager and use persistenceunit instead of persistencecontext The following code works well:
@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(); } }
About configuring transactions and persistence For additional information about settings in XML, please visit: http://openejb.apache.org/3.0/jpa-concepts.html