How does HibernateTemplate and Spring #Transactional work together? - java

We use HibernateTemplate in our DAOs for all the CRUD operations.
My question is, we use spring #Transactional on the services, Because the spring is managing the transactions, how does the HibernateTemplate behave in the senario where I update multiple DAOs. Meaning does HibernateTemplate use same session across different DAOs when Spring #Transactional is used?
#Transactional
public boolean testService(SObject test)[
dao1.save(test.getOne());
dao2.save(test.gettwo());
}
This is how the DAO class looks:
public class GenericHibernateDao<T, PK extends Serializable> extends HibernateDaoSupport
.
.
.
public PK save(T newInstance) {
return (PK) getHibernateTemplate().save(newInstance);
}

The HibernateTransactionManager javadoc is pretty clear about this:
This transaction manager is appropriate for applications that use a single Hibernate SessionFactory for transactional data access, but it also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access Hibernate and services which use plain JDBC (without being aware of Hibernate)! Application code needs to stick to the same simple Connection lookup pattern as with org.springframework.jdbc.datasource.DataSourceTransactionManager (i.e. DataSourceUtils.getConnection or going through a TransactionAwareDataSourceProxy).
You're fine as long as you are accessing the connection through helper classes that are aware of the connection proxy such as DataSourceUtils (and the JdbcTemplate uses that behind the hood)

Related

Using same jdbcTemplate for two different schemas

