【问题标题】:Eclipselink JPA, Oracle, Weblogic, Calling Persist does not commit to databaseEclipselink JPA、Oracle、Weblogic、Calling Persist 不提交数据库
【发布时间】:2011-01-01 13:18:29
【问题描述】:

我刚刚开始了解 java 持久性(目前使用 eclipse 的默认提供程序 eclipselink)。基本上只是创建一个对象并尝试将其持久化到数据库(Oracle)。我的理解是,默认事务性应该在方法返回时将新对象提交到数据库,但似乎没有发生任何事情。有什么想法吗?

@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>

实体类:

@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;
 }

}

另外,为了回应对这个问题的回复,我列出了日志中的代码显示提交正在执行(为简洁起见,删除了一些细节)

[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, 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
...
...

但是如果我在持久化之后添加“flush”,我会得到“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: 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
...
...

【问题讨论】:

    标签: java jpa persistence eclipselink


    【解决方案1】:

    经过大量调查,包括尝试容器管理和用户管理的事务,问题似乎在于事务类型被指定为 RESOURCE_LOCAL。在这种情况下,以下规则适用:

    *  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)
    

    在我的例子中,我需要使用管理器工厂来访问实体管理器,并使用persistenceUnit 而不是persistenceContext。以下代码可以正常工作:

    @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();
     }
    }
    

    有关配置事务和persistence.xml 中的设置的其他信息可以在这里找到:http://openejb.apache.org/3.0/jpa-concepts.html

    【讨论】:

      【解决方案2】:

      您不能使用 EntityTransaction (em.getTransaction()),因为您使用的是容器托管实体管理器(注入),因此您必须依赖容器进行交易。您是否在 XML 中为无状态会话 bean 设置了任何事务设置?如果您还没有,那么它应该可以正常工作,因为默认值应该是“必需的”。您可以尝试使用 @TransactionAttribute(TransactionAttributeType.REQUIRED) 注释“registerNewUser”

      或者,您可以在访问 EM 之前创建用户事务,但容器管理事务会更好。

      【讨论】:

        【解决方案3】:

        这可能是因为您尚未开始交易。试试:

        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();
        }
        

        虽然我不喜欢以这种方式进行事务处理。相反,我倾向于使用 Spring 的声明式事务,它看起来像这样:

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

        配置时。

        编辑: 另一种可能性是我曾经在使用 EclipseLink 时遇到的问题,当我在 J2SE 环境中运行它时,它没有将所有内容都写入数据库(一个控制台应用程序,用于将一些文件加载​​到一个数据库)。在那种情况下,我必须明确地 flush() EntityManager 才能写入所有记录。

        【讨论】:

        • 据我了解,您可以像第二个示例一样使用容器管理的事务,但使用普通 java 而不是 spring。我认为这应该是默认的(如果您不指定任何内容),并且您可以使用注释 @TransactionManagement(TransactionManagementType.BEAN) 来指定手动处理。
        • 对于您的第一个示例,我有以下异常:注册用户时出现异常 javax.ejb.EJBException:EJB 异常::java.lang.IllegalStateException:方法 public abstract javax.persistence.EntityTransaction javax。 persistence.EntityManager.getTransaction() 不能在 JTA EntityManager 的上下文中调用。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-27
        • 2015-05-29
        • 2016-10-15
        • 1970-01-01
        • 2017-10-10
        • 2016-11-07
        • 2014-01-08
        相关资源
        最近更新 更多