Spring and Hibernate: Multiple connections, thread safe - java

I have an existing Project working fine, but now I have to implement a Backup System that is executed exery day and dumps the Database to a File. I want to solve this using a ScheduledTask, but this means that there is another Thread using Hibernate.
My Question: How exactly can I make Hibernate Thread safe?
I have the following code-(snippets):
In applicationContext.xml
<bean id="myEmf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dbDataSource" />
<property name="packagesToScan" value="redb.main.core.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
<!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> -->
</props>
</property>
</bean>
<!-- Transaction Management -->
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
So I can get the EntityManager by
#PersistenceContext
protected EntityManager entityManager;
But if i understood it correctly, every Thread needs its own EntityManager from the EntityManagerFactory.
How can I create a new EntityManager in an other class?
I have no persistence.xml. Do I have to create it?

He-he. Welcome in the hell.
The main problem, that spring tries to do that with an aspect-based solution. Although this is buggy (or undebuggable), in trivial cases it can work.
The general answer to your question is that the EntityManagerFactory can be a global, static object in your software, although I were stoned if I simply used that.
By default, the spring aop "weaves" your application on deployment, finds all of the database entity classes by their annotations, and wraps their methods to provide always an existing entitymanager. This is the theory. But it is not the practice.
The practice is that you have very little control over what exactly will happen.
What I did: there is a servlet filter named org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter, which can open an entitymanager for every request, and flush/close that on need. Yes, its name is about "views", but soon its name is its first bug: practically we had to call it as "requesttransactionfilter" or such. It hasn't anything with the MVC views to do, it is working on the http request entities coming from your servlet container.
If you don't like to use servlet filters in a spring application, there is a also a spring interceptor named OpenEntityManagerInViewInterceptor with the very similar functionality, too.
Programmatically, you can generate an EntityManager from an EntityManagerFactory by its createEntityManager() method.
Happy googling! You are on the begin of a long way.

Related

Manually open a hibernate session with Spring config

The issue I am having is that I use Spring to manage and load hibernate for my web application. I am currently using OpenSessionInViewFilter. This works as intended when I am viewing the application, but not so well when I am trying to access hibernate from non-view related activities such as a Quartz task or some Runnable thread I create to help with some tasks. This causes the Lazy initialize exception and no session available exceptions to occur.
Here is how I currently use Spring to manage Hibernate
<bean id="mainDataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
[..DB config..]
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="mainDataSource"/>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
<property name="dataSource"><ref local="mainDataSource"/></property>
</bean>
I then configure DAO objects which extend HibernateDaoSupport and inject them into service classes
<bean id="myDAO"
class="package.myDAO">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="mySvcTarget" class="package.myService">
<property name="myDAO"><ref bean="myDAO"/></property>
</bean>
<bean id="myService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="txManager"/>
</property>
<property name="target">
<ref bean="mySvcTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
So then in my application, myService is injected into my controller classes so I use that to get access to my DAO's. For my situation though it appears I need to access my DAO's (or service preferably) some other way and manually open and close my hibernate sessions since my service classes only seem to be open during view session. I am not exactly sure the best way to do this. All the hibernate configurations are there already in Spring so I'm assuming its just a matter or calling them somehow.
First of all those additional services that you're using (non-views) should be visible by Spring. The simplest way to do it is to use #Service annotation. And to make it work you can add <context:component-scan base-package="your.package"> in your configuration.
After this, if Spring sees your service as a bean, it should be enough to use #Transactional annotation to have Hibernate session in it.

Using HibernateTransactionManager for jdbc template

