How to make spring-data-envers work with Hibernate 3 - java

I am trying to implement Entity Auditing functionality using spring-data-envers. The problem is my company is still using Hibernate 3, and it looks like spring-data-envers only work with Hibernate 4. The following are the error I got:
org.springframework.orm.jpa.JpaSystemException: You need to install the org.hibernate.envers.event.AuditEventListener class as post insert, update and delete event listener.; nested exception is org.hibernate.envers.exception.AuditException: You need to install the org.hibernate.envers.event.AuditEventListener class as post insert, update and delete event listener.
at org.hibernate.envers.AuditReaderFactory.get(AuditReaderFactory.java:71)
at org.hibernate.envers.AuditReaderFactory.get(AuditReaderFactory.java:85)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.findRevisions(EnversRevisionRepositoryImpl.java:127)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:414)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:399)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:371)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy30.findRevisions(Unknown Source)
at org.springframework.data.envers.repository.support.RepositoryIntegrationTest.returnsEmptyRevisionsForUnrevisionedEntity(RepositoryIntegrationTest.java:99)
Any help is appreciated.

Try following configuration
in pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>${hibernate.version}</version>
</dependency>
in spring-hibernate.xml ( or whatever name you gave )
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.yourpackage.model</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">replace_with_your_</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">${hibernate.show.sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format.sql}</prop>
<!-- Envers properties -->
<prop key="org.hibernate.envers.auditTablePrefix"/>
<prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
</props>
</property>
Important line:
<prop key="org.hibernate.envers.auditTablePrefix"></prop>
<prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
The suffix '_HISTORY' is the name you choose to give to database table that will hold different versions of you entity. And last one #Audited annotation, is placed on top of your entities that need to be audited.
#Entity
#Table(name = "user")
#Audited
public class User implements Serializable {}

Here is the Spring Java Config in my project that make the spring-data-envers works:
#Configuration
#EnableJpaRepositories(basePackages = "your.repository.package", repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class ServiceModelTestSpringConfig {
//.. Spring-JPA-Hibernate setup ..
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("your.entity.package");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
// dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); // Use in-memory database
dataSource.setUrl("jdbc:h2:~/test/itdata;DB_CLOSE_DELAY=-1"); // Use file database
dataSource.setUsername("ying");
return dataSource;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.connection.autocommit", "false");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
// Hibernate Envers Event Listeners
properties.setProperty("hibernate.ejb.event.post-insert", "org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-update", "org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-delete", "org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.pre-collection-update", "org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.pre-collection-remove", "org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-collection-recreate", "org.hibernate.envers.event.AuditEventListener");
return properties;
}
// .. EOF Spring-JPA-Hibernate setup ..
}

Related

Spring JPA Config IllegalArgumentException: No persistence unit with name found

