2010-01-05 3 views
3

Я только начинаю смотреть на постоянство Java (на данный момент с поставщиком eclipelink по умолчанию для eclipse). В основном просто создавая объект и пытаясь сохранить его в db (Oracle). Я понял, что транзакционная транзакция по умолчанию должна передать новый объект в базу данных при возврате метода, но ничего не происходит. Есть идеи?Eclipselink JPA, Oracle, Weblogic, Calling Persist не связывается с базой данных

@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 Класс:

@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: [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 
... 
... 

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

ответ

8

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

В моем случае, мне нужно использовать менеджер фабрики, чтобы получить доступ к EntityManager и использовать 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(); 
} 
} 

Дополнительная информация о настройке транзакций и настройках настойчивости.xml можно найти здесь: http://openejb.apache.org/3.0/jpa-concepts.html

1

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

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

при настройке.

Edit: Другая возможность это проблема, которую я когда-то с EclipseLink, где он не писал все в базе данных, когда я запустить его в среде J2SE (консольное приложение, чтобы загрузить некоторые файлы в базу данных). В этом случае я должен был явно указать flush()EntityManager, чтобы получить все записанные записи.

+0

Насколько я понимаю, вы можете использовать транзакции, управляемые контейнером, так же, как это делает ваш второй пример, но с использованием обычной java вместо пружины. Я думаю, что это должно быть значение по умолчанию (если вы ничего не укажете), и что вы можете использовать аннотацию @TransactionManagement (TransactionManagementType.BEAN), чтобы указать ручную обработку. –

+0

С вашим 1-м примером у меня есть следующее исключение: Исключение при регистрации пользователя javax.ejb.EJBException: EJB Exception:: java.lang.IllegalStateException: метод public abstract javax.persistence.EntityTransaction javax.persistence.EntityManager.getTransaction () не может быть вызван в контексте JTA EntityManager. –

3

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

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