I was working on an spring application before which uses HibernateTransactionManager for transactions with queries/updates using jdbc template and works fine as well.
Below was the code used
<bean id="sybaseDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="MySybaseDS"/>
<property name="lookupOnStartup" value="false"/>
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="sybaseDataSource" />
<property name="mappingResources">
<list>..........</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.SybaseAnywhereDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
I am creating a new application and confused now whether to use the HibernateTransactionManager or JpaTransactionManager or both(possible?).
The application will use both HibernateTemplate and JdbcTemplate(for bulk updates) for database operations and need to be transactional.
I mean, can/should I use HibernateTransactionManager for transactions with jdbctemplate and HibernateTemplate database operations? Will there be any performance bottleneck of using one transaction manager over another?
The short answer is that it will work. See also this thread for a description of the low-level details.
If the application is JPA based (an entity manager factory is configured), then the JpaTransactionManager should be used.
This transaction manager binds an entity manager to the thread during the duration of the transaction.
The HibernateTransactionManager is for applications that don't use JPA but use instead use Hibernate directly (a session factory is configured).
This transaction manager binds a hibernate session to the thread instead of an entity manager.
They do basically the same, it's just one handles a Session while the other handles an EntityManager. Their choice is simply dictated by the fact that JPA is used or not.
Both transaction managers are compatible with the JdbcTemplate, according to their respective javadocs.
There are no performance consequences of using one transaction manager versus the other.
Internally the entity manager uses a Hibernate session, so the end result is the same: a hibernate session is binded to the thread directly or indirectly during the duration of the transaction.

Creating a distributable Java library that uses Hibernate