I am having a weird issue I'm not able to wrap my head around. I have used JPA/Hibernate is Spring before with NO persistence.xml file, Spring handled everything. I'm working on a new project and this time I decided to go all Java Config. I am having some issues with my PersistenceConfig.java, it keeps saying it can't find a persistence unit. If I comment out the line the sets the PersistenceUnitName then it complains IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}.
I don't understand why its trying to use a persistence.xml when I use Java Config and not when I use XML. Any solutions?
Here is my PersistenceConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.testapp.ots.repository"})
public class PersistenceConfig {
#Autowired
Environment environment;
#Bean(name = "datasource")
public DataSource dataSource() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
return dsLookup.getDataSource("jdbc/postgres");
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
return entityManagerFactory;
}
#Bean(name = "jpaVendorAdapter")
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean(name = "jpaDialect")
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
jpaTransactionManager.setDataSource(dataSource());
jpaTransactionManager.setJpaDialect(jpaDialect());
return jpaTransactionManager;
}
#Bean(name = "persistenceExceptionTranslation")
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
public Properties jpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", environment.getProperty("hibernate.hbm2ddl.auto"));
properties.setProperty("hibernate.dialect", environment.getProperty("hibernate.dialect"));
properties.setProperty("hibernate.show_sql", environment.getProperty("hibernate.show_sql"));
properties.setProperty("hibernate.format_sql", environment.getProperty("hibernate.format_sql"));
properties.setProperty("hibernate.connection.charSet", environment.getProperty("hibernate.connection.charSet"));
properties.setProperty("hibernate.cache.use_second_level_cache", environment.getProperty("hibernate.cache.use_second_level_cache"));
properties.setProperty("hibernate.cache.use_query_cache", environment.getProperty("hibernate.cache.use_query_cache"));
properties.setProperty("hibernate.cache.use_structured_entries", environment.getProperty("hibernate.cache.use_structured_entries"));
properties.setProperty("hibernate.generate_statistics", environment.getProperty("hibernate.generate_statistics"));
return properties;
}
}
As a reference here is the XML configuration I used a few months back.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:annotation-config />
<jpa:repositories base-package="net.jkratz.bloodpressure.api.repository" />
<jee:jndi-lookup jndi-name="jdbc/BloodPressureDB" id="dataSource" expected-type="javax.sql.DataSource" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="BPPersistenceUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="packagesToScan">
<list>
<value>net.jkratz.bloodpressure.api.model</value>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.connection.charSet">${hibernate.connection.charSet}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="${jpa.vendor.database}" />
<property name="showSql" value="${jpa.vendor.showSql}"/>
<property name="generateDdl" value="${jpa.vendor.generateDdl}"/>
<property name="databasePlatform" value="${jpa.vendor.databasePlatform}"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
From LocalEntityManagerFactoryBean documentation:
In case of Spring-based scanning, no persistence.xml is necessary; all
you need to do is to specify base packages to search here.
So, try change your bean entityManagerFactory to this:
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
entityManagerFactory.setPackagesToScan("net.jkratz.bloodpressure.api.model");
return entityManagerFactory;
}

Transactions and JPA / Persistence.xml

