I am working with Hibernate 4.3.8 on a web app and It looks like that the persist() method does not update the PersistentContext (cache level 1). Here is my configuration and the singleton to manage the persistent operations:
Hibernate configuration
<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/irm"/>
<property name="hibernate.connection.username" value="nrossi"/>
<property name="hibernate.connection.password" value="nicolas"/>
<property name="hibernate.connection.pool_size" value="5"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.max_fetch_depth" value="5"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
Persistence Manager
public class PersistenceManager
{
private static final Logger log = LogManager.getLogger();
private static final EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
static
{
emf = Persistence.createEntityManagerFactory("PersistenceUnit");
threadLocal = new ThreadLocal<EntityManager>();
}
public static EntityManager getEntityManager()
{
EntityManager em = threadLocal.get();
if (em == null)
{
em = emf.createEntityManager();
threadLocal.set(em);
}
return em;
}
public static <T>T get(Class<T> clazz, Object id)
{
return getEntityManager().find(clazz, id);
}
public static void save(Object object)
{
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try
{
em.persist(object);
et.commit();
}
catch (Exception e)
{
et.rollback();
throw new RuntimeException("Error saving object", e);
}
}
}
I update a model calling PersistenceManager.save(model) and it updates the record on the database, but after that when I call PersistenceManager.get(model.id) it returns the model from memory with the old values. It looks like the persist method is not updating the PersistenceCache.
By the way, If I call the PersistenceManager.get(model.id) on a new thread (i.e. incognito window) it returns the updated model.
I tried adding a refresh call em.refresh(model) after the commit and It is working, but I am not sure if this is the right way to get the context updated.
Updated info
I coded a simple JSP page just to reproduce the behavior. If I update the entity description and wait 5' and refresh the page It returns the old value:
<%#page import="com.identicum.framework.persistence.PersistenceManager"%>
<%#page import="com.identicum.irm.core.model.Entity"%>
<%
Entity entity = PersistenceManager.get(Entity.class, 1L);
String value = request.getParameter("entityName");
if(value != null)
{
entity.setDescription(value);
PersistenceManager.save(entity);
}
%>
<html>
<body>
Entity description: <b><%= entity.getDescription() %></b>
<br>
<br>
<form method="post">
Enter new entity description <br>
<input type="text" name="entityName"/>
<input type="submit" />
</form>
</body>
</html>
** New information **
My PersistenceManager is a copy of this suggestion. My application is an Application-managed EntityManager. I have to access to the same EntityManager during the lifecycle of each request. That's the reason this approach. Is there any other way to implement this ?
First of all persist() is for new entities (no record on database).
If you want to change an object you must use merge().
But your problem is that you probably are in a multi threaded environment.
So you cannot use ThreadLocal. Each thread will have his own PersistenceManager.
What app server or web container are you using?
I finally fixed it changing the way I get and close the EntityManager. Now I get the EntityManager from the EntityManagerFactory at the beginning of each request (on my Rest Dispatcher) and close it at the end. In this way each request has his own PersistentContext.
The PersistenceMangaer.java is almost the same. The main difference is that I removed the EntityManagerFactory reference to the ApplicationServiceContext and I call the setEntityManager() outside the class. Here is an example:
PersistenceManager.setEntityManager(PersistenceFactory.createEntityManager);
FooService.createObject1();
FooService.createObject2();
PersistenceManager.closeEntityManager();
These links where helpful to find the problem:
Best practice to get EntityManagerFactory
Should JPA Entity Manager be closed?
http://www.objectdb.com/java/jpa/start/connection
Related
I have a mySQL database for manage user information, and I am using JTA datasource for my mySQL database, here is what the persistence.xml look like:
<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="SensorCloudPU" transaction-type="JTA">
<jta-data-source>java:/SensorCloudPU</jta-data-source>
<!-- <non-jta-data-source>java:/SensorCloudPU</non-jta-data-source> -->
<class>com.sensorhound.common.domain.impl.AnomalousInfo</class>
<class>com.sensorhound.common.domain.impl.Code</class>
<class>com.sensorhound.common.domain.impl.Device</class>
<class>com.sensorhound.common.domain.impl.Executable</class>
<class>com.sensorhound.common.domain.impl.Group</class>
<class>com.sensorhound.common.domain.impl.GroupAlert</class>
<class>com.sensorhound.common.domain.impl.GroupRule</class>
<class>com.sensorhound.common.domain.impl.GroupRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.GroupRuleStatus</class>
<class>com.sensorhound.common.domain.impl.Node</class>
<class>com.sensorhound.common.domain.impl.NodeAlert</class>
<class>com.sensorhound.common.domain.impl.NodeRule</class>
<class>com.sensorhound.common.domain.impl.NodeRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.Organization</class>
<class>com.sensorhound.common.domain.impl.PastGroupStatus</class>
<class>com.sensorhound.common.domain.impl.Trace</class>
<class>com.sensorhound.common.domain.impl.TrainingSession</class>
<class>com.sensorhound.common.domain.impl.User</class>
<class>com.sensorhound.common.domain.impl.Role</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value = "false" />
<property name="hibernate.connection.autocommit" value="true" />
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
<property name="transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="jta.UserTransaction" value="java:jboss/UserTransaction"/>
</properties>
</persistence-unit>
</persistence>
And I have an endpoint like this:
#Path("/delete")
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response deleteUser(#FormParam("organization_id") Integer organizationId,
#FormParam("username") String username) throws JsonProcessingException, NotSupportedException,
SystemException, SecurityException, IllegalStateException, RollbackException,
HeuristicMixedException, HeuristicRollbackException, NamingException {
Organization org = organizationDAO.getByOrganizationId(organizationId);
userDao.deleteUserByUserNameAndOrganization(username, org);
return Response.status(Response.Status.OK).build();
}
And the DAO is like this:
public class userDAO {
#PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
#Resource
protected UserTransaction utx;
public void deleteUserByUserNameAndOrganization(String userName, Organization org)
throws NotSupportedException, SystemException, SecurityException, IllegalStateException,
RollbackException, HeuristicMixedException, HeuristicRollbackException {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u == null) {
return;
}
utx.begin();
this.em.remove(u);
utx.commit();
}
}
But every time when I load the page and try to delete the from the database, I got this error:
Resource lookup for injection failed: java:jboss/UserTransaction]
UserTransaction [Root exception is java.lang.IllegalStateException: WFLYEJB0137: Only session and message-driven beans with bean-managed transaction demarcation are allowed to access UserTransaction]
You can't use UserTransaction in an EJB, unless you add #TransactionManagement(BEAN)
What TransactionManagement does is
Specifies whether a session bean or message driven bean has container managed transactions or bean managed transactions. If this annotation is not used, the bean is assumed to have container-managed transaction management.
#TransactionManagement(BEAN)
public class userDAO {
Since you are primarily concerned with transaction management I suggest that you convert your DAO into an EJB. It only takes one line:
#Stateless
public class userDAO {
#PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
public void deleteUserByUserNameAndOrganization(String userName, Organization org) {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u != null) {
this.em.remove(u);
}
}
}
and you can see that it simplifies things significantly. EJBs give you JTA transaction demarcation (and rollback if needed) for free.
This will work even if you are building a WAR only deployment.
You could also add #Stateless to your JAX-RS endpoint if you want. At the very least you will get a bit more monitoring than you may otherwise have.
I have a problem with my new app. It's webapp with JAX-RS REST API, I have placed it on Tomcat 9.
Everything was good, my app can fetch data from localhost database (PSQL). I don't know why, but when i want to persist data -> it's returning me no error at all, but there is no mark after persisting data on database.
#POST
#Produces(MediaType.APPLICATION_JSON )
#Path("/register")
public Response register(#FormParam("email") String email, #FormParam("password") String password,
#FormParam("phoneNumber") String phoneNumber) {
UserEntity newUser = new UserEntity();
newUser.setEmail(email);
newUser.setPassword(password);
newUser.setPhoneNumber(phoneNumber);
newUser.setEntryDate(new Date());
AuthorizationDAO.put(newUser);
and DAO method:
public static <T extends AbstractTechnicalEntity> void put(T entity) {
em.persist(entity);
}
It's not a problem with connection - as I said, I can select data from this database, even from this table.
persistence.xml - > database conf
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/*****" />
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.user" value="******" />
<property name="javax.persistence.jdbc.password" value="*****" />
<property name="hibernate.show_sql" value="true" />
</properties>
Any ideas?
I'm creating an application with Hibernate JPA and I use c3p0 for connection pooling with MySQL. I have an issue with the number of connections to the MySQL database as it hits the 152 opened connections, this is not wanted since I define in my c3p0 config file the max pool size to 20, and of course I close every entity manager I get from the EntityManagerFactory after committing every transaction.
For every time a controller is executed, I notice more than 7 connections are opened, and if I refresh, then 7 connections are opened again without the past idle connections being closed. And in every DAO function I call, the em.close() is executed. I admit here that the issue is in my code, but I don't know what I am doing wrong here.
This is the Sondage.java entity:
#Entity
#NamedQuery(name="Sondage.findAll", query="SELECT s FROM Sondage s")
public class Sondage implements Serializable {
private static final long serialVersionUID = 1L;
public Sondage() {}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private byte needLocation;
//bi-directional many-to-one association to ResultatSondage
#OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL)
#OrderBy("sondage ASC")
private List<ResultatSondage> resultatSondages;
//bi-directional many-to-one association to SondageSection
#OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL)
private List<SondageSection> sondageSections;
}
And here's my DAO class:
#SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
EntityManager em = PersistenceManager.getEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
}
return allSondages;
}
As you see, em is closed. In my JSP, I do this: I know this is not the good way of doing thing in the view side.
<body>
<div class="header">
<%#include file="../../../Includes/header.jsp" %>
</div>
<h2 style="color: green; text-align: center;">الاستمارات</h2>
<div id="allsurveys" class="pure-menu custom-restricted-width">
<%
List<Sondage> allSondages = (List<Sondage>) request.getAttribute("sondages");
for (int i = 0; i < allSondages.size(); i++) {
%>
<%= allSondages.get(i).getName()%>
<%
if (request.getSession().getAttribute("user") != null) {
Utilisateur user = (Utilisateur) request.getSession().getAttribute("user");
if (user.getType().equals("admin")) {
%>
تعديل
<%
}
}
%>
<br />
<%
}
%>
</div>
</body>
I'm guessing that every time I call user.getType(), a request is established ? If so, how can I prevent this?
For c4p0 config file, I included it in persistence.xml, I saw several posts saying that I need to put the c3p0 config file in c3p0-config.xml, but with my setup the c3p0 is initialized with the values I pass in the persistence.xml file, also the mysql connections are reaching 152 connections but the maxpoolsize is at 20, here's the persistence.xml file
<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="CAOE" transaction-type="RESOURCE_LOCAL">
<class>com.caoe.Models.ChoixQuestion</class>
<class>com.caoe.Models.Question</class>
<class>com.caoe.Models.Reponse</class>
<class>com.caoe.Models.ResultatSondage</class>
<class>com.caoe.Models.Section</class>
<class>com.caoe.Models.Sondage</class>
<class>com.caoe.Models.SondageSection</class>
<class>com.caoe.Models.SousQuestion</class>
<class>com.caoe.Models.Utilisateur</class>
<properties>
<property name="hibernate.connection.provider_class"
value=" org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/caoe?useUnicode=yes&characterEncoding=UTF-8"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.c3p0.max_size" value="50" />
<property name="hibernate.c3p0.min_size" value="3" />
<property name="hibernate.c3p0.max_statements" value="20" />
<property name="hibernate.c3p0.acquire_increment" value="1" />
<property name="hibernate.c3p0.idle_test_period" value="30" />
<property name="hibernate.c3p0.timeout" value="35" />
<property name="hibernate.c3p0.checkoutTimeout" value="60000" />
<property name="hibernate.connection.release_mode" value="after_statement" />
<property name="debugUnreturnedConnectionStackTraces"
value="true" />
</properties>
</persistence-unit>
</persistence>
EDIT: I'm deploying the Application to a red hat server with Tomcat and MySQL Installed. I'm just wondering why Hibernate is opening too much connections to MySQL, with all entity managers closed no connection will remain open, but this is not the case. I'm guessing and correct me if I'm true that the connections are opened when I do something like this:
List<Sondage> allSondages = SondageDao.getAllSondages();
for (Sondage sondage : allSondages) {
List<Question> questions = sondage.getQuestions();
//code to display questions for example
}
Here when I use sondage.getQuestions(), does Hibernate open a connection to the database and doesn't close it after, am I missing something in the configuration file that close or return connection to pool when it's done with it. Thanks in advance for any help.
EDIT2 :
Since people are asking for versions, here they are :
JAVA jre 1.8.0_25
Apache Tomcat v7.0
hibernate-core-4.3.10
hibernate c3p0 4.3.10.final
hibernate-jpa 2.1
Thanks in advance
The mysql version is Mysql 5.6.17 if that can help...
EDIT 4: as people are getting confused about witch version of the code I posted is buggy, let me edit this so you'll know what happens exactly:
First I'll start by showing what's the buggy code, as you guys don't care about what's working:
#SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
EntityManager em = PersistenceManager.getEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
}
return allSondages;
}
So this is basically what I did for all my dao functions, I know transaction is not needed here, since I saw questions pointing that transactions are important for connection to close. beside this , I getEntityManager from PersistenceManager class that has an EntityManagerFactory singleton Object, so getEntityManager creates an entityManager from the EntityManagerFactory singleton Object:=> code is better than 1000 word :
PesistenceManager.java:
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class PersistenceManager
{
private static EntityManagerFactory emf = null;
public static EntityManager getEntityManager()
{
return getEntityManagerFactory().createEntityManager();
}
public static EntityManagerFactory getEntityManagerFactory()
{
if(emf == null) {
emf = Persistence.createEntityManagerFactory("CAOE");
return emf;
}
else
return emf;
}
}
Yes this is cool and all good, but where's the problem?
The problem here is that this version opens the connections and never close them, the em.close() have no effect, it keeps the connection open to the database.
The noob fix:
What I did to fix this issue is create an EntityManagerFactory for every request, it mean that the dao looks something like this:
#SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
//this is the method that return the EntityManagerFactory Singleton Object
EntityManagerFactory emf = PersistenceManager.getEntitManagerFactory();
EntityManager em = emf.createEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
emf.close();
}
return allSondages;
}
Now this is bad and I'll just keep it while I don't have answer for this question (it seems like forver :D ). So with this code basically All connections gets closed after hibernate doesn't need them. Thanks in advance for any efforts you put in this question :)
I think that Hibernate and C3P0 are behaving correctly here. In fact you should see that there are always at least three connections to the database open as per your C3P0 configuration.
When you execute a query Hibernate will use a connection from the pool and then return it when it is done. It will not close the connection. C3P0 might shrink the pool if the min size is exceeded and some of the connections time out.
In your final example you see the connections closed because you've shut down your entity manager factory and therefore your connection pool as well.
You call Persistence.createEntityManagerFactory("CAOE") every time. It is wrong. Each call createEntityManagerFactory creates new (indepented) connection pool. You should cache EntityManagerFactory object somewhere.
EDIT:
Also you should manually shutdown EntityManagerFactory. You can do it in #WebListener:
#WebListener
public class AppInit implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {}
public void contextDestroyed(ServletContextEvent sce) {
PersistenceManager.closeEntityMangerFactory();
}
}
Otherwise each case of redeploy is source of leaked connections.
Can you try the following:
<property name="hibernate.connection.release_mode" value="after_transaction" />
<property name="hibernate.current_session_context_class" value="jta" />
instead of your current release mode?
Since sibnick has already answered the technical questions I'll try to address some points you seem to be confused about. So let me give you some ideas on how a hibernate application and connection-pool is intended to work:
Opening a database connection is an "expensive" operation. In order to avoid having to pay that cost for each and every request, you use a connection-pool. The pool opens a certain number of connections to the database in advance and when you need one you can borrow one of those existing connections. At the end of the transaction, these connections will not be closed but returned to the pool so they can be borrowed by the next request. Under heavy load, there might be too few connections to serve all requests so the pool might open additional connections that might be closed later on but not at once.
Creating an EntityManagerFactory is even more expensive (it will create caches, open a new connection-pool, etc.), so, by all means, avoid doing it for every request. Your response-times will become incredibly slow. Also creating too many EntityManagerFactories might exhaust your PermGen-space. So only create one EntityManagerFactory per application/persistence-context, create it at application startup (otherwise the first request will take too long) and close it upon application shutdown.
Bottom line: When using a connection-pool you should expect a certain number of DB-connections to remain open for the lifetime of your application. What must not happen is that the number increases with every request. If you insist on having the connections closed at the end of the session don't use a pool and be prepared to pay the price.
I ran into the same problem and was able to fix it by creating a singleton wrapper class for the EntityManagerFactory and creating the EntityManager where it's needed. You're having the connection overload problem because you're wrapping the EntityManager creation in the singleton class, which is wrong. The EntityManager provides the transaction scope (should not be re-used), the EntityManagerFactory provides the connections (should be re-used).
from: https://cloud.google.com/appengine/docs/java/datastore/jpa/overview
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class EMF {
private static final EntityManagerFactory emfInstance =
Persistence.createEntityManagerFactory("CAOE");
private EMF() {}
public static EntityManagerFactory get() {
return emfInstance;
}
}
and then use the factory instance to create an EntityManager for each request.
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import EMF;
// ...
EntityManager em = EMF.get().createEntityManager();
In my application property i have some datasource related parameter. Those are given bellow:
# DataSource Parameter
minPoolSize:5
maxPoolSize:100
maxIdleTime:5
maxStatements:1000
maxStatementsPerConnection:100
maxIdleTimeExcessConnections:10000
Here, **maxIdleTime** value is the main culprit. It takes value in second. Here maxIdleTime=5 means after 5 seconds if connection is not using then it will release the connection and it will take the minPoolSize:5 connection. Here maxPoolSize:100 means it will take maximum 100 connection at a time.
In my DataSource Configuration class i have a bean. Here is the example code:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
#Autowired
private Environment env;
#Bean
public ComboPooledDataSource dataSource(){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(env.getProperty("db.driver"));
dataSource.setJdbcUrl(env.getProperty("db.url"));
dataSource.setUser(env.getProperty("db.username"));
dataSource.setPassword(env.getProperty("db.password"));
dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
dataSource.setMaxIdleTimeExcessConnections(10000);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return dataSource;
}
Hope this will solve your problem :)
Looks like issue is related to Hibernate bug. Please try to specify fetch strategy EAGER in your OneToMany annotations.
#OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
I am absolutely new to Hibernate and JPA and I have the following problem trying to implement a tutorial that uses Hibernate following the JPA specification.
I have these classes:
1) A HelloWorldClient class, the entry point of my application, containing the main method:
package client;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import entity.Message;
public class HelloWorldClient {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("merging");
EntityManager em = emf.createEntityManager();
EntityTransaction txn = em.getTransaction();
txn.begin();
Message message = new Message("Hello"); //transient state
em.persist(message); //persistent state
txn.commit();
em.close();
message.setText("Hi"); //modifying the detached state of message
EntityManager em2 = emf.createEntityManager();
EntityTransaction txn2 = em2.getTransaction();
txn2.begin();
//the returned mergedMessage is a persistent object
//any changes to mergedMessage will be dirty checked when the txn2 will be committed and updated in the database
Message mergedMessage = em2.merge(message);
txn2.commit();
em2.close();
//Detaching objects explicitly
/*
EntityManager em3 = emf.createEntityManager();
EntityTransaction txn3 = em.getTransaction();
txn3.begin();
Message msg = new Message("Howdy"); //transient state
em.persist(msg); //persistent state
em.detach(msg); //detaching the message object explicitly
txn3.commit();
em3.close();
*/
}
}
2) A Message entity class that is mapped on a database table:
package entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="message")
public class Message {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="ID")
private Long id;
#Column(name="TEXT")
private String text;
public Message() {}
public Message(String text) {
this.text = text;
}
public void setText(String text) {
this.text = text;
}
}
3) And finally I have the persistence.xml configuration file in the META-INF folder of my application:
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="merging" transaction-type="RESOURCE_LOCAL">
<properties>
<!-- Database connection settings -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/hello-world" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="myPassword" />
<!-- SQL dialect -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- Create/update tables automatically using mapping metadata -->
<property name="hibernate.hbm2ddl.auto" value="update" />
<!-- Pretty print the SQL in the log file and console -->
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
When I try to run my application, I obtain this error message in the stacktrace:
Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/share/java/jayatanaag.jar
Exception in thread "main" java.lang.AbstractMethodError: org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.getConfigurationValues()Ljava/util/Map;
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:404)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
at client.HelloWorldClient.main(HelloWorldClient.java:14)
I've had the same issue when trying to do hibernate tutorials. It usually means that there are compatibility issues between the jar files you added to your build path.
in your case, it would seem that
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.getConfigurationValues()
appears in the latest version as an abstract method, hence the above error. Try changing the JPA jar to a previous version, that will probably solve the issue; that's what helped in my case.
I had the same problem and when I checked the Maven repository for hibernate-entity manager I found I wasn't specifying the latest version in my POM.xml. Once I updated to the latest version it fixed the problem.
I'm trying to invoke method based on some interval time, here are some beans inside applicationContext.xml
<bean id="MngtTarget"
class="com.management.engine.Implementation"
abstract="false" lazy-init="true" autowire="default" dependency-check="default">
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="MngtTarget" />
<property name="targetMethod" value="findItemByPIdEndDate"/>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<!-- 10 seconds -->
<property name="startDelay" value="10000" />
<!-- repeat every 50 seconds -->
<property name="repeatInterval" value="20000" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
</list>
</property>
</bean>
Here is the method I'm trying to invoke :
public List<Long> I need findItemByPIdEndDate() throws Exception {
List<Long> list = null;
try{
Session session = sessionFactory.getCurrentSession();
Query query = session.getNamedQuery("endDateChecker");
list = query.list();
for(int i=0; i<list.size(); i++)
{
System.out.println(list.get(i));
}
System.out.println("Total " + list.size());
}catch (HibernateException e){
throw new DataAccessException(e.getMessage());
}
return list;
}
Here is the exception message that I get :
Invocation of method 'findItemByPIdEndDate' on target class [class com.management.engine.Implementation] failed; nested exception is No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I've spent time googling alot so far also I've tried to modify my method like this :
public List<Long> I need findItemByPIdEndDate() throws Exception {
List<Long> list = null;
try{
Session session = sessionFactory.openSession();
Query query = session.getNamedQuery("endDateChecker");
list = query.list();
for(int i=0; i<list.size(); i++)
{
System.out.println(list.get(i));
}
System.out.println("Total " + list.size());
session.close();
}catch (HibernateException e){
throw new DataAccessException(e.getMessage());
}
return list;
}
And I get different error msg, I get : Invocation of method 'findItemByPIdEndDate' on target class [class com.management.engine.Implementation] failed; nested exception is could not execute query] , anyone knows what is this all about, any suggestions ? thank you
Also my queries.hbm.xml
<hibernate-mapping>
<sql-query name="endDateChecker">
<return-scalar column="PId" type="java.lang.Long"/>
<![CDATA[select
item_pid as PId
from
item
where
end_date < trunc(sysdate)]]>
</sql-query>
</hibernate-mapping>
For the second error ("could not execute the query"), I don't know and I'm really wondering what the session looks like.
In deed, AFAIK, the persistent context is not available to Quartz Jobs as nothing take care of establishing a Hibernate Session for them (Quartz runs outside the context of Servlets and the open session in view pattern doesn't apply here). This is why you get the first error ("No hibernate session bound to thread").
One solution for this is described in AOP – Spring – Hibernate Sessions for background threads / jobs. In this post, the author shows how you can use Spring AOP proxies to wire a hibernate interceptor that gives you access to the persistence context and it takes cares of closing and opening the sessions for you.
Didn't test it myself though, but it should work.
I too was facing the same "HibernateException: No Hibernate Session bound to thread" exception
2012-01-13 13:16:15.005 DEBUG MyQuartzJob Caught an exception
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
at com.company.somemodule.dao.hibernate.AbstractHibernateDaoImpl.getSession(AbstractHibernateDaoImpl.java:107)
at com.company.somemodule.dao.hibernate.SomeDataDaoImpl.retrieveSomeData(SomeDataDaoImpl.java:264)
and I solved it by following the example here.
Relevant code
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.company.somemodule.dao.SomeDataDao;
import com.company.somemodule.SomeData;
public class MyQuartzJob extends QuartzJobBean implements Runnable {
private boolean existingTransaction;
private JobExecutionContext jobExecCtx;
private static Logger logger = LoggerFactory.getLogger(MyQuartzJob.class);
private SomeDataDao someDataDao; //set by Spring
private Session session;
private SessionFactory hibernateSessionFactory; //set by Spring
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException
this.jobExecCtx = ctx;
run();
}
private void handleHibernateTransactionIntricacies() {
session = SessionFactoryUtils.getSession(hibernateSessionFactory, true);
existingTransaction = SessionFactoryUtils.isSessionTransactional(session, hibernateSessionFactory);
if (existingTransaction) {
logger.debug("Found thread-bound Session for Quartz job");
} else {
TransactionSynchronizationManager.bindResource(hibernateSessionFactory, new SessionHolder(session));
}
}
private void releaseHibernateSessionConditionally() {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after TransactionalQuartzTask");
} else {
TransactionSynchronizationManager.unbindResource(hibernateSessionFactory);
SessionFactoryUtils.releaseSession(session, hibernateSessionFactory);
}
}
#Override
public void run() {
// ..
// Do the required to avoid HibernateException: No Hibernate Session bound to thread
handleHibernateTransactionIntricacies();
// Do the transactional operations
try {
// Do DAO related operations ..
} finally {
releaseHibernateSessionConditionally();
}
}
public void setHibernateSessionFactory(SessionFactory hibernateSessionFactory) {
this.hibernateSessionFactory = hibernateSessionFactory;
}
public void setSomeDataDao(SomeDataDao someDataDao ) {
this.someDataDao = someDataDao ;
}
}
Relevant bean configuration inside applicationContext.xml
<bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.somecompany.worker.MyQuartzJob" />
<property name="jobDataAsMap">
<map>
<entry key="hibernateSessionFactory" value-ref="sessionFactory" />
<entry key="someDataDao" value-ref="someDataDao" />
</map>
</property>
</bean>
There's bug spring https://jira.spring.io/browse/SPR-9020
And there's workaround.
Configure session with hibernate.current_session_context_class property with this class:
https://gist.github.com/seykron/4770724