#Transactional method called from another method doesn't obtain a transaction - java

In Spring, a method that is annotated with #Transactional will obtain a new transaction if there isn't one already, but I noticed that a transactional method does not obtain any transaction if it is called from a non-transactional one. Here's the code.
#Component
public class FooDao {
private EntityManager entityManager;
#PersistenceContext
protected void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional
public Object save(Object bean) {
return this.entityManager.merge(bean);
}
public Object saveWrap(Object bean) {
return save(bean);
}
}
#Component
public class FooService {
private FooDao fooDao;
public void save(Object bean) {
this.fooDao.saveWrap(bean); // doesn't work.
this.fooDao.save(bean); // works
}
}
saveWrap() is a regular method that calls save() which is transactional, but saveWrap() won't persist any changes.
I'm using Spring 3 and Hibernate 3. What am I doing wrong here? Thanks.

It is one of the limitations of Springs AOP. Because the dao bean is in fact a proxy when it is created by spring, it means that calling a method from within the same class will not call the advice (which is the transaction). The same goes for any other pointcut

Yes, this is expected behaviour. #Transactional tells spring to create a proxy around the object. The proxy intercepts calls to the object from other objects. The proxy does not intercept calls within the object.
If you want to make this work, add #Transactional on the method that is invoked from "outside".

This is a bit late I know, but would just like to add a way to overcome this limitation is that within the method obtain the spring bean from the application context and invoke the method. When the spring bean is obtained from the application context it will be the proxy bean not the original bean . Since the proxy bean is now invoking the method instead of the original bean the transaction advice will be implemented on it.

A possible workaround is to call the method like if it was invoked from "outside"
You can do it by getting the current proxy of the component and then call the method :
((MyService) AopContext.currentProxy()).innerMethod();
Source: https://www.programmersought.com/article/58773839126/

Related

Spring Data: JPA and Nested Transaction

I am having a problem with Spring JPA Data and nested transactions. Following are two methods with a nested transaction of my service.
#Service
public UserService {
#Transactional
public User createUser(UserDto userDto) {
....
user = saveUser(user);
sendEmail(user);
....
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public User saveUser(User user) {
return userRepository.save(user);
}
It happens there is one scenario that the method userRepository.save() should throw an exception but somehow is not being thrown, it looks like it is waiting the parent transaction to be finished. I was expecting the exception being thrown on the saveUser method and the sendEmail method not even to be executed.
Because the method UserService.saveUser have the propagation set to Propagation.REQUIRES_NEW I was expecting that transaction to be commited (the SQL statement to be executed) and any exception being propagated.
I did not setup anything related with Transaction, so i believe that the flush mode is set to AUTO.
Can anyone spot what i am doing wrong or what is my misconception?
It's because you're invoking #Transactional method from within same bean.
#Transactional only works on methods invoked on proxies created by spring. It means, that when you create a #Service or other bean, method called from the outside will be transactional. If invoked from within bean, nothing will happen, as it doesn't pass through proxy object.
The easiest solution would be to move the method to another #Service or bean. If you really want to keep it within same component, then you need to invoke it, so that it gets wrapped in proxy by spring AOP. You can do this like that:
private YourClass self;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void postContruct(){
self = applicationContext.getBean(YourClass.class);
}
Then invoking method on self would result in opening a transaction.
In other words: you are not experiencing any of those anomalies, because #Transactional over saveUser does not work.

Strict alternative to Spring #Transactional annotation

I have a Spring bean with #Transactional method.
public class ABean{
#Transactional
public void method aMethod(){
//do some job with Hibernate.
}
}
But now I need to call this method from another method which should be called not in Spring context (in Quartz context actually):
public class ABean implements org.quartz.Job{
#Transactional
public void method aMethod(){
//do some job with Hibernate.
}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("start...");
//#Transactional annotation is ignored here
//so I have 'Could not obtain transaction-synchronized Session
//for current thread' exception.
aMethod();
System.out.println("done");
}
}
As I understand annotation #Transactional just somehow wraps method with some another code. So how I must wrap aMethod() call to call it exactly like Spring calls?
You can use Transaction from Hibernate instead as you said this method will not run in Spring managed environment and use it pro grammatically.
Create Session object from Hibernate SessionFactory.
From Session you can get Transaction using session.beginTransaction().
Check out :
Hibernate Docs
Spring only adds its transactional logic when you call it from another bean. When calling a method from the same class, the annotation is ignored.
For you that means you should move aMethod() to another Bean and invoke it from your existing ABean.

Why Spring Bean Self Invocation is working here for Transaction

Environment :
Tomcat 6
Spring 4
Hibernate 4
Spring MVC
Code :
I have below service layer class :
public interface AbhisheskService {
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
#Service("abhishekService")
public class AbhishekServiceImpl implements AbhisheskService {
#Autowired
private AbhishekDao abhishekDao;
#Transactional
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto) {
return getAbs();
}
public List<AbhishekDTO> getAbs(){
Abhishekdetails absDt = this.abhishekDao.get(4L);
return null;
}
}
The AbhishekDao is a standard DAO layer interface which extends GenericDAO super interface.
public interface AbhishekDao extends GenericDAO<Abhishekdetails, Long>{
public List<Abhishekdetails> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
My question is :
findByMatchingCriteria method is marked with #Transactional.
This method calls another method getAbs which is NOT MARKED AS #Transactional and it is invoked within findByMatchingCriteria (self-invocation).
As per my understanding since :
1)findByMatchingCriteria is calling getAbs within itself (self-invocation) , getAbs() method SHOULD NOT run inside transaction. Since it is bypassing dynamically created proxy here
2)Moreever getAbs doesn't have #Transactional annotation on it.
3)But when getAbs calls this.abhishekDao.get(4L) everything works fine and a record with ID 4L is retrieved. The DAO bean is calling sessionFactory.getCurrentSession() inside it to get object from Db. But why is this working ?
Since there SHOULD NOT BE any active transaction.
4)Why is above code working ? A lot of posts on Spring Transaction management state that self invocation will not work. (Even spring docs).
Then why is above set up working ?
Am I amissing anything here ?
Or My understanding of spring transaction is incorrect?
Please repply as I am getting confused here
The way it works is:
- AbhishekServiceImpl bean is wrapped in a proxy.
findByMatchingCriteria is #Transactional, so before the method is invoked Spring gets new database connection from the connection pool and sets auto commit to false.
The transactions are bound to a thread, so the other methods on this thread will use this connection.
The methods findByMatchingCriteria and getAbs are executed
after findByMatchingCriteria Spring calls commit on the connection(or rollback if RuntimeException occurs).
So your code is in transaction that's around findByMatchingCriteria
A case where a transaction will not be created is if you have #Transactional on getAbs , but not on findByMatchingCriteria(reverse the calling) and you call findByMatchingCriteria outside of the service. But if you call only getAbs outside of the service it will be in transaction.
More clear example:
#Service
public class MyServiceImpl implements MyService{
#Autowired
private MyDao myDao;
#Transactional
public List<T> transactionalMethod() {
return this.myDao.get(4L);
}
public List<T> notTransactionalMethod(){
return transactionalMethod();
}
}
In some other class:
#Component
public class SomeClass {
#Autowired
private MyService myService;
public void someMethod(){
myService.transactionalMethod();//will be in transaction. Here actualy you go to the proxy first and then it calls the real method.
myService.notTransactionalMethod();//will not be in transaction and hibernate will throw an error.
//You go to the proxy, but doesent do anything special because the method is not transactional and it calls the real method,
//but here you dont't got trough the proxy so the #Transactional is ignored.
}
}

