I want to do an asynchronous transactional action in a ejb method by calling a stored procedure. When I call the methot I give below error:
java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
Bean
#Stateless
public class FileSearchDAO {
private static Logger logger = LoggerFactory.getLogger(FileSearchDAO.class);
#PersistenceContext(unitName = "FileSearchPU")
private EntityManager entityManager;
#Asynchronous
public Future<String> saveFile(String fileNo, List<String> runningFiles) {
try {
entityManager.getTransaction().begin();
entityManager.createNativeQuery(
" BEGIN prc_save_file (:fileNo); END;")
.setParameter("fileNo", fileNo).executeUpdate();
entityManager.getTransaction().commit();
runningFiles.remove(fileNo);
return new AsyncResult<>(fileNo);
} catch (Exception ex) {
ex.printStackTrace();
return new AsyncResult<>(ex.getMessage());
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="FileSearchPU" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/FileSearchDS</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.transaction.jta.platform"
value="${hibernate.transaction.jta.platform}"/>
</properties>
</persistence-unit>
</persistence>
I haven't any Entity class. I just want to call the stored procedure which updates some table.
In a JTA managed datasource container handles transactions in a distributed way so also handling concurrency outside your application for example.
EntityManagers transaction can not be used because it is local transaction so something that is then not handled outside your application. Read also this post for more information.
If you need transaction you should use UserTransaction
#Resource
UserTransaction utx;
To use it your annotate your bean
#TransactionManagement(TransactionManagementType.BEAN)
and use transaction like
utx.begin();
...
utx.commit(); // utx.rollback();
Related
I use JPA with Hibernate in my Servlet, which is hosted by Tomcat.
The database I use is MySQL.
I do not use JNDI or a Connection Pool.
This is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="pixxio-jpa" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>de.java2enterprise.onlineshop.model.AccessToken</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.88.88:3306/felix1_0"/>
<property name="javax.persistence.jdbc.user" value="felix1_0"/>
<property name="javax.persistence.jdbc.password" value="mypassword"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
</properties>
</persistence-unit>
</persistence>
This is the important code in my Servlet:
void doubleDatabaseConnection(PrintWriter out) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("pixxio-jpa", null);
EntityManager em = emf.createEntityManager();
EntityManager em2 = emf.createEntityManager();
getDatabaseSessionId(out, em);
getDatabaseSessionId(out, em2);
em.close();
em2.close();
emf.close();
}
void getDatabaseSessionId(PrintWriter out, EntityManager entityManager) {
Query q = entityManager.createNativeQuery("SELECT CONNECTION_ID();");
BigInteger result = (BigInteger) q.getSingleResult();
out.println("<br>Database Session Id: " + result);
}
This is printed by the servlet:
Database Session Id: 51317
Database Session Id: 51317
I assumed that the actual database connection is established, when the EntityManager is created. Therefore I assumed that the two MySQL-Connection-IDs from the two EntityManager instances differ.
Is it possible to create multiple distinct database connections from one EntityManagerFactory instance?
I want to note that changing the JPA provider is an option for me.
Hibernate use the same connection if you do not need a transaction.
If you start a transation, you get a new connection
EntityManagerFactory emf = Persistence.createEntityManagerFactory("pixxio-jpa", null);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
getDatabaseSessionId(System.out, em);
getDatabaseSessionId(System.out, em2);
em.close();
em2.close();
emf.close();
Updated
FYI: Hibernate use it's own connection pool if you do not set an connection pool (min=1; max=20).
I'm trying to inject an EntityManager into my application using CDI but the EntityManager is null when trying to use it.
Here is my code I followed several tutorial on how to inject EntityManager and I use the same code as in those tutorial.
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD})
public #interface DevDatabase {
}
#Singleton
public class JPAResourceProducer {
#Produces
#PersistenceContext(unitName = "DevPU")
#DevDatabase
private EntityManager em;
}
the persistence.xml
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="DevPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>entity.MyEntity</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/MyDB"/>
<property name="javax.persistence.jdbc.user" value="appuser"/>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.password" value="apppassword"/>
</properties>
</persistence-unit>
</persistence>
This is how I use it in my DAO
public abstract class GenericDAO<T> {
#DevDatabase
#Inject
private EntityManager em;
private final Class<T> entityClass;
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void beginTransaction() {
em.getTransaction().begin();
}
}
Concrete DAO
public class MyEntityDAO extends GenericDAO<MyEntity> {
public MyEntityDAO() {
super(MyEntity.class);
}
}
And somewhere in my code when I call for exemple myEntityDao.beginTransaction() I get a NullPointerException cause the injected EntityManager is null.
Is there anything I am missing in my producer ?
#PersistenceContext does not work out-of-the-box in a servlet container like tomcat. It works in a Java EE container.
So your EntityManager field stays to null because #PersistencContext has no effect in Tomcat, even using Weld-servlet.
You may add a ServletListener to bootstrap a JPA implementation, probalby hibernate in your case. Then you may obtain EntityManagerinstances through #Inject.
Note that you should also provide a JPA implementation (like hibernate), the same way you did for Weld.
You can try doing something like: Injecting EntityManager with a producer in tomcat
This is my first real exposure to JPA and I'm trying to run the simplest of update statements. I'm running inside a jBoss 7.1.x server using Hibernate as JPA implementation. Any help would be greatly appreciated..
Here is my producer method for EntityManager:
#ApplicationScoped
public class EntityManagerProducer
{
#PersistenceContext
private EntityManager entityManager;
#Produces
#RequestScoped
public EntityManager getEntityManager()
{
return entityManager;
}
}
Here is the DAO method that tries to perform the update:
#Inject EntityManager em;
public void updateRequestStatus(String requestNumber, String newStatus)
{
em.getTransaction().begin();
ServiceRequestEntity serviceRequestToUpdate = em.find(RequestEntity.class, requestNumber);
requestToUpdate.setStatus(newStatus);
em.merge(serviceRequestToUpdate);
em.getTransaction().commit();
}
Here is persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="database" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:/jdbc/myDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.use_sql_comments" value="true" />
</properties>
</persistence-unit>
</persistence>
Here is the error message (can provide full stacktrace if needed -it chokes on the "merge" line):
javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
....
at org.jboss.weld.proxies.EntityManager$-1727851269$Proxy$_$$_WeldClientProxy.merge(EntityManager$-1727851269$Proxy$_$$_WeldClientProxy.java) [weld-core-1.1.5.AS71.Final.jar:]
#Inject annotation on EntityManager I don't think will work. With your current setup I believe you want to inject your EntityManagerProducer class (which is not used in your DAO), and then call your getEntityManager method on it.
The other option would just be to use the #PersistenceContext in your DAO.
You also may want to specify the name of your persistence context as specified in your persistence.xml like:
#PersistenceContext(name="database")
I am trying to create a web app using JSF and EJB 3.0.
I am using plain JSF, Glassfish Server, Hibernate as my persistance provider. My database is apache derby.
Here my Stateless Session bean as follows:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class StudentServiceBean implements StudentService{
#PersistenceContext(unitName="forPractise")
private EntityManager entityMgr;
#Resource
private SessionContext sessionContext;
#Override
public List<StudentVO> fetchStudentListOrderByStudentId(boolean flag){
List<StudentEntity> studentList = null;
TypedQuery<StudentEntity> studentQuery = null;
List<StudentVO> studentVOList = null;
String queryDesc = "select s from StudentEntity s order by s.studentId desc";
String query = "select s from StudentEntity s order by s.studentId";
try{
if(!flag){
studentQuery = entityMgr.createQuery(query,StudentEntity.class);
}else{
studentQuery = entityMgr.createQuery(queryDesc,StudentEntity.class);
}
studentList = studentQuery.getResultList();
studentVOList = new ArrayList<StudentVO>();
for(StudentEntity studentE : studentList){
studentVOList.add(new StudentVO(String.valueOf(studentE.getStudentId()),studentE.getStudentName(),studentE.getContactNumber()));
}
}catch(Exception e){
System.out.println(" EXCEPTION IN "+this.getClass().getName()+" in method fetchStudentListOrderByStudentId "+e);
}
return studentVOList;
}
And this is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="forPractise" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/app</jta-data-source>
<class>com.entity.StudentEntity</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup" />
</properties>
</persistence-unit>
</persistence>
What happens is on load of the JSP page, the getter method of StudentList is called -
inside the getter method I have written logic that if studentList is empty then call the studentService.fetchStudentListOrderByStudentId(true);.
But when I do this I get an exception:
EXCEPTION IN com.bb.StudentServiceBean in method
fetchStudentListOrderByStudentId
org.hibernate.service.UnknownServiceException: Unknown service
requested
[org.hibernate.service.jdbc.connections.spi.ConnectionProvider]
Can you please tell me what I am missing, or where I am going wrong?
Thanks.
You indicate that you are using Hibernate 4.x, but the class you mentioned afaik is only valid for JPA 1.0 and Hibernate 3.x. Try removing the following line from your configuration:
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup" />
Just in case it's of any interest, I got this error on Jetty when trying to start a Hibernate session:
Unknown service requested [org.hibernate.service.jdbc.connections.spi.ConnectionProvider]
The root cause was a previous Exception (a few seconds earlier in the logs) which caused the spring context (WebAppContext) to fail to initialize.
Once I fixed the spring context, the "Unknown service requested" fixed itself. So, if you're seeing this error it's worth checking for earlier errors before investigating too much..
I have my ear-project deployed in jboss 5.1GA.
From webapp i don't have problem, the lookup of my ejb3 work fine!
es:
ShoppingCart sc= (ShoppingCart)
(new InitialContext()).lookup("idelivery-ear-1.0/ShoppingCartBean/remote");
also the iniection of my EntityManager work fine!
#PersistenceContext
private EntityManager manager;
From test enviroment (I use Eclipse) the lookup of the same ejb3 work fine!
but the lookup of entitymanager or PersistenceContext don't work!!!
my good test case:
public void testClient() {
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost");
Context context;
try{
context = new InitialContext(properties);
ShoppingCart cart = (ShoppingCart) context.lookup("idelivery-ear-1.0/ShoppingCartBean/remote"); // WORK FINE
} catch (Exception e) {
e.printStackTrace();
}
}
my bad test :
EntityManagerFactory emf = Persistence.createEntityManagerFactory("idelivery");
EntityManager em = emf.createEntityManager(); //test1
EntityManager em6 = (EntityManager) new InitialContext().lookup("java:comp/env/persistence/idelivery"); //test2
PersistenceContext em3 = (PersistenceContext)(new InitialContext()).lookup("idelivery/remote"); //test3
my persistence.xml
<persistence-unit name="idelivery" transaction-type="JTA">
<jta-data-source>java:ideliveryDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" /><!--validate | update | create | create-drop-->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
my datasource:
<datasources>
<local-tx-datasource>
<jndi-name>ideliveryDS</jndi-name>
...
</local-tx-datasource>
</datasources>
I need EntityManager and PersistenceContext to test my query before build ejb...
Where is my mistake?
Server-side EntityManager cannot be serialized so that you can use it as a client side EntityManager. That would mean that EntityManager referenced on the client-side still can talk to the database, use connection pool, etc. It is impossible (think of firewall, which protects database server, for instance).
If you need to test JPA, use local EntityManager without JTA transactions. If you want to test EJBs you need to simulate whole EJB container. You can use Spring Pitchfork or Glassfish 3 embedded container (the latter option is easier).
I need to test JPA, use local EntityManager without JTA transactions!
I followed your suggestion:I created new persistence.xml with a new persistence-unit
<persistence-unit name="ideliveryTest" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>it.idelivery.model.Category</class>
<class>it.idelivery.model.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/application"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>
</properties>
</persistence-unit>
and in my test case:
try {
logger.info("Building JPA EntityManager for unit tests");
emFactory = Persistence.createEntityManagerFactory("ideliveryTest");
em = emFactory.createEntityManager();
} catch (Exception ex) {
ex.printStackTrace();
fail("Exception during JPA EntityManager instanciation.");
}
work fine!
In my maven project i put persistence.xml with persistence-unit type="RESOURCE_LOCAL" in src/test/resources
and i put persistence.xml with persistence-unit type="JTA" in src/main/resources
by this way I have two separates enviroment. One for test and one for production.
it's a best practice?