Looking for some advice before I start a minor project...
I have a Java EE project which uses Spring 3 and Hibernate 3.6 to access a database, in which I've created quite a few APIs to access the database. There are several other applications that need to use these APIs (backed by the same database), so I'd like to break them out into distributable JARs.
Problem is - I can't figure out a good way to distribute a library that is backed by Hibernate. I use annotations, not config files for Hibernate. Each API has a singleton which, in my application, is setup as a Spring bean and consumes a SessionFactory. The Spring bean (copied below) has a few configuration items.
So, my questions are:
I would like to decouple the library from Spring (so the other applications don't necessarily have to use Spring). Is that realistic?
What is the best way to take a DataSource instance (the common
denominator for each application), turn it into a SessionFactory and
pass it to the singleton?
Is there a way to encapsulate the few hibernateProperties items from the bean below, so they're in the library rather than in a config file?
The singletons use the Spring transaction manager with the #Transactional annotation. Obviously that's coupled with Spring, so I suppose I'd have to remove it if I want to make this Spring-agnostic? Should I switch to programmatic transaction management?
So that's the story - does this sound doable?
Spring config:
<jee:jndi-lookup id="dataSource" jndi-name="oracleDatabase" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.company.data.DataManagerSingleton</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.default_schema">schema_name</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
</props>
</property>
<property name="packagesToScan">
<value>com.company.data</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<qualifier value="ec" />
</bean>
Thanks.

Understanding the SessionFactory in Spring

A little background: I'm using Spring and Hibernate to create a really simple domain/dao/service structure. I'm also using Autowiring to inject all my beans into their happy places.
While refactoring, I recently got the all-too-popular error message "could not initialize proxy - no Session" when trying to access a FetchType.LAZY property on my hibernate object. It goes something like this:
public class Person {
...
#ManyToOne(cascade = {}, fetch = FetchType.LAZY)
#JoinColumn(name = "pet_id", nullable = false)
public Pet getPet() {
return pet;
}
...
}
I used to have a PersonService bean that accessed the Pet property, and had no trouble doing so. However, I recently refactored the code so that instead of the PersonService looking at the Pet, a PersonHelper looks at it. While my helper bean can see the PersonDao, can make a call to get the person, it cannot access the Pet as my session is closed.
So, I think that I'm unclear as to when I loose my hibernate session. All the configs look fine, and the DAO is getting injected into my helper, just like it used to get injected into my service. I'm not sure why my service could get the Pet just fine, but my helper cannot.
Any help with understand this "SessionFactory mystery" is well appreciated. I realize this might be a complicated subject, so links to some good reading material would rock.
I've since changed the code to FetchType.EAGER (working fine), but this riddle is burning a whole in my brain :).
Per requests, here is a (simplified) look into my config:
<bean id="personSvc" class="org.comp.service.impl.PersonServiceImpl" />
<bean id="personHelper" class="org.comp.service.helper.PersonHelper" />
<bean id="personDao" class="org.comp.dao.hibernate.HibPersonDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
...
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="packagesToScan" value="org.comp.domain"/>
<property name="schemaUpdate" value="true" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">/hibernate-ehcache.xml</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
DAO is autowired into the helper:
#Autowired
private PersonDao personDao;
Without seeing the code/context config for PersonService, I can only guess as to why it worked before the refactoring. If you're using a HibernateInterceptor to wrap session management around your DAO methods, then the session is closed immediately after the method has finished, unless it was opened beforehand (such as by a OpenSessionInViewFilter).
My guess is that the scope of the HibernateInterceptor may have changed during refactoring so that the session is now closed immediately after the data is fetched. You may want to look at extending the scope of HibernateInterceptor to cover your service/business methods, so that the session is kept around long enough for lazy fetching to work, or, alternatively, use the OpenSessionInViewFilter, which ensures the session is always available.
OSIV is always a must-read be it you are writing a web-based application or not.
I use the #Transactional tag in my Spring beans' methods (at the service layer) and let Spring to manage the session for me that way (Spring handles Hibernate's session per thread by default).

How can I define multiple sessionfactory instances in Spring?

I would like to have multiple Hibernate SessionFactories in a spring application, all of them with identical configurations except for the DataSource. Ideally, I would acquire a particular SessionFactory by name. I need to be able to do this based on runtime state, and it isn't possible to determine which session factories I will need at application startup time. Basically, I need a SessionFactoryTemplate or something like it.
Is this possible? How do I go about doing it?
You might define an abstract bean and use bean inheritance. This means you'll have a bean definition that works as a template and you may have multiple beans just copying the attributes set by the parent bean.
Here's an example:
<bean id="abstractSessionFactory" abstract="true"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="mySessionFactory" parent="abstractSessionFactory">
<property name="dataSource" ref="myDataSource"/>
...
</bean>
<bean id="mySessionFactory2" parent="abstractSessionFactory">
<property name="dataSource" ref="myDataSource2"/>
...
</bean>
Using the attribute 'abstract' you ensure that bean won't be instantiated and it will be used just as a template.
More info here: link text
Are you sure you need multiple SessionFactories? If all the mappings/configurations are the same and you just have multiple identical databases (e.g. in a multi-tenant app?), then how about having a single SessionFactory that connects to a DataSource which dynamically supplies the appropriate database connection?
See this question for more details:
And this blog post on Dynamic DataSource Routing in Spring.
I have no idea what your current bean definition looks like now, but wouldn't you just ... define a second SessionFactory?
<bean id="mySessionFactory1"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource1"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="mySessionFactory2"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource2"/>
...
</bean>
You could then simply just wire your DAOs up with one sessionFactory vs the other:
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory1"/>
</bean>
<bean id="myCompanyDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory2"/>
</bean>
I don't know of an easy solution for your problem using Spring.
However, you could be able to use Hibernate Interceptors, provided that your particular databases/data-sources can be reached through one master/admin database connection. This blog post explains how in detail, but the gist of it is to dynamically replace table names in SQL statements that Hibernate generates, with qualified names identifying different databases. This is relatively easy to understand and maintain, and works well in my company's multi-tenant set-up.
Apart from that, you can try writing your own TransactionManager, using the HibernateTransactionManager as a starting point, adding support for working with multiple session factories. However, this would mean you having to really dive into Spring ORM support internals, and that is something I tried, but then scrapped in favor of the first approach. I'm sure it can be done with moderate effort, but the previous solution was already doing the job for us.

Categories

Resources