Indirect Hibernate/JPA method call loses transaction

I'm using Spring/JPA2/hibernate with this code:
class A {
#Autowired
B b;
#RequestMapping("/test")
public void test(final HttpServletRequest r1, HttpServletResponse r2) throws ... {
b.inner(); // Works
b.outer(); // javax.persistence.TransactionRequiredException:
// no transaction is in progress ... :|
}
#Component
class B {
#PersistenceContext
EntityManager em;
public void outer() { inner(); }
#Transactional
public void inner() { em.flush(); }
}
Why does inner() only when called indirectly loose the transaction?
http://static.springsource.org/spring/docs/current/reference/transaction.html#transaction-declarative-annotations
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional.
Consider the use of AspectJ mode (see mode attribute in table below) if you expect self-invocations to be wrapped with transactions as well. In this case, there will not be a proxy in the first place; instead, the target class will be weaved (that is, its byte code will be modified) in order to turn #Transactional into runtime behavior on any kind of method.
The #Autowired reference B b (inside class A), is wrapped with a Spring AOP transaction-aware proxy.
When b.inner() is called, you are invoking it on the transaction-aware instance, and it is marked as #Transactional. Thus a Spring managed transaction is started.
When b.outer() is called, it is also on a transaction-aware instance, but it is not #Transactional. Thus a Spring managed transaction is not started.
Once you are inside the invocation of outer() the call to inner() is not going through the transaction-aware proxy, it is being invoked directly. It is the same as this.inner(). Since you are invoking it directly, and not through the proxy, it does not have the Spring transaction-aware semantics.
Since no transaction has been started, this results in the TransactionRequiredException.
Possible solutions include making the method outer() #Transactional.
#Transactional
public void outer() { inner(); }
Or making the entire class #Transactional.
#Transactional
#Component
class B {
#PersistenceContext
EntityManager em;
The transactional context lasts over the scope of your spring bean's entire lifespan. #Transactional notation has a scope of the entire component and you should annotate your #Component as #Transactional eg
#Transactional
#Component
class B {
#PersistenceContext
EntityManager em;
public inner() { }
public outer() { }
}
The methods inner and outer should accomplish individual units of work. If you need some helper function or what have you that is fine, but the unit of work that requires the transactional boundary should be scoped to each method. See the spring docs on #Transactional http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html

Spring Injection - access to the injected object within a constructor

I have a resource (Spring bean) which has some of its fields injected by Spring, for example:
#Repository(value="appDao")
public class AppDaoImpl implements AppDao {
#PersistenceContext
EntityManager entityManager;
public Resource() {
... use entityManager ... // doesn't work
}
}
I know that I can't access the injected entityManager in the constructor and should use a #PostConstruct annotation on a different method. But what are the reasons for this?
Because Spring can't access any fields or methods before the object is created (which is done through the constructor). So Spring instantiates the object using the constructor and then injects the properties.
The only way around this is to use Constructor Injection (which can be cumbersome if you have multiple dependencies). I think what you should do is move your code out of the constructor and into an initialization method using the #PostConstruct annotation:
#PostConstruct
public void init(){
// do stuff with entitymanager here
}
The reason is in the lifecycle of the bean:
The container (spring application context) instantiates the object
then it sets all the dependencies (incl. the entityManager in your example)
after all dependencies have been set, it invokes the #PostConstruct method, if any.
Spring (and no one) can set fields to an object before actually constructing that object.
You can use constructor-injection - passing the dependencies to a non-default constructor, but it is not possible with #PersistenceContext

Categories

Resources