Eclipselink JPA, Oracle, Weblogic, Calling Persist не передает в базу данных - PullRequest
3 голосов
/ 05 января 2010

Я только начинаю смотреть на постоянство 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
...
...

Ответы [ 3 ]

8 голосов
/ 06 января 2010

После долгих исследований, включая попытки как транзакций, управляемых контейнером, так и транзакций, управляемых пользователями, похоже, что проблема заключается в том, что тип транзакции указан как 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

3 голосов
/ 05 января 2010

Вы не можете использовать EntityTransaction (em.getTransaction ()), потому что вы используете Диспетчер управляемых контейнеров (внедренный), поэтому вы должны полагаться на контейнер для транзакций. Вы установили какие-либо транзакционные параметры для bean-компонента сеанса без сохранения состояния в XML? Если у вас его нет, он должен работать, так как по умолчанию должно быть указано «Требуется». Вы можете попробовать аннотировать 'registerNewUser' с помощью @TransactionAttribute (TransactionAttributeType.REQUIRED)

В качестве альтернативы вы могли бы создать пользовательскую транзакцию перед доступом к EM, но транзакция с управлением контейнером была бы лучше.

1 голос
/ 05 января 2010

Это может быть потому, что вы еще не начали транзакцию. Попробуйте:

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, чтобы получить все записанные записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...