I am working on a JPA, jsf2.0 Hibernate project. It is a management of the user's actions through a primefaces calendar that you can see here.
I managed to get user's actions and display them in the calendar, but when I want to add a new action it seems to work: I have no error message but in reality the action is not added in database. It seems like the persist method is not doing its job, it is not returning any error message so I don't know what to do to see why.
I put you here the 2 functions for these 2 actions (display and add):
Method to add an action (it does not work)
public void creerAction(Action action){
Date date = action.getDateAction();
action.setDateAction(date);
EntityManagerFactory emf = null;
try{
emf = Persistence.createEntityManagerFactory("GA2010-ejbPU-dev");
em = emf.createEntityManager();
em.persist(action);
FacesMessage message = new FacesMessage("Action " + action.getTexteAction()+ " ajouté avec succès");
FacesContext.getCurrentInstance().addMessage(null, message);
}catch(PersistenceException e){
System.out.println(e.getMessage());
}
}
and the method to get all actions of an user (it works)
public List<Action> getAllAction(){
HttpSession sess = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
String codeUser = (String) sess.getAttribute("codeUser");
EntityManagerFactory emf = null;
try{
emf = Persistence.createEntityManagerFactory("GA2010-ejbPU-dev");
em = emf.createEntityManager();
Query requete = em.createQuery(SELECT_ALL_ACTION);
requete.setParameter("codeUtilisateur", codeUser);
this.allAction= requete.getResultList();
}catch(Exception e){
this.message = new FacesMessage(e.getMessage()) ;
FacesContext.getCurrentInstance().addMessage( null, message );
}
return allAction;
}
And here is the declaration of my unit persistence
<persistence-unit name="GA2010-ejbPU-dev" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>dev</jta-data-source>
<class>entities.Utilisateur</class>
<class>entities.Action</class>
<properties>
<property name="eclipselink.target-server" value="SunAS9"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
<property name="eclipselink.application-location" value="C:/tmp"/>
</properties>
How can I see why persist does not persist and why I am not having an error message?
Persists need to be done from within a transaction. The object is not persisted until you commit the transaction:
Hibernate EntityManager tutorial
Related
The line mapping logic in the job config xml is as follows:
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="ID,NAME"/>
<property name="strict" value="false"/>
</bean>
</property>
<property name="fieldSetMapper">
<bean class="com.company.batch.mappers.EmpFieldSetMapper"/>
</property>
The field set mapper read logic is as follows:
fieldSet.readString("ID");
But while writing UT for EmpFieldSetMapper, I am getting below error:
java.lang.IllegalArgumentException: Cannot access columns by name without meta data
at org.springframework.batch.item.file.transform.DefaultFieldSet.indexOf(DefaultFieldSet.java:675)
at org.springframework.batch.item.file.transform.DefaultFieldSet.readString(DefaultFieldSet.java:169)
The UT is as follows:
#Before
public void setUp() throws Exception {
mapper = new EmpFieldSetMapper();
DefaultFieldSetFactory fieldSetFactory = new DefaultFieldSetFactory();
String[] inputValues = { "123", "RAJ" };
fieldSet = fieldSetFactory.create(inputValues);
}
#Test
public void testMapFieldSet() {
try {
Model model = mapper.mapFieldSet(fieldSet);
assertEquals("ID field mapping is wrong", "123", model.getId());
assertEquals("NAME field mapping is wrong", "RAJ", model.getName());
} catch (BindException e) {
fail("Exception during field set mapping");
}
}
I think I need to change the DefaultFieldSetMapper to something else but unsure about it. This issue can be resolved by replacing the column names with index but I want to retain the column names in EmpFieldSetMapper. So need suggestions.
I found the answer. Need to pass in column names as well.
String[] inputValues = { "123", "RAJ" };
String[] inputColumns = { "ID", "NAME" };
fieldSet = fieldSetFactory.create(inputValues, inputColumns);
I have recently migrated to JPA 2.0 (EclipseLink 2.4.2 Juno) in TomEE 1.7 in Eclipse IDE, As i am storing the values they are getting stored and retrieved fine, but they are not persisting into the database when is use entitymanager.flush()it is showing javax.persistence.TransactionRequiredException Here is my code
Create.java (register method)
public static int register(String first, String last, String email,
String date, String phone, String address, String pin, Login login) {
try {
System.out.println("registering persisting the entity");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("FirstEE");
EntityManager manager = emf.createEntityManager();
manager.getTransaction().begin();
//
// Query query = manager
// .createQuery("select l from Truck l");
Login log = login;
System.out.println(log.getUsername() + "username"
+ log.getPassword() + "password");
User reg = new User();
reg.setLogin(log);
reg.setDate(date);
reg.setEmail(email);
reg.setFirst(first);
reg.setLast(last);
reg.setPhone(phone);
reg.setAddress(address);
reg.setPin(pin);
manager.persist(reg);
manager.getTransaction().commit();
manager.flush();
manager.close();
emf.close();
// FacesContext.getCurrentInstance().addMessage("reg:result",
// new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error Message",
// "Registered Successfully"));
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage(
"Registered Successfully");
facesContext.addMessage(null, facesMessage);
System.out.println("after message global");
return 1;
} catch (Exception e) {
System.out.println("hai this is exception caught:" + e);
System.out.println("hai" + e.getMessage());
FacesContext.getCurrentInstance().addMessage(
"reg:result",
new FacesMessage("Something went wrong",
"\tSomething went wrong\t"));
// FacesContext facesContext = FacesContext.getCurrentInstance();
// FacesMessage facesMessage = new
// FacesMessage("Something went wrong");
// facesContext.addMessage(null, facesMessage);
}
return 0;
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="FirstEE" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>FirstEE</non-jta-data-source>
<!-- <exclude-unlisted-classes>false</exclude-unlisted-classes> -->
<class>com.jason.Entity.User</class>
<class>com.jason.ManagedBean.Login</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/yash" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="eclipselink.logging.level" value="FINEST" />
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
</persistence>
I cant figure out the problem data is getting retreived and stored but it is not updating and not getting persisted in database
The commit()method is committing your transaction immediately. Therefore, the changes are writting into the database & your previously open transaction also ends in this moment. When you call flush() afterwards, there is no open transaction so the flush() operation - complains as you experience it - with a javax.persistence.TransactionRequiredException. See also javax.persistence
Interface EntityManager#flush()
void flush()
Synchronize the persistence context to the underlying database.
Throws:
TransactionRequiredException - if there is no transaction
You should call the commit() method after you synced the state of your EntityManager, like so
manager.getTransaction.begin();
// ...
// do something with your entities in between
// ...
manager.persist(reg);
manager.flush(); // in your case: could also be skipped
// finally - if nothing fails - we are safe to commit
manager.getTransaction().commit();
Another hint:
You should avoid to mix your UI-side code (JSF...) with Backend code. This is generally considered 'spaghetti' anti-pattern here.
Moreover, do not open and close EntityManagerFactory every time (!) you call this UI-bound method (register(...)), as this is a performance killer - at least it produces unnecessary processing every time somebody tries to register here. At least, you should create an instance of EntityManagerFactory (or: EntityManager) as a field (via a DBService class) and reuse this to communicate with the application backend.
The error indicates you cant call flush outside of a transaction. Your code clearly shows you are calling flush right after calling manager.getTransaction().commit(). There is no need to call flush after commit, since the entityManager synchronizes to the database on commit or flush. You only use flush if you have a long running transaction and you want to synchronize at particular stages.
For the rest, turn on EclipseLink logging https://wiki.eclipse.org/EclipseLink/Examples/JPA/Logging and it will show you want it is doing on the commit/flush calls.
With this query, I succeed to retrieve a phone number in database:
import java.util.List;
import org.springframework.data.jpa.repository.JpaReposit ory;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.mc.appcontacts.domain.hibernate.Contact;
public interface ContactRepository extends JpaRepository<Contact, Integer> {
#Query("SELECT c.phoneNumber from Contact c WHERE LOWER(c.name) = LOWER(:name)")
String find(#Param("name") String name);
But is it possible to specify dynamically name of the property i want to retrieve in parameter?
In all tuto i've read on the net, i learn we can pass the value of the property in parameter (In my exemple : #Param("name") String name )
but what i want to pass in parameter is the name of the property not the value !
I know the exemple below is not correct but it's to give the general idea :
#Query("SELECT c.(property) from Contact c WHERE LOWER(c.name) = LOWER(:name)")
String find(#Param("name") String name, #Param("property") String property);
With property = phoneNumber (or an other property of my table).
Thank you for your help !!
I don't understand how to do that (everything is new for me):
I have read (and try) that jpql is defined like this :
import com.mysema.query.jpa.impl.JPAQuery;
import com.mc.appcontacts.repository.ContactRepository; // managed by spring data
//jpa repository
public class ServicesC {
#Autowired
private ContactRepository repository;
#PersistenceContext // try
private EntityManager em; // try
JPAQuery query = new JPAQuery(em); // try
public Contact getOne(Integer id) {
return repository.findOne(id);
}
public String findAtt(String att, String key){
String jpql = "SELECT c." + att + " from Contact c WHERE LOWER(c.name) = LOWER(:key)"; // try
List<Contact> l = (List<Contact>) em.createQuery(jpql); // try
return "test";
}
}
But it doesn't work (i'm not surprised...) :
2014-02-24 18:18:34.567:WARN::Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appMapping': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mc.appcontacts.service.ServiceC com.mc.appcontacts.mvc.MappingService.service; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Service' defined in file [C:\Professional\Workspaces\Eclipse\ContactMain\ContactCore\target\classes\com\mc\appcontacts\service\ServiceC.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.mc.appcontacts.service.ServiceC]: Constructor threw exception; nested exception is java.lang.NullPointerException:
java.lang.NullPointerException
at com.mysema.query.jpa.impl.JPAProvider.get(JPAProvider.java:72)
at com.mysema.query.jpa.impl.JPAProvider.getTemplates(JPAProvider.java:80)
at com.mysema.query.jpa.impl.JPAQuery.<init>(JPAQuery.java:46)
Must i define a second EntityManager only for jpql ? (Is it possible ? is it the right way ? I don't think so...)
I have already a EntityManager defin for Spring-data in xml file :
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Activate Spring Data JPA repository support -->
<jpa:repositories base-package="com.mc.appcontacts.repository" />
<!-- Declare a JPA entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/contacts/hibernate/persistence.xml" />
<property name="persistenceUnitName" value="hibernatePersistenceUnit" />
<!-- <property name="dataSource" ref="dataSource" /> -->
<property name="jpaVendorAdapter" ref="hibernateVendor" />
</bean>
<!-- Specify our ORM vendor -->
<bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${hibernate.showSql}" />
</bean>
<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Please help me ... how does it work ?
No, it's not possible to do that. You'll have to implement it by yourself by dynamically generating the JPQL query.
Using query parameyters is not an option, because query parameters can only be values to replace in a given prepared statement, and can't alter the nature of the query itself. So you'll have to do something like
String jpql = "select c." + property + " from ...";
I think for this use case of building queries dynamically your best bet would be to explore Criteria API, which is very suitable for such things. http://docs.oracle.com/javaee/6/tutorial/doc/gjitv.html
Hello everybody i'm looking for some help with the next problem:
i have a jpa/stateless ejb's proyect that works perfectly, it just does simple queries and persist operations, but now i need to execute a set of persist operations, if any of them fails, i must perform a rollback, so i found JTA can do the job but using this piece of source code:
#Stateless
public class ProjectBean implements IProject {
#Resource
javax.transaction.UserTransaction utx;
#PersistenceContext(unitName = "JPADB")
private EntityManager entityManager;
...
//more code
//this is part of a method
try{
utx.begin();
entityManager.joinTransaction();
for(Project p:projectResultList){
entityManager.persist(p);
}
utx.commit();
}catch(Exception e){
e.printStackTrace();
if(utx != null)
try {
utx.rollback();
} catch (IllegalStateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SystemException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//tx.rollback();
}
simply doesn't work, and this is how the persistence.xml looks like:
<persistence-unit name="JPADB">
<jta-data-source>java:jboss/datasources/OracleBic</jta-data-source>
<properties>
<property name="hibernate.show_sql" value ="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
</properties>
</persistence-unit>
really hope anyone can give me a tip or advice, i'm a newbie with jpa/jta concepts and i tried lots of codes i found in the web but i always obtain different errors (Wrong tx on thread: expected TransactionImple usertransaction begin,Cannot use an EntityTransaction while using JTA). thanks in advance.
Did you instruct your AS that you are going to handle transactions manually with
#TransactionManagement(TransactionManagementType.BEAN) on method level? I do not see the annotation on class level. Probably you have it on method level, but your code snipped is insufficient to make any guess.
Otherwise all transactions are Container managed and your code is not going to work. So you have to either put
#TransactionManagement(TransactionManagementType.BEAN)
on either a method or class level depends on requirements or you may want to allow your container to manage transactions for you and than you have to make changes that #remigio suggested to you.
It seems that the second approach is better in your case
remigio's comment is correct, #Stateless session beans control transaction boundaries with javax.ejb.#TransactionAttribute, if the annotation is absent all public methods are TransactionAttribute.REQUIRED. For more information, see http://download.oracle.com/otndocs/jcp/ejb-3_0-fr-eval-oth-JSpec/ (ejb-3_0-fr-spec-ejbcore.pdf).
UserTransaction is never used in a #Stateless session bean, but rather is used by clients that are calling the bean to demarcate a wider transaction window than that of just the method call itself.
I'm little confused how transactions work in EJBs. I've always thought that all transaction aware objects in container managed EJBs are all committed or rollbacked when a method with TransactionAttribute=REQUIRED_NEW is finished but unfortunately it's not in my case. I don't have my code in front of me so I can't include whole example but what I ask for is just the confirmation of the idea of how it should work.
Only key points of my code just from the top of my head are presented:
EntityManager em; //injected
[...]
public void someEJBMethod() {
[...]
em.persist(someObject);
[...]
Session session = JpaHelper.getEntityManager(em).getActiveSession();
[...]
session.executeQuery(query, args);
[...]
if (someCondition) {
throw new EJBException();
}
[...]
}
And my problem is that when EJBException is thrown database changes caused by em.persist are rollbacked but changes caused by session.executeQuery are committed.
Is it expected behaviour?
I'm using Glassfish 3.1.2, EclipseLink 2.3.2 with Oracle database
Update (test case added)
I've created working test case to show the problem
First database objects:
create table txtest
(id number not null primary key,
name varchar2(50) not null);
create or replace function txtest_create(p_id number, p_name varchar2) return number is
begin
insert into txtest
(id, name)
values
(p_id, p_name);
return p_id;
end;
Definition of a database connection (from domain.xml)
<jdbc-connection-pool driver-classname="" datasource-classname="oracle.jdbc.pool.OracleConnectionPoolDataSource" res-type="javax.sql.ConnectionPoolDataSource" description="" name="TxTest">
<property name="User" value="rx"></property>
<property name="Password" value="rx"></property>
<property name="URL" value="jdbc:oracle:thin:#test:1529:test"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="TxTest" description="" jndi-name="jdbc/TxTest"></jdbc-resource>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="txTest">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/TxTest</jta-data-source>
<class>txtest.TxTest</class>
</persistence-unit>
</persistence>
session bean:
#Stateless
public class TxTestBean implements TxTestBeanRemote, TxTestBeanLocal {
private static Logger log = Logger.getLogger(TxTestBean.class.getName());
#PersistenceContext(unitName="txTest")
EntityManager em;
#SuppressWarnings({ "unchecked", "rawtypes" })
#Override
public void txTest(boolean throwException) {
TxTest t = new TxTest();
t.setId(1L);
t.setName("em.persist");
em.persist(t);
Session session = JpaHelper.getEntityManager(em).getActiveSession();
log.info("session : " + String.valueOf(System.identityHashCode(session)));
PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall();
call.setProcedureName("txtest_create");
call.addNamedArgument("p_id", JDBCTypes.NUMERIC_TYPE);
call.addNamedArgument("p_name", JDBCTypes.VARCHAR_TYPE, 50);
call.setResult(JDBCTypes.NUMERIC_TYPE);
ValueReadQuery query = new ValueReadQuery();
query.setCall(call);
query.addArgument("p_id");
query.addArgument("p_name");
t = new TxTest();
t.setId(2L);
t.setName("session.executeQuery");
List args = new ArrayList();
args.add(t.getId());
args.add(t.getName());
Long result = ((Number)session.executeQuery(query, args)).longValue();
//added to see the state of txtest table in the database before exception is thrown
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("result=" + result.toString());
if (throwException) {
throw new EJBException("Test error #1");
}
}
}
entries from server.log when txTest(true) is invoked:
[#|2012-05-21T12:04:15.361+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|client acquired: 21069550|#]
[#|2012-05-21T12:04:15.362+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|TX binding to tx mgr, status=STATUS_ACTIVE|#]
[#|2012-05-21T12:04:15.362+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|acquire unit of work: 16022663|#]
[#|2012-05-21T12:04:15.362+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|persist() operation called on: txtest.TxTest#11b9605.|#]
[#|2012-05-21T12:04:15.363+0200|INFO|glassfish3.1.2|txtest.TxTestBean|_ThreadID=167;_ThreadName=Thread-2;|session : 16022663|#]
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.query|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Execute query ValueReadQuery()|#]
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Connection acquired from connection pool [read].|#]
[#|2012-05-21T12:04:15.364+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|reconnecting to external connection pool|#]
[#|2012-05-21T12:04:15.365+0200|FINE|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.sql|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|
DECLARE
p_id_TARGET NUMERIC := :1;
p_name_TARGET VARCHAR(50) := :2;
RESULT_TARGET NUMERIC;
BEGIN
RESULT_TARGET := txtest_create(p_id=>p_id_TARGET, p_name=>p_name_TARGET);
:3 := RESULT_TARGET;
END;
bind => [:1 => 2, :2 => session.executeQuery, RESULT => :3]|#]
[#|2012-05-21T12:04:15.370+0200|FINEST|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|Connection released to connection pool [read].|#]
[#|2012-05-21T12:04:35.372+0200|INFO|glassfish3.1.2|txtest.TxTestBean|_ThreadID=167;_ThreadName=Thread-2;|result=2|#]
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|TX afterCompletion callback, status=ROLLEDBACK|#]
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.transaction|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|release unit of work|#]
[#|2012-05-21T12:04:35.372+0200|FINER|glassfish3.1.2|org.eclipse.persistence.session.file://txTest/_txTest.connection|_ThreadID=167;_ThreadName=Thread-2;ClassName=null;MethodName=null;|client released|#]
[#|2012-05-21T12:04:35.373+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=167;_ThreadName=Thread-2;|EJB5184:A system exception occurred during an invocation on EJB TxTestBean, method: public void txtest.TxTestBean.txTest(boolean)|#]
[#|2012-05-21T12:04:35.373+0200|WARNING|glassfish3.1.2|javax.enterprise.system.container.ejb.com.sun.ejb.containers|_ThreadID=167;_ThreadName=Thread-2;|javax.ejb.EJBException: Test error #1
What surprised me the most is that when I checked txtest table during this 20 sec. sleep the record (2,"session.executeQuery") was already there.
It seems like session.executeQuery somehow commits its work (but not the whole transaction).
Can someone explain this behaviour?
I'm not sure what JpaHelper.getEntityManager(em).getActiveSession(); is supposed to do exactly, but it seems likely this doesn't return a container managed entity manager. Depending on how it's exactly implemented, this may not participate in the ongoing (JTA) transaction.
Normally though, transactional resources all automatically participate in the ongoing JTA transaction. In broad lines they do this by checking if there's such on ongoing transaction, and if there indeed is, they register themselves with this transaction.
In EJB, REQUIRES_NEW is not the only mode that can start a transaction 'REQUIRES' (the default) also does this incase the client didn't start a transaction.
I've got it solved!!!
It turned out that EclipseLink uses read connection pools for processing read queries (and obviously that kind of pools uses autocommit or even don't use transactions at all) and default connection pools for data modification queries. So what I had to do was changing:
ValueReadQuery query = new ValueReadQuery();
into
DataModifyQuery query = new DataModifyQuery();
and it works like a charm.
Update
DataModifyQuery doesn't allow to get the result of the function. It returns the number of modified rows. So I got back to ValueReadQuery but used configuration parameter in persistance.xml
<property name="eclipselink.jdbc.exclusive-connection.mode" value="Always"/>
This parameter tells EclipseLink to use default connection pool for both reads and writes.