I have 2 datasources say dataSourceA and dataSourceB but based upon few calculations, I need to execute the same query in different schemas. Also, it is going to be executed in either of the schemas.
so, at DAO layer , I have one setDataSource() method which is #autowired to the dataSourceA, thus,returning the JDBCTemplate with former DataSource. How can I implement the dataSourceB changes using the same JDBCTemplate as it will be difficult to change at every DAO layer as entire application change will be required.
You could you inject both datasources and select the datasource inside your method according to your logic:
public class SomeDaoImpl implements SomeDao {
private final JdbcTemplate jdbcTemplateA;
private final JdbcTemplate jdbcTemplateB;
#Autowired
public SomeDaoImpl(JdbcTemplate jdbcTemplateA, JdbcTemplate jdbcTemplateB) {
// injecting both JdbcTemplate instances
this.jdbcTemplateA = jdbcTemplateA;
this.jdbcTemplateB = jdbcTemplateB;
}
public void businessLogicMethod(...) {
// choosing the actual template to be used according to your logic
JdbcTemplate jdbcTemplate = chooseTemplate(...);
// now using the template to execute a query
jdbcTemplate.execute(...);
}
}
Another option would be to instantiate two SomeDaoImpl instances and inject one JdbcTemplate into each of them, and select the DAO instance in your service layer.
But both these solutions have a flaw: transaction is usually initiated in the service layer (with an interceptor, for example), and it has no idea that you are going to route your requests to another datasource; so it could happen that a transaction starts on one datasource, but the query is executed on another one.
So the clearest solution would be to go one level up and instantiate 2 services, in each of them DAOs with different JdbcTemplate instances. Of course, 2 transaction managers will have to be configured and carefully wired (for example, via #Transactional("transactionManagerA")). More information on this here Spring - Is it possible to use multiple transaction managers in the same application?

JPA's EntityManager should be RequestScoped?

I am developing a JavaEE6 based web application using JBoss7.
In my application I am injecting the EntityManager in my EJBs as:
class ForumServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
class TopicServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
The problem when I update some data using ForumServiceEJB's EntityManager then the changes are made into DB but TopicServiceEJB's EntityManager is not able to see those changes and the results are always fetched from Cache.
I am using ExtendedPerssisteenceContext as My Entities contain child Entity Collections of Lazy Loading type.
How can I use/Inject EntityManager of type ExtendedPersistenceContext and make different EntityManager in one EJB can still see the changes done by other different EJB EntityManagers?
Somewhere I read EntityManagers should be RequestScoped objects.
public class MyEntityManagerProducers {
#Produces #RequestScoped
public EntityManager createDbEm() {
return Persistence.createEntityManagerFactory("forumDb").
createEntityManager();
}
public void disposeUdEm(#Disposes EntityManager em) {
em.close();
}
Is it the way to go?
I am using ExtendedPerssisteenceContext as My Entities contain child
Entity Collections of Lazy Loading type.
This is not a good reason to use EXTENDED. I would suggest you to make it default, which is TRANSACTION. And it's good to make your EntityManager request-scoped, or method-scoped, in non-enterprise environment or when using application-managed persistence, as this is not a very heavy object to create. Moreover, neither using application-scoped EntityManager is a good idea, as it is not threadsafe.
Having said that, as you are using JBoss, you should let the container handle the lifecycle of EntityManager, in case you are using JTA. Hence, just inject that with everything default
Note:
Only stateful session beans can have a container-managed, extended entity manager.
Links:
http://javanotepad.blogspot.com/2007/08/managing-jpa-entitymanager-lifecycle.html
https://blogs.oracle.com/enterprisetechtips/entry/extended_persistence_context_in_stateful
Suggestions:
Your business method should know whether to load the children or not. But that's the ideal case. A number of times we can't say that and completely depends on the user input -- we can't predict that well. Therefore, there are two solutions available,
make a separate AJAX call to load children
Use the filter called open-session-in-view. I would prefer the former.
Links:
https://community.jboss.org/wiki/OpenSessionInView
http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
Why is Hibernate Open Session in View considered a bad practice?

Service methods without using hibernate template

I have been googling for several hour now trying to find an example on how to write a service method that doesn't use Springs Hibernate Template while using a DAO interface. Something that is also confusing me is what happens when I put the #Transactional annotation in the service layer as opposed the DAO. Are the Service methods/DAO interfaces interchangeable?
Here is an example where the #Transactional is in the DAO
Here is one with the #Transactional in the Service Layer but using hibernate templates
Thanks for your help!
The Spring documentation recommends avoiding HibernateTemplate completely, and use the Hibernate API directly instead:
NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
also be coded in plain Hibernate style. Hence, for newly started
projects, consider adopting the standard Hibernate3 style of coding
data access objects instead, based on
SessionFactory.getCurrentSession().
And the #Transactional annotation should always be put on methods of the service layer. This is the layer that demarcates transactions.
Read http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#orm-session-factory-setup to understand how to setup a session factory. Once done, the session factory can be injected in your DAOs:
#Repository
public class MyDAO {
#Autowired
private SessionFactory sessionFactory;
...
}

HibernateDaoSupport , transaction is not rolled back

I'm playing around with Spring + Hibernate and some "manual" transaction management with PostgreSQL
I'd like to try this out and understand how this works before moving to aop based transaction management.
#Repository
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
#Override
public void saveUser(User u) {
Transaction tx = getSession().beginTransaction();
getHibernateTemplate().saveOrUpdate(u);
tx.rollback();
}
}
Calling saveUser here, I'd assume that saving a new User will be rolled back.
However, moving to a psql command line, the user is saved in the table.
Why isn't this rolled back, What do I have to configure to do transactions this way ?
Edit; a bit more debugging seems to indicate getHibernateTemplate() uses a different session than what getSession() returns (?)
Changing the code to
Transaction tx = getSession().beginTransaction();
getSession().persist(u);
tx.rollback();
and the transaction does get rolled back. But I still don't get why the hibernateTemplate would use/create a new session..
A couple of possibilities spring to mind (no pun intended):
a) Your JDBC driver defaults to autocommit=true and is somehow ignoring the beginTransaction() and rollback() calls;
b) If you're using Spring 3, I believe that SessionFactory.getSession() returns the Hibernate Session object wrapped by a Spring proxy. The Spring proxy is set up on the Session in part to handle transaction management, and maybe it's possible that it is interfering with your manual transaction calls?
While you can certainly use AOP-scoped proxies for transaction management, why not use the #Transactional(readOnly=false|true) annotation on your service layer methods? In your Spring config file for your service layer methods, all you need to do to make this work is to add
<tx:annotation-driven />
See chapters 10 and 13 of the Spring Reference Documentation on Transaction Management and ORM Data Access, respectively:
http://static.springsource.org/spring/docs/3.0.x/reference/index.html
Finally, if you're using Spring 3, you can eliminate references to the Spring Framework in your code by injecting the Spring-proxied SessionFactory bean into your DAO code - no more need to use HibernateDaoSupport. Just inject the SessionFactory, get the current Session, and use Hibernate according to the Hibernate examples. (You can combine both HibernateDaoSupport and plain SessionFactory-based Hibernate code in the same application, if required.)
If you see the JavaDoc for HibernateDaoSupport.getSession() it says it will obtain a new session or give you the one that is used by the existing transaction. In your case there isn't a transaction listed with HibernateDaoSupport already.
So if you use getHibernateTemplate().getSession() instead of just getSession(), you should get the session that is used by HibernateTemplate and then the above should work.
Please let me know how it goes.
EDIT:
I agree its protected...my bad. So the other option then is to keep the session thread bound which is usually the best practice in a web application. If HibernateDaoSupport is going to find a thread bound session then it will not create a new one and use the same one. That should let you do rollbacks.

using JdcbTemplate standalone

We are looking into using the JdbcTemplate for accessing the DB - but we have many different DB-connections, that each class could use, so injecting the jdbcTemplate is not an option atm. So if we do a
jdbcTemplate = new JdbcTemplate(dataSource);
what will the transaction policy be? Auto-commit is off in the DB.
You can configure each javax.sql.DataSource object to enable auto-commit if that does the job, or disable auto-commit and write the transaction logic programatically.
Both the java.sql.Connection and the javax.sql.DataSource class have methods for enable/disable auto-commit.
Regarding dependency injection and Spring, you can still inject a datasource object into your repository. If you also let each repository extend the org.springframework.jdbc.core.support.JdbcDaoSupport class, then you have a JdbcTemplate object available for you with the derived getJdbcTemplate() method.
You can also let Spring handle the transaction handling for you. Without a XA transaction manager, you need one transaction manager for each datasource. With many transaction managers, declarative transaction support with the #Transactional annotation is impossible. You can however, inject the transaction manager into your service class. This is described in the reference documentation here.

Categories

Resources