Hibernate java.lang.OutOfMemoryError: Java heap space - java

I have a Java web application running on Tomcat 7 - jdk1.7
This application uses Spring 4.1.5.RELEASE and Hibernate 4.2.2.Final
My problem is a OutOfMemoryException of the Heap space on building section factory
This is my static method that opens a SessionFactory
public class GenericDAO {
public static SessionFactory sessionFactory = null;
public static ServiceRegistry serviceRegistry = null;
Transaction tx = null;
public static SessionFactory createSessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()). buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
}
And this is an example of DAO
public class SpecificDAO extends GenericDAO {
public int save(MyObject item) {
Session session = createSessionFactory().openSession();
try {
tx = session.beginTransaction();
session.save(item);
tx.commit();
return item.getId();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return -1;
}
}
The error occurs at the line containing
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
The problem doesn't occur immediately at the deploy, but after 2 o 3 days of usage
This is my Hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName</property>
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<mapping class="it.company.client.project.hibernate.MyObject"/>
<!-- DB schema will be updated if needed -->
<!-- <property name="hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>

You have to create the session factory only once as it is a heavy weight object, refer to the hibernate documentation for its details.
Here is the sample code from the doc on how it should be created:
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory(
new StandardServiceRegistryBuilder().build() );
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}

It is better idea to flush and clear the session after used, you can use both
session.flush();
session.clear();
for more information link1 and link2

You are creating a SessionFactory object for every save() call.
i.e you are creating a new SessionFactory repeatedly for every save() call but not closing the existing SessionFactory objects in memory.
How many times save() is called ? the same no of SessionFactory will be in memory, which causes the memory leak.
SessionFactory are heavy weight objects, so you'd create at application initialization. You can create a SingleTon to instantiate SessionFactory.

Avoid instantiation of SessionFactory object on every DAO action. It is very slow and causes memory leaks. Better explained in this answer
If you're using Spring anyway, better to delegate to Spring work with SessionFactory, transactions and handling SQL exceptions. For example, your save() method will reduce to one line of code sessionFactory.getCurrentSession().save(item); Manual transaction open/commit/rollback should be replaced with #Transactional attribute. Also, usually better place transactions on whole service method, not on every single DAO method, but it depends of business logic.
Here example how to configure spring context for work with Hibernate (just first article for google)
I slightly adopted this example for current question
#Repository
public class SpecificDAO {
private SessionFactory sessionFactory;
#Autowired
public SpecificDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Transactional(propagation=Propagation.REQUIRED)
public int save(MyObject item) {
try{
sessionFactory.getCurrentSession().save(item);
}catch (HibernateException e) {
return -1;
}
}
}
Spring configuration
<context:annotation-config/>
<context:component-scan base-package="it.company.client.project"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>it.company.client.project.hibernate.MyObject</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</prop>
<prop key="hibernate.show_sql">false</prop>
<!--prop key="hibernate.hbm2ddl.auto">update</prop-->
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

Related

Getting org.hibernate.HibernateException: No CurrentSessionContext configured

