Using HibernateTransactionManager for jdbc template - java

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.

Related

How do I use custom hibernate SQL under Spring/Hibernate Transaction Management

I have the following Spring/Hibernate configs:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="jndiDataSource" />
<property name="annotatedClasses">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
I am extensively using spring transaction annotations to control transaction propagation methods throughout my code base. It is all working great.
I have a need to perform an update that will affect many rows at once and I want to blend it in with the rest of my transaction logic. The last thing I want to do is to bull in a china shop and load all objects into memory and loop through them changing them one at a time.
I am trying something like:
#Autowired
private SessionFactory sessionFactory;
...
String hql = "UPDATE TABLE_NAME SET COLUMN_LIST WHERE ID IN :list";
// I see the transaction and get an error when I try to start a new one.
Transaction trans = sessionFactory.getCurrentSession().getTransaction();
Query query = sessionFactory.getCurrentSession().createSQLQuery(hql);
query.setParameterList("list", listOfIds);
success = (query.executeUpdate() == listOfIds.size());
I have tried dropping this into a method with its own transaction instructions, but am not seeing any evidence that it is being executed (other than a lack of errors).
What is the recommended way to include custom Hibernate SQL into Spring managed transactions?
Thanks a lot.

Spring and Hibernate: Multiple connections, thread safe

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.

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.

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.

Hibernate and JDBC in one transaction

I have a method, marked as #Transactional.
It consists of several functions, one of them uses JDBC and the second one - Hibernate, third - JDBC.
The problem is that changes, made by Hibernate function are not visible in the last functions, that works with JDBC.
#Transactional
void update() {
jdbcUpdate1();
hibernateupdate1();
jdbcUpdate2(); // results of hibernateupdate1() are not visible here
}
All functions are configured to use the same datasource:
<bean id="myDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource" ref="targetDataSource"/>
</bean>
<bean id="targetDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" lazy-init="true" scope="singleton">
<!-- settings here -->
</bean>
myDataSource bean is used in the code. myDataSource.getConnection() is used to work with connections in jdbc functions and
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
...
}
});
is used in hibernate function.
Thanks.
First, avoid using JDBC when using hibernate.
Then, if you really need it, use to Session.doWork(..). If your hibernate version does not yet have this method, obtain the Connection from session.connection().
You can use JDBC and Hibernate in the same transaction if you use the right Spring setup:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="myDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target">
<bean class="MyDaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
This assumes that the JDBC portion of your DAO uses JdbcTemplate. If it doesn't you have a few options:
Use DataSourceUtils.getConnection(javax.sql.DataSource) to get a connection
Wrap the DataSource you pass to your DAO (but not necessarily the one you pass to the SessionFactory) with a TransactionAwareDataSourceProxy
The latter is preferred since it hidse the DataSourceUtils.getConnection inside the proxy datasource.
This is of course the XML path, it should be easy to convert this to annotation based.
The problem is, the operations on Hibernate engine does not result in immediate SQL execution. You can trigger it manually calling flush on Hibernate session. Then the changes made in hibernate will be visible to the SQL code within the same transaction. As long as you do DataSourceUtils.getConnection to get SQL connection, because only then you'll have them run in the same transaction...
In the opposite direction, this is more tricky, because you have 1nd level cache (session cache), and possibly also 2nd level cache. With 2nd level cache all changes made to database will be invisible to the Hibernate, if the row is cached, until the cache expires.

Categories

Resources