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.
Related
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
Good day!
My problem is when i transferred configuration for another DB from xml to #Bean my transactions is lost.... dont rollback and not work.
I see this when in DB after first insert created row (!), but in this method(transaction) start second insert i take Exception and row after first inset stay on DB!
This xml
<bean name="sqlSessionFactoryYarus" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="/WEB-INF/MapperConfigYarus.xml" />
<property name="dataSource" ref="dataSourceYarus" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="ru.project.crm.mapper_yarus"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryYarus" />
</bean>
<bean id="transactionManagerYarus" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceYarus" />
<qualifier value="yarus"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManagerYarus" />
this code (dataSource there is no this not to waste space)
#Component
#Scope("singleton")
#DependsOn("springApplicationContextHolder")
public class YarusConnectionConfig {
#Bean
public SqlSessionFactory sqlSessionFactoryYarus() throws Exception {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSourceYarus());
sqlSessionFactory.setConfigLocation(new ClassPathResource("../MapperConfigYarus.xml"));
return sqlSessionFactory.getObject();
}
#Bean
public MapperScannerConfigurer yarusMapper() throws Exception {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setSqlSessionFactoryBeanName("sqlSessionFactoryYarus");
msc.setBasePackage("ru.project.crm.mapper_yarus");
return msc;
}
#Bean
public DataSourceTransactionManager transactionManagerYarus() throws Exception {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSourceYarus());
return dataSourceTransactionManager;
}
}
And
All paces when i want to Transactional annotate #Transactional(value = "transactionManagerYarus")
And if i build project with xml Transactional works fine
BUT if build with #Bean its dont work...
Plesae Help me!
I use
1) Spring 4.3
2) MyBatis
3) Postgesql
4) Java 8
Also we find solution.
Problem was in dataSource
#Bean(destroyMethod = "close", name = "dataSourceYarus")
public ComboPooledDataSource dataSourceYarus() {
ComboPooledDataSource cpds = new ComboPooledDataSource();
//config connection
}
It is my bean, and i call this bean like method, for example
new DataSourceTransactionManager(dataSourceYarus());
I did not attach any importance to this, because in all example this is true.
BUT in xml configuration caused this like "Bean" on his name, i replace call in java-config to
new DataSourceTransactionManager(context.getBean("dataSourceYarus"))
and.... this work for me!
Because if call this method, every time creating new pool then transaction was over
Maybe it is a simple question, but I can't find out this situation of relations in Hibernate.
I have these Entities:
#Entity
public class User {
...
#OneToMany(mappedBy = "user")
private Set<Conversation> posts = new HashSet<Conversation>();
...
}
#Entity
public class Conversation {
...
#OneToMany(mappedBy = "conversation")
private Set<Message> messages = new HashSet<Message>();
...
}
#Entity
public class Message { ... }
and then I want create User with Conversation and Message at once. Idea should be like this:
User user = new User();
user.getPosts().add(new Conversation(){
{
getMessages().add(new Message());
}
});
session.persist(user);
But just User is saved in database - why isn't it all? Because of default LAZY fetching? Could my idea be implemented somehow?
PS: Of course I know about the solution of persisting each of the entities, but I am used to do like this in other frameworks like nette or Django, so I can't get out of my head.
PPS: I found out that problem is in default CascadeType. Could it be set on globally, e.g. in Hibernate config XML? Is it a good idea (by performance point of view - it is persisted each time on "superpersist" or only in case of changes)?
PPPS: I also found out (opposite to Django) that I have to set FK ex-post for each item added to collection. It is natural (because of selected pure Set type), but new for me. Which approach would you recommend me? Required FK as argument in constructor on item Entity e.g.:
Class Message{
Message(Conversation conversation){
setConversation(conversation);
}
...
}
or make a method for adding where FK sets inside e.g.:
Class Conversation{
...
public void addMessage(Message msg){
msg.setConversation(this);
getMessages().add(msg);
}
...
}
?
Making Session + configure XML.
private final static String CFG = "hibernate-cfg.xml";
private final static String SCRIPT_FILE = "query.sql";
private static SessionFactory sessionFactory;
private static ServiceRegistry buildRegistry() {
return new StandardServiceRegistryBuilder()
.configure(CFG)
.build();
}
private static Metadata getMetaData() {
return new MetadataSources(buildRegistry()).getMetadataBuilder().build();
}
private static SessionFactory buildSessionFactory() {
return getMetaData().getSessionFactoryBuilder().build();
}
public static SessionFactory getSessionFactory() {
if (sessionFactory == null) {
sessionFactory = buildSessionFactory();
}
return sessionFactory;
}
public static Session getSession(){
try {
return getSessionFactory().openSession();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
and the hibernate-cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/learnme
</property>
<property name="connection.username">root</property>
<property name="connection.password"/>
<property name="connection.pool_size">100</property>
<!-- SQL dialect -->
<property name="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>
<!-- Display all generated SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="learnme.hibernate.entities.User"/>
<mapping class="learnme.hibernate.entities.Conversation"/>
<mapping class="learnme.hibernate.entities.Message"/>
</session-factory>
</hibernate-configuration>
According to this and this
you need to have this in your persistence.xml file to set it globally:
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<cascade-persist/>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>
The mapping file has to be located either in the default location,
META-INF/orm.xml, or in another location that is specified explicitly
in the persistence unit definition (in persistence.xml).
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>
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.