I have created a maven project with hibernate 5.4 and successfully created DAOs now when I try to get Hibernate Session via getSessionFactory().getCurrentSession() I get Exception org.hibernate.HibernateException: No CurrentSessionContext configured! although I have already added
<property name="hibernate.current_session_context_class">thread</property> in hibernate.cfg.xml file. Already checked several forums including this question org.hibernate.HibernateException: No CurrentSessionContext configured but unable to solve it,
Here is the hibernate.cfg.xml
<?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.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">onetozero</property>
<property name="hibernate.connection.url">jdbc:mysql://192.168.0.112:3306/ecdis</property>
<property name="hibernate.connection.username">root1</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping class="Domain.Route"/>
<mapping class="Domain.RoutePoint"/>
</session-factory>
</hibernate-configuration>
HibernateSession Class
public class HibernateSession {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
and this is how I am using getting the List via DAO
public List<T> list() {
Session session = HibernateSession.getSessionFactory().getCurrentSession();
CriteriaQuery<T> query = session.getCriteriaBuilder().createQuery(entityClass);
query.select(query.from(entityClass));
return session.createQuery(query).getResultList();
}
I am new new to Java and Hibernate, also not using any framework atm so a little detail can also go along the way. TIA
Use HibernateSession.getSessionFactory().openSession() rather than getCurrentSession() to get session, then session factory will bind session to current context as you are using current session context class thread not JTA.Details here

StackOverflowError thrown when C3P0 jars are added

I'm writing simple app using Hibernate. I have hibernate.cfg.xml file as follows:
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/demo
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1234</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- Use the C3P0 connection pool provider -->
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!--List of XML mapping files -->
<mapping class="www.Message"/>
</session-factory>
</hibernate-configuration>
and retrieve SessionFactory object as follows:
//in HibernateUtil.class
SessionFactory sessionFactory;
Configuration configuration=new
Configuration().configure("hibernate.cfg.xml");
sessionFactory=configuration.buildSessionFactory();`
And everything works fine until I add C3P0 jars:
c3p0-0.9.5.2.jar
hibernate-c3p0-5.2.14.Final.jar
mchange-commons-java-0.2.11.jar
After adding jars above, the app throws StackOverflowError.
Here's my main App class:
package www;
import org.hibernate.Session;
import utils.HibernateUtil;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(new Message("Hello Denmark!"));
session.getTransaction().commit();
session.close();
System.out.println("Message saved...");
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
List messages = session.createQuery("from Message m order by m.text
asc").list();
System.out.println("Messages found:"+messages.size());
for (Object mes: messages) {
Message message = (Message) mes;
System.out.println(message.getText());
}
session.getTransaction().commit();
session.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (session != null) session.close();
}
}
}
Any help would be appreciated.

Hibernate Enable PostLoad Event

I'm currently trying to use the #PostLoad Annotation for some processing after my model has been loaded from the database. But at the moment it looks like that my method won't get triggered. I don't use the EntityManager so I'm looking for a way to enable this event bahavior.
My configuration looks like this:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.provider_class">com.zaxxer.hikari.hibernate.HikariConnectionProvider
</property>
<property name="hibernate.connection.tinyInt1isBit">true</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/testing</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.pool_size">1</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- OUTPUT STUFF -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.use_sql_comments">false</property>
<property name="hibernate.format_sql">false</property>
<!-- SESSION CONTEXT -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- CONNECTION POOL hikariCP -->
<property name="hibernate.hikari.maximumPoolSize">25</property>
<property name="hibernate.hikari.idleTimeout">30000</property>
<property name="hibernate.hikari.dataSource.url">jdbc:mysql://localhost:3306/testing</property>
<property name="hibernate.hikari.dataSource.user">root</property>
<property name="hibernate.hikari.dataSource.password"></property>
<property name="hibernate.hikari.dataSource.cachePrepStmts">true</property>
<property name="hibernate.hikari.dataSource.prepStmtCacheSize">250</property>
<property name="hibernate.hikari.dataSource.prepStmtCacheSqlLimit">2048</property>
<property name="hibernate.hikari.dataSource.useServerPrepStmts">true</property>
<!-- Include the mapping entries -->
<mapping class="at.adtime.core.v1.model.User"/>
<mapping class="at.adtime.core.v1.model.Test"/>
</session-factory>
</hibernate-configuration>
Update:
I have a method called afterUserLoad which looks like this:
#PostLoad
public void afterUserLoad() {
ArrayList<String> computedIds = new ArrayList<String>();
for (Test test : this.Test) {
computedIds.add(test.getId());
}
this.setTestIds(computedIds);
}
It should load the Test List and put only the ids in an ArrayList.
#PostLoad handling is implemented at least since 5.2.17 version in Hibernate.
According with my research, #PostLoad, #PrePersist and other kinds of these JPA annotations do not work for Hibernate, instead of them, we can use Interceptors. I am using Hibernate-JPA and Spring with xml based configuration. With Spring I get a SessionFactory object, when i set the properties for this object I inject a MyInterceptor instance that extends EmptyInterceptor class, then you can overide several methods like postLoad, onSave, etc. When you implement this code, the overrided methods are executed according the life cycle of the operation. I have not tested the postLoad method because onSave method worked for me.
Update
Spring Java based configuration #JeffersonTavares:
Spring configuration class:
#Configuration
public class SpringConfig {
#Bean
public BasicDataSource basicDataSource(){ // org.apache.commons.dbcp2.BasicDataSource Object
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
basicDataSource.setUrl("jdbc:sqlserver://172.125.25.7:1433;databaseName=LIST_FIRMAS;selectMethod=direct;");
basicDataSource.setUsername("user");
basicDataSource.setPassword("password");
return basicDataSource;
}
#Bean
public MyInterceptor myInterceptor(){ // Your interceptor
return new MyInterceptor();
}
#Bean(name = "sessionFactory")
public SessionFactory sessionFactory() throws IOException{
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(basicDataSource()); // DataSource
localSessionFactoryBean.setAnnotatedClasses(
com.isapeg.timbrado.model.SalMinimo.class,
com.isapeg.timbrado.model.DeduccionCnom12.class,
com.isapeg.timbrado.model.PercepcionCnom12.class); // JPA entity classes ....
localSessionFactoryBean.setEntityInterceptor(myInterceptor()); // Setting your Interceptor
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
properties.put("hibernate.current_session_context_class", "thread");
properties.put("hibernate.show_sql", "false");
localSessionFactoryBean.setHibernateProperties(properties); // Setting Hibernate Properties
localSessionFactoryBean.afterPropertiesSet(); // Session Factory initialization
return localSessionFactoryBean.getObject(); // Returning of SessionFactory Object
}
// other beans ....
}
Something to test session factory object:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
SessionFactory sessionFactory = (SessionFactory) ctx.getBean("sessionFactory");
if (sessionFactory == null) {
System.out.println("SessionFactory obj is null");
} else {
Session session = sessionFactory.openSession();
System.out.println("Session obj: " + session);
System.out.println("isOpen: " + session.isOpen() + " isConnected: " + session.isConnected());
session.close();
}
Update 2
How to implement an Interceptor here.

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/

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