I am having problems with transactions using Hibernate's implementation of JPA (I am folowing Camel Tracer example)
I am using Hibernate JPA implementation:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.5.Final</version>
</dependency>
If I include a persistence.xml in my META-INF folder, everything works OK:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0">
<persistence-unit name="tracer" transaction-type="RESOURCE_LOCAL">
<class>org.apache.camel.processor.interceptor.jpa.JpaTraceEventMessage</class>
<properties>
<property name="hibernate.dialect" value="..."/>
<property name="hibernate.connection.driver_class" value="..."/>
<property name="hibernate.connection.url" value="..."/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.connection.username" value="..." />
<property name="hibernate.connection.password" value="..."/>
</properties>
</persistence-unit>
</persistence>
I want to use a Java way, so I remove the persistence.xml and create the following beans:
#Configuration
#EnableTransactionManagement
public class AppConfiguration
{
#Bean public EntityManagerFactory entMngFac()
{
EntityManagerFactory emf = Persistence.createEntityManagerFactory("tracer");
return emf;
}
#Bean public DataSource ds()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("...");
dataSource.setUrl("...");
dataSource.setUsername( "..." );
dataSource.setPassword( "..." );
return dataSource;
}
#Bean public PlatformTransactionManager ptm(EntityManagerFactory emf, DataSource ds)
{
JpaTransactionManager jpat = new JpaTransactionManager();
jpat.setDataSource(ds);
jpat.setEntityManagerFactory(emf);
return jpat;
}
#Bean public TransactionTemplate tranTemp(PlatformTransactionManager ptm)
{
TransactionTemplate tt = new TransactionTemplate();
tt.setTransactionManager(ptm);
return tt;
}
}
After saving, when Camel attempts to flush the JPATracer object it has created, I get the following exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
at org.apache.camel.component.jpa.JpaProducer$1.doInTransaction(JpaProducer.java:86)
Which is a little odd as the "no transaction is in progress" error is coming from the "doInTransaction" method.
My thoughts are that Camel is starting a transaction, and then Hibernate is trying to flush the object and is unaware of the transaction that Camel has started? So there is some mix of up of transactions somewhere, but I can't figure out where.
Try with the following EntityManagerFactory configuration (note the packagesToScan call)
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(ds());
em.setPackagesToScan(new String[] { "org.apache.camel.processor.interceptor.jpa" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em.getObject();
}

hibernate spring sigletons server down

I am using hibernate with spring frame work and my beans are in singleton mode.did i supposed to close my session or no (because they are in singleton mode)?
the reality is that we got some problems on our server and too many connections problem
and i thought may be that is the problem.thanks.
this is my codes:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope = "singleton" >
<property name="dataSource" ref local="dataSource" property/>
<property name="packagesToScan" >
<value>Model.Entity</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.auto_close_session">false</prop>
</props>
</property>
and this is the way i use , i close all sessions after i used
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void updateDB() {
Session session = getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
If you configure the spring and hibernate configuration you don't need to close the connections and sessions, Spring will do that for you.
See this example http://howtodoinjava.com/2013/03/21/spring-3-and-hibernate-integration-tutorial-with-example/

getCurrentSession gives No Session Bound to Context, openSession does not

I'm trying to integrate Spring 3.1 with Hibernate 4.1.4, but I am having problems when getting my session from a generic DAO.
The problem is, if I use getCurrentSession() I get a NullPointerException and Hibernate says No session is bound to the context, yet if I use openSession everything seems to be working. Somehow I feel I should be using getCurrentSession, but can't find the origin of the problem.
I've searched this over the internet but none of the solutions worked for me.
Here's my genericDAO code:
public class GenericDaoHibernateImpl<E, PK extends Serializable> implements GenericDao<E, PK> {
private Class<E> entityClass;
protected GenericDataBaseExceptionHandler exceptionHandler;
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public GenericDaoHibernateImpl() {
this.entityClass = (Class<E>) ((ParameterizedType) getClass().
getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setExceptionHandler(GenericDataBaseExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
if (sessionFactory.getCurrentSession() == null)
throw new IllegalStateException("Session has not been set on DAO before usage");
return sessionFactory.getCurrentSession(); //This crashes
// return sessionFactory.openSession(); //This does not
}
public Class<E> getEntityClass() {
return entityClass;
}
public void persist(E entity) throws GenericDataBaseException {
try {
getSession().persist(entity);
} catch (Throwable t) {
Collection<Object> args = new ArrayList<Object>();
args.add(entity);
throw exceptionHandler.handle(t, "persist", args);
}
}
(...)
}
And my spring config file:
<context:annotation-config />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:mysql://localhost/forestool</value>
</property>
<property name="user">
<value>forestool</value>
</property>
<property name="password">
<value>forestool</value>
</property>
</bean>
<!-- Declaración de la factoría de sesiones hibernate con los mappings necesarios -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="mappingLocations">
<list>
<value>classpath*:/hbm/*.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<ref bean="hibernateProperties"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="hibernateProperties" class="java.util.Properties">
<constructor-arg index="0">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
</props>
</constructor-arg>
</bean>
Exception:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1041)
at es.fsc.core.dao.impl.GenericDaoHibernateImpl.getSession(GenericDaoHibernateImpl.java:83)
at es.fsc.core.dao.impl.GenericDaoHibernateImpl.findAll(GenericDaoHibernateImpl.java:244)
at es.fsc.dao.explotacion.impl.ExplotacionDaoImpl.getExplotacionesAbiertas(ExplotacionDaoImpl.java:21)
at es.fsc.service.explotacion.impl.ExplotacionServiceImpl.getExplotacionesAbiertas(ExplotacionServiceImpl.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:196)
at $Proxy5.getExplotacionesAbiertas(Unknown Source)
at es.fsc.app.FscApp.runApp(FscApp.java:58)
at es.fsc.app.App.run(App.java:65)
at es.fsc.main.Main.main(Main.java:20)
Exception in thread "main" java.lang.NullPointerException
at es.fsc.core.dao.impl.GenericDaoHibernateImpl.findAll(GenericDaoHibernateImpl.java:253)
at es.fsc.dao.explotacion.impl.ExplotacionDaoImpl.getExplotacionesAbiertas(ExplotacionDaoImpl.java:21)
at es.fsc.service.explotacion.impl.ExplotacionServiceImpl.getExplotacionesAbiertas(ExplotacionServiceImpl.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:196)
at $Proxy5.getExplotacionesAbiertas(Unknown Source)
at es.fsc.app.FscApp.runApp(FscApp.java:58)
at es.fsc.app.App.run(App.java:65)
at es.fsc.main.Main.main(Main.java:20)
I don't see anything in this configuration that would actually open a Hibernate session for you, or control when that is done.
If you are new to Spring, you might just want to configure an OpenSessionInViewFilter in your web.xml to have a Session open and bound to each request automatically.

How can I set Datasource when I'm creating Hibernate SessionFactory?

I'm creating SessionFactory and I have my datasource as object in code where I'm creating SessionFactory, but i cannot set datasource to Hibernate Configuration object. So how can I set my datasource to my SessionFactory?
Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
configuration.setProperties(properties);
configuration.setProperty("packagesToScan", "com.my.app");
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();
If you happen to have your DataSource stored in JNDI, then simply use:
configuration.setProperty(
"hibernate.connection.datasource",
"java:comp/env/jdbc/yourDataSource");
But if you use a custom data source provider like Apache DBCP or BoneCP and you don't want to use a dependency injection framework like Spring, then you may inject it on the StandardServiceRegistryBuilder before creating the SessionFactory:
//retrieve your DataSource
DataSource dataSource = ...;
Configuration configuration = new Configuration()
.configure();
//create the SessionFactory from configuration
SessionFactory sf = configuration
.buildSessionFactory(
new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
//here you apply the custom dataSource
.applySetting(Environment.DATASOURCE, dataSource)
.build());
Note that if you use this approach, you don't need to put the connection parameters in your hibernate.cfg.xml anymore. Here's an example of a compatible hibernate.cfg.xml file when using approach from above:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="show_sql">false</property>
<!-- your mappings to classes go here -->
</session-factory>
</hibernate-configuration>
Code above tested on Hibernate 4.3.
To supply JDBC connections to Session, you need an implementation of ConnectionProvider.
By default, Hibernate uses DatasourceConnectionProvider which obtains a DataSource instance from JNDI.
To use a custom DataSource instance, use InjectedDataSourceConnectionProvider and inject the DataSource instance into it.
There is TODO note on InjectedDataSourceConnectionProvider
NOTE :
setDataSource(javax.sql.DataSource)
must be called prior to
configure(java.util.Properties).
TODO : could not find where
setDataSource is actually called.
Can't this just be passed in to
configure???
As per the note, call setDataSource() method from configure() method.
public class CustomConnectionProvider extends InjectedDataSourceConnectionProvider {
#Override
public void configure(Properties props) throws HibernateException {
org.apache.commons.dbcp.BasicDataSource dataSource = new BasicDataSource();
org.apache.commons.beanutils.BeanUtils.populate( dataSource, props );
setDataSource(dataSource);
super.configure(props);
}
}
You can also extend UserSuppliedConnectionProvider.
According to the contract of ConnectionProvider
Implementors should provide a public
default constructor.
Hibernate will invoke this constructor if custom ConnectionProvider is set through Configuration instance.
Configuration cfg = new Configuration();
Properties props = new Properties();
props.put( Environment.CONNECTION_PROVIDER, InjectedDataSourceConnectionProvider.class.getName() );
cfg.addProperties(props);
Luiggi Mendoza's answer is why my search sent me here, but I figure I should give my version because I spent quite some time looking around for how to do this - it sets it up with the Spring in-memory database for testing, a SessionContext and the hbm.xml in case you're not using annotations:
/**
* Instantiates a H2 embedded database and the Hibernate session.
*/
public abstract class HibernateTestBase {
private static EmbeddedDatabase dataSource;
private static SessionFactory sessionFactory;
private Session session;
#BeforeClass
public static void setupClass() {
dataSource = new EmbeddedDatabaseBuilder().
setType(EmbeddedDatabaseType.H2).
addScript("file:SQLResources/schema-1.1.sql").
addScript("file:SQLResources/schema-1.2.sql").
build();
Configuration configuration = new Configuration();
configuration.addResource("hibernate-mappings/Cat.hbm.xml");
configuration.setProperty("hibernate.dialect",
"org.hibernate.dialect.Oracle10gDialect");
configuration.setProperty("hibernate.show_sql", "true");
configuration.setProperty("hibernate.current_session_context_class",
"org.hibernate.context.internal.ThreadLocalSessionContext");
StandardServiceRegistryBuilder serviceRegistryBuilder =
new StandardServiceRegistryBuilder();
serviceRegistryBuilder.applySetting(Environment.DATASOURCE, dataSource);
serviceRegistryBuilder.applySettings(configuration.getProperties());
StandardServiceRegistry serviceRegistry =
serviceRegistryBuilder.build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
sessionFactory.openSession();
}
#AfterClass
public static void tearDown() {
if (sessionFactory != null) {
sessionFactory.close();
}
if (dataSource != null) {
dataSource.shutdown();
}
}
#Before
public final void startTransaction() {
session = sessionFactory.getCurrentSession();
session.beginTransaction();
}
#After
public final void rollBack() {
session.flush();
Transaction transaction = session.getTransaction();
transaction.rollback();
}
public Session getSession() {
return session;
}
}
and you'll need these:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.184</version>
<scope>test</scope>
</dependency>
If your datasource is bounded at the JNDI tree:
configuration.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test");
Otherwise, if you have a DataSource object in code, which you want to use:
java.sql.Connection conn = datasource.getConnection();
Session session = sessionFactory.openSession(conn);
I would recommend the first one, to let Hibernate handle the connection lifecycle as needed. At the second approach, make sure that you close the connection when it's no longer needed.
I don't think you can. The Hibernate API will let you configure the JDBC properties so that it can manage the connections itself, or you can give it a JNDI DataSource location so it can go and fetch it, but I don't think you can give it a DataSource.
On the off-chance that you're using Spring, it's easier - use LocalSessionFactoryBean to configure Hibernate, and inject your DataSource into that. Spring performs the necessary magic in the background.
If you are using Spring framework, then use LocalSessionFactoryBean for injecting your data source to Hibernate SessionFactory.
<beans>
<bean id="YourClass"
class="com.YourClass.
<property name="sessionFactory">
<ref bean="DbSessionFactory" />
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>org.postgresql.Driver</value>
</property>
<property name="url">
<value>jdbc:postgresql://localhost/yourdb</value>
</property>
<property name="username">
<value>postgres</value>
</property>
<property name="password">
<value>postgres</value>
</property>
</bean>
<bean id="DbSessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="mappingResources">
<list>
<value>conf/hibernate/UserMapping.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.PostgreSQLDialect </prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.use_second_level_cache"> true </prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
</beans>
If you've implemented a class with javax.sql.DataSource, Hibernate's DataSource can be set by configuring properties.
import javax.sql.DataSource;
public class HibernateDataSource implements DataSource {
...
}
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
public class MyHibernateCfg {
public void initialize() {
HibernateDataSource myDataSource = new HibernateDataSource();
Configuration cfg = new Configuration();
// this is how to configure hibernate datasource
cfg.getProperties().put(Environment.DATASOURCE, myDataSource);
...
}
}
import org.hibernate.cfg.Configuration;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
public class TableClass {
public void initialize() {
MyHibernateCfg cfg = new MyHibernateCfg();
Configuration conf = cfg.getCfg();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();
SessionFactory sessionFactory = conf.buildSessionFactory(serviceRegistry);
Session sessionFactory.openSession();
...
}
}
I used LocalContainerEntityManagerFactoryBean to create EntityManagerFactory instance at the configuration class.
If it is required to set another DataSource, than it is possible to update it with entity manager factory instance at runtime:
#Service("myService")
public class MyService
{
....
#Autowired
private LocalContainerEntityManagerFactoryBean emf;
....
public void replaceDataSource(DataSource dataSource)
{
emf.setDataSource(dataSource);
emf.afterPropertiesSet();
}
....
}
It works with Hibernate 5.2.9 Final.

Categories