I have a spring based tomcat service. I use annotations based hibernate mapping and I have multiple sharded databases. All the sharded databases have same tables say Student. I want to implement transaction on them using #Transactional annotation.
#Autowired
List<SessionFactory> sessionFactoryList;
#Transactional
public insertStudentBatch(List<Student> students) {
}
Now I want to insert entire batch. If any error occurs, I want all of them to roll back. What is the best way to do that? Can I write multiple TransactionManager qualifier like #Transactional("txManager1", "txManager2")?
No, unfortunately the spring #Transactional annotation is specific to a single transaction manager and does not behave in the desire you described.
It seems to me what you would likely want is a JTA transaction for 2PC commit where you basically start a master JTA transaction and then for each SessionFactory, you invoke each of the specific transaction managers for your shards and perform your operations.
#Service
public class StudentBatchServiceImpl implements StudentBatchService {
#Autowired List<StudentService> studentServices;
#Transactional(value = "jtaTransactionManager")
public void storeStudents(List<Student> students) {
for(StudentService service : studentServices)
service.storeStudents(students);
}
}
public interface StudentService {
void storeStudents(List<Student> students);
}
public abstract AbstractStudentServiceImpl implements StudentService {
protected void storeStudents(EntityManager em, List<Student> students) {
for(Student student : students) {
em.persist(student);
}
}
}
#Service
public class Shard1StudentServiceImpl extends AbstractStudentServiceImpl {
#PersistenceContext(name = "shard1")
private EntityManager entityManager;
#Override
#Transactional(value = "shard1TransactionManager")
public void storeStudents(List<Student> students) {
storeStudents(entityManager, students);
}
}
There may be some other ways to handle this without a 2PC commit setup with JTA, but tyically in container managed transactions (like JBoss, WebLogic, etc); this would be the approach.
As a side bar, if you're already down the spring path I might suggest you check out spring-batch. It provides a decent baseline for batch like operations for a plethora of use cases. What I described above is a poor-mans implementation of one case inside spring-batch.
UPDATE
If you want to avoid having to create multiple shard class implementations with annotation details, you could resort to XML configuration and have a single class implementation:
<bean id="shard1" class="default.ShardStudentServiceImpl">
<property name="entityManager" ref="shard1EntityManager" />
<property name="transactionManager" ref="shard1TransactionManager" />
</bean>
The only difference here is that you have to define your 25 shards in XML and then you have to write your own code to start, commit, and manage the transaction inside your ShardStudentServiceImpl class.
Using the abstract base class in conjunction with annotations in the final implementations shown above my update arrives at the same destination. In fact, if you look at spring-batch, you'll notice their batch configuration follows a similar premise with specifying the entity manager and transaction managers as input properties to a single class.
Related
I am using JPA/hibernate, Spring and JSF.
so my application is organized as following:
I have my entities,
My Dao Interface and implementation for each entity where I define basic methods: findById, add, update, remove ...
and then I have my service layer which just use DAO interfaces and where ther is basically the same methods as in my DAO.
My problem is that in my backing bean, I have a method Add_hospital(), which add a hospital and also services in that hospital, so my method looks like
add_hospital(){
add-hospital();
add-services();
add-Hospital-schedule();
}
so this method is a transaction and I want that if some issue happen, the transaction rollback, but I know that the rollback need to be managed in my DAO, will I need to define my method Add_hospital() in my managed bean, and it's in this stage where I have this combination of inserts.
Please how to solve this problem?
Transactions should be managed on the service layer, not data access.
Example from spring:
#Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
I have an abstract class and two sub classes that extend it. I have the following in spring config file
<bean id="importConfigFile" class="xxx.ImportConfigFiles" parent="parentImportFile"></bean>
<bean id="importFile" class="xxx.ImportUMTSKPIFiles" parent="parentImportFile"></bean>
<bean id="parentImportFile" name="parentImportFile" class="xxx.ImportUMTSFiles" abstract="true"></bean>
<tx:annotation-driven transaction-manager="transactionManager" />
In my abstract class I have the following methods
public void importDataToDB(){
//all the good stuff goes in here
}
#Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
My java code
ImportConfigFiles importConfigFiles = (ImportConfigFiles)context.getBean("importConfigFile");
importConfigFiles.setFileLocation(destPath);
importConfigFiles.importDataToDB();
This does not work. executeInsertUpdateQuery() executes just one native sql query. If I put #Transactional on imortDataToDB() it works but then it makes my transaction huge since inside that method I loop through all the rows in a file and insert the records in db.
This is one of the major pitfalls in Spring - if you call #Transactional-method from non-transactional method in the same class, the #Transactional is ignored (unless you use AspectJ weaving). This is not Spring problem per se - the EJB has the same shortcomings.
Unfortunately with interface-based and class-based proxies all you can do is to split your class in two:
public class BeanA() {
#Resource
private BeanB b;
public void importDataToDB(){
b.executeInsertUpdateQuery();
}
}
public class BeanB {
#Transactional
public void executeInsertUpdateQuery(){
//all the good stuff goes in here
}
}
The whole hustle is caused by the internal implementation of AOP proxies in Spring. With the code above new transaction will be started every time you call b.executeInsertUpdateQuery() from non-transactional BeanA.
I wrote about it on my blog Spring pitfalls: proxying, Spring AOP riddle and Spring AOP riddle demystified.
Not quite sure, what the question is, but #Transactional wraps the entire method in one transaction so obviously it will be huge if you import everything in one method. The advantage is, that if at some place your import fails, the entire transaction will not get executed and no faulty data is in your database.
If you don't want that, you'll have to manage the transactions yourself or call a #Transactional annotated method for a subset of your data, like you're doing right now for one import, but maybe you do it for 10 files or other e.g. logical restrictions.
My Spring+Hibernate configuration files are small and super tight. I use auto scanning to find my model entities/daos.
I don't want to have to write a DAO + DAOImpl for EVERY Entity in my hierarchy.
Some may qualify to have their own, like if they have complex relationships with other entities and require more than basic CRUD functionality. But for the rest...
Is there any way to circumvent the defacto standard?
Say, something like a generic DAO, ex:
http://www.ibm.com/developerworks/java/library/j-genericdao/index.html
Then I can do something like
GenericDao dao = appContext.getBean("genericDao");
dao.save(car);
dao.save(lease);
Is this possible with annotations? I don't want to have to configure anything in xml. If I cannot do above, is it still possible to have one GenericDaoImpl.java with something like:
#Repository("carDao")
#Repository("leaseDao")
class GenericDaoImpl extends CustomHibernateDaoSupport implements GenericDao {
...
}
and then
GenericDao dao = appContext.getBean("carDao");
dao.save(car);
dao = appContext.getBean("leaseDao"); //carDao is garbage coll.
dao.save(lease);
Is this practical at all?
Using generics, you might try something like this:
#Repository
#Transactional
public class GenericDAOImpl<T> implements GenericDAO<T> {
#Autowired
private SessionFactory factory;
public void persist(T entity) {
Session session = factory.getCurrentSession();
session.persist(entity);
}
#SuppressWarnings("unchecked")
public T merge(T entity) {
Session session = factory.getCurrentSession();
return (T) session.merge(entity);
}
public void saveOrUpdate(T entity) {
Session session = factory.getCurrentSession();
session.saveOrUpdate(entity);
}
public void delete(T entity) {
Session session = factory.getCurrentSession();
session.delete(entity);
}
}
The content may be different, but the general idea is applicable.
You should be able to then autowire the DAO in your controller and service classes by using
#Autowired
private GenericDAO<Car> carDao;
You can combine Spring/Hibernate with JPA, which provides the EntityManager for a large amount of basic persistence tasks:
#Service
public class CarService {
#PersistenceContext
private EntityManager em;
public void saveCarAndLease(Car car, Lease lease) {
em.persist(car);
em.persist(lease);
}
}
It will also handle transactions and simple queries without needing to write a DAO. For the more complex operations, you can still write a DAO and fall back to Hibernate's SessionFactory (although JPA is an option here too).
Some tutorials suggest you should still write the DAO for abstraction of the JPA plumbing. However, I have personally found this unnecessary (JPA has a very small integration footprint), and in fact this is also the way Spring Roo deals with the data layer behind the scenes.
Have you tried to use Spring Data. I mean to say Spring JPA where you can use repositories.
You can eliminate writing all stuffs for each entity.
I'm using a JPA EntityListener to do some additional audit work and am injecting a Spring-managed AuditService into my AuditEntryListener using #Configurable. The AuditService generates a collection of AuditEntry objects. The AuditService is itself a Singleton scoped bean, and I'd like to gather all the AuditEntry objects under a common key that can then be accessed by the outermost service layer (the one that invoked the persist call which in turn triggered the EntityListener).
I'm looking at using Spring's TransactionSynchronizationManager to set a specific transaction name (using UID() or some other unique strategy) at the beginning of the transaction, and then using that name as a key within the AuditService that will allow me to group all AuditEntry objects created within that transaction.
Is mixing declarative and programmatic transaction management have the potential for trouble? (Though I'm doing nothing more than setting the transaction name). Is there a better way to associate the generated AuditEntry objects with the current transaction? This solution does work for me, but given that the TransactionSynchronizationManager isn't intended for application use, I'd like to make sure that my use of it won't cause some unforseen problems.
Related Question
Finally, a related, but not immediately pertinent question: I know that the documentation for JPA EntityListeners cautions against using the current EntityManager, but if I did want to use it to diff an object against it's persisted self, would I be safe using an #Transactional(propagation=REQUIRES_NEW) annotation around my preUpdate() method?
Prototype Code:
Service Class
#Transactional
public void create(MyEntity e) {
TransactionSynchronizationManager.setCurrentTransactionName(new UID().toString());
this.em.persist(e);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
Set<AuditEntry> entries = auditService.getAuditEntries(TransactionSynchronizationManager.getCurrentTransactionName());
if(entries != null) {
for(AuditEntry entry : entries) {
//do some stuff....
LOG.info(entry.toString());
}
}
}
});
}
JPA EntityListener
#Configurable
public class AuditEntryListener {
#Autowired
private AuditService service;
#PreUpdate
public void preUpdate(Object entity) {
service.auditUpdate(TransactionSynchronizationManager.getCurrentTransactionName(), entity);
}
public void setService(AuditService service) {
this.service = service;
}
public AuditService getService() {
return service;
}
}
AuditService
#Service
public class AuditService {
private Map<String, Set<AuditEntry>> auditEntryMap = new HashMap<String, Set<AuditEntry>>();
public void auditUpdate(String key, Object entity) {
// do some audit work
// add audit entries to map
this.auditEntryMap.get(key).add(ae);
}
}
#Filip
As far as I understand, your requirement is:
Have an unique token generated within each transaction (database
transaction of course)
Keep this unique token easily accessible across all layers
So naturally you're thinking about the TransactionSynchronizationManager provided by Spring as a facility to store the unique token (in this case, an UID)
Be very carefull with this approach, the TransactionSynchronizationManager is the main storage helper to manage all the #Transactional processing for Spring. Under the #Transactional hood, Spring is creating an appropriate EntityManager, an appropriate Synchronization object and attach them to a thread local using TransactionSynchronizationManager.
In your service class code, inside a #Transactional method your are tampering with the Synchronization object, it can end up with undesirable behavior.
I've done an indept analysis of how #Transactional works here, have a look: http://doanduyhai.wordpress.com/2011/11/20/spring-transactional-explained/
Now back to your needs. What you can do is:
Add a Thread local to the AuditService, containing the unique token when entering the #Transactional method and destroy it when exiting the method. Within this method call, you can access the unique token in any layer. Explanation for ThreadLocal usage can be found here: http://doanduyhai.wordpress.com/2011/12/04/threadlocal-explained/
Create a new annotation, let's say #Auditable(uid="AuditScenario1") to annotate methods that need to be audited and use Spring AOP to intercept these method calls and manage the Thread local processing for you
Example:
Modified AuditService
#Service
public class AuditService {
public uidThreadLocal = new ThreadLocal<String>();
...
...
}
Auditable annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Documented
public #interface Auditable
{
String uid();
}
Usage of #Auditable annotation
#Auditable(uid="AuditScenario1")
#Transactional
public void myMethod()
{
// Something
}
Spring AOP part
#Around("execution(public * *(..)) && #annotation(auditableAnnotation))
public Object manageAuditToken(ProceedingJoinPoint jp, Auditable auditableAnnotation)
{
...
...
AuditService.uidThreadLocal.set(auditableAnnotation.uid())...
...
}
Hope this will help.
You can come up with a solution using the TransactionSynchronizationManager. We register a "TransactionInterceptorEntityListener" with JPA as an entity-listener. What we wanted to achieve is the ability to listen to CRUD events such that we can work with a spring managed "listener" that has a lifecycle tied to the current transaction (i.e., spring-managed but instance per transaction). We sub-class the JPATransactionManager and introduce in the prepareSynchronization() method, a hook to setup a "TransactionInterceptorSynchronizer." We also use the same hook for allow code (in programmatic tx) to associate and retrieve arbitrary objects with the current transaction and also register jobs that run before/after transaction commit.
The overall code is complex, but definitely do-able. If you use JPATemplates for programmatic tx, it is tough to achieve this. So we rolled our own template that simply calls the JPA template after taking care of the interceptor work. We plan to open-source our JPA library (written on top of Spring's classes) soon.
You can see a pattern of adding custom transactions and hooks with Spring managed transactions in the following library for Postgresql
i'm using spring + hibernate. All my HibernateDAO use directly sessionFactory.
I have application layer -> service layer -> DAO layer and all collections is lazly loaded.
So, the problem is that sometime in the application layer(that contains GUI/swing) i load an entity using a service layer method(that contains #Transactional annotation) and i want to use a lazly property of this object, but obviusly the session is already closed.
What is the best way to resolve this trouble?
EDIT
I try to use a MethodInterceptor, my idea is to write an AroundAdvice for all my Entities and use annotation, so for example:
// Custom annotation, say that session is required for this method
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface SessionRequired {
// An AroundAdvice to intercept method calls
public class SessionInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
bool sessionRequired=mi.getMethod().isAnnotationPresent(SessionRequired.class);
// Begin and commit session only if #SessionRequired
if(sessionRequired){
// begin transaction here
}
Object ret=mi.proceed();
if(sessionRequired){
// commit transaction here
}
return ret;
}
}
// An example of entity
#Entity
public class Customer implements Serializable {
#Id
Long id;
#OneToMany
List<Order> orders; // this is a lazy collection
#SessionRequired
public List<Order> getOrders(){
return orders;
}
}
// And finally in application layer...
public void foo(){
// Load customer by id, getCustomer is annotated with #Transactional
// this is a lazy load
Customer customer=customerService.getCustomer(1);
// Get orders, my interceptor open and close the session for me... i hope...
List<Order> orders=customer.getOrders();
// Finally use the orders
}
Do you think can this work?
The problem is, how to register this interceptor for all my entities without do it in xml file?
There is a way to do it with annotation?
Hibernate recently introduced fetch profiles which (in addition to performance tuning) is ideal for solving issues like this. It allows you to (at runtime) choose between different loading and initialization strategies.
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-fetching-profiles
Edit (added section on how to set the fetch profile using an interceptor):
Before you get started: Check that fetch profiles actually will work for you. I haven't used them myself and see that they are currently limited to join fetches. Before you waste time on implementing and wiring up the interceptor, try setting the fetch profile manually and see that it actually solves your problem.
There are many ways to setup interceptors in Spring (according to preference), but the most straight-forward way would be to implement a MethodInterceptor (see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html#aop-api-advice-around). Let it have a setter for the fetch profile you want and setter for the Hibernate Session factory:
public class FetchProfileInterceptor implements MethodInterceptor {
private SessionFactory sessionFactory;
private String fetchProfile;
... setters ...
public Object invoke(MethodInvocation invocation) throws Throwable {
Session s = sessionFactory.openSession(); // The transaction interceptor has already opened the session, so this returns it.
s.enableFetchProfile(fetchProfile);
try {
return invocation.proceed();
} finally {
s.disableFetchProfile(fetchProfile);
}
}
}
Lastly, enable the interceptor in the Spring config. This can be done in several ways and you probably already have a AOP setup that you can add it to. See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-schema.
If you're new to AOP, I'd suggest trying the "old" ProxyFactory way first (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html#aop-api-proxying-intf) because it's easier to understand how it works. Here's some sample XML to get you started:
<bean id="fetchProfileInterceptor" class="x.y.zFetchProfileInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="fetchProfile" ref="gui-profile"/>
</bean>
<bean id="businessService" class="x.y.x.BusinessServiceImpl">
<property name="dao" .../>
...
</bean>
<bean id="serviceForSwinGUI"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="x.y.z.BusinessServiceInterface/>
<property name="target" ref="businessService"/>
<property name="interceptorNames">
<list>
<value>existingTransactionInterceptorBeanName</value>
<value>fetchProfileInterceptor</value>
</list>
</property>
</bean>
Create a method in the service layer that returns the lazy-loaded object for that entity
Change to fetch eager :)
If possible extend your transaction into the application layer
(just while we wait for someone who knows what they are talking about)
You need to rework your session management, unfortunately. This is a major problem when dealing with Hibernate and Spring, and it's a gigantic hassle.
Essentially, what you need is for your application layer to create a new session when it gets your Hibernate object, and to manage that and close the session properly. This stuff is tricky, and non-trivial; one of the best ways to manage this is to mediate the sessions through a factory available from your application layer, but you still need to be able to end the session properly, so you have to be aware of the lifecycle needs of your data.
This stuff is the most common complaint about using Spring and Hibernate in this way; really, the only way to manage it is to get a good handle on exactly what your data lifecycles are.