issue with spring transaction management? - java

I am using spring and hibernate. i am using spring for transaction management. i have below class.
#Service
#Transactional(readOnly = true)
public class Sample implements SampleInterface{
#Override
public List<Some> getData(){
//gets data after that it updates something
setStatus(someId);
}
#Override
#Transactional
public void setStatus(Long someId){
//sets status
}
}
If i dont keep #Transactional for getData() then i get below exception.
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode
if i keep #Transactional for getData() then it will save properly. what is an issue here? any how i have #Transactional for setStatus(). Still do i need to keep #Transactional for getData() as it is calling a public method which will set the status?
Thanks!

The problem is a bit complex and is caused by calling setStatus() inside getData(). When you are calling getData() from outside, you are actually calling a Java proxy created for you by Spring framework. This proxy applies transaction behaviour (starts read-only transaction) and delegates to your actual service class. This works fine.
However, when you call setStatus(), you are bypassing the transactional proxy and calling your service directly. In other words the request to setStatus() is not intercepted, and #Transactional is ignored.
There is no easy way to deal with this problem and ejb has the same issue. You just have to be extra careful when calling public methods inside the same class.
See also
8.6.1 Understanding AOP proxies - official documentation
Spring pitfalls: proxying - my blog

When you call getData (without #Transactional on the method) Spring will start a read only transaction as that is the default for your class and when getData calls setStatus Spring will use the existing rad only transaction instead of creating a new one. That's the reason you are getting the exception.
The default transaction propagation is PROPAGATION REQUIRED. Read more on the topic at http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html#tx-propagation

Related

Spring transaction not being created when invoking #Transactional method via reflection

I have a class that is invoking a public method on another class via reflection. The invoking class already has an active transaction, and the public method on the invoked class is marked with
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleProcess() { ..}
The invocation looks like
Runnable runnable = null;
Method handleMethod = config.handleProcessMethod;
Object handler = autowireHandler(process);
runnable = () -> {
LOGGER.info("executing method {} on {}",handleMethod,handler);
handleMethod.invoke(handler);
};
runnable.run();
The method is called correctly, but the log indicates that it is particpating in the current transaction instead of creating a new one.
08:54:33.452 [process-executor-2] DEBUG o.springframework.orm.jpa.JpaTransactionManager - Found thread-bound EntityManager ... for JPA transaction
08:54:33.453 [process-executor-2] DEBUG o.springframework.orm.jpa.JpaTransactionManager - Participating in existing transaction
Edit: Actually the logs from above are being created within the invoked method, caused by a JPA repository, not prior to it. So it looks like the #Transactional annotation isn't being processed at all.
Is the reflection causing spring to miss the #Transactional annotation? I need the invoked method to use it's own transaction so that it's committed prior to returning from the invocation.
The annotation tells Spring what to wrap with a proxy that implements the transactional behavior. Reflection is bypassing that proxy and calling the wrapped method directly. Looking at the logs should confirm that, you may need to dial up log level for spring stuff.
Don't use reflection for this, because that's going behind Spring's back and it can't help you. You can autowire a list of services that implement a common interface. Your code can go through the list and figure out which one is relevant to what you need to do, then call the method on the chosen service.
If you are submitting tasks to an executor, you are going to have trouble when there is no entitymanager found on the worker thread. If you make these services use Spring async methods instead, that will let Spring handle the transactions, entityManager, etc.

Spring #transactional not auto rolling back during unchecked exception

Class A{
#transactional
public Void methodA(){
methodB();
int i=10/0;
}
#transactional
public void methodB(){
session.save(student)
}
Here there is an exception in methodA but it is not rolling back and inserting student data.why?
}
By default, #Transactional rolls back on runtime exceptions.
You need to use rollbackFor().
#Transactional(rollbackFor = {MyException.class})
Method marked with #Transactional has to be public.
This is documented in Spring Manual chapter 10.5.6:
Method visibility and #Transactional
When using proxies, you should apply
the #Transactional annotation only
to methods with public visibility. If
you do annotate protected, private or
package-visible methods with the
#Transactional annotation, no error
is raised, but the annotated method
does not exhibit the configured
transactional settings. Consider the
use of AspectJ (see below) if you need
to annotate non-public methods.
Beacuse A and B separate transactions !
When you call a method without #Transactional within a transaction block, the parent transaction will continue to the new method. It will use the same connection from the parent method(with #Transactional) and any exception caused in the called method(without #Transactional will cause the transaction to rollback as configured in the transaction definition.
If you call a method with a #Transactional annotation from a method with #Transactional within the same instance, then the called methods transactional behavior will not have any impact on the transaction. But if you call a method with a transaction definition from another method with a transaction definition, and they are in different instances, then the code in the called method will follow the transaction definitions given in the called method.
You can find more details in the section Declarative transaction management of spring transaction documentation.
Spring declarative transaction model uses AOP proxy. so the AOP proxy is responsible for creation of the transactions. The AOP proxy will be active only if the methods with in the instance are called from out side the instance.
The answer depends on what you already know.
Do you know how Spring works when you add a #Transactional annotation?
Ans: It does so by creating a proxy class for the class which has annotated methods.
Do you know how Spring Proxy object works when one method in the proxied class calls another method in the same proxied class?
Ans: Sprig is not able to handle this scenario implicitly. Any annotation on the called method would be ignored (since the call happens on 'this' rather than on the Proxy)
You need to switch to AspectJ to handle such scenario's
If you really like to understand this behavior I recommend reading this section of the Spring documentation.

How to have thread safe controller in spring boot

How should I create a controller which is thread safe?
As per the best practice controllers are singleton.
Consider the below code in which im storing user data through a autowired service Object ,which makes my code stateful.
How would i make the below code thread safe.
#RestController
class ApiController {
#Autowired
IDbService< User > iDBService;
#RequestMapping(value = "/api/adduser", method = RequestMethod.POST)
public ResponseEntity<User> createUser(#RequestBody User user){
User savedUser=iDBService.create(user);
return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
}
Here is my Service implementation.
I have shared variable in my service
public class IDbServiceImpl<T> implements IDBService<T>{
#Autowired
GenericRepository<T, Serializable> genericRepository;
#Override
public T create(T object) {
return genericRepository.save(object);
}
}
Your controller is a singleton by default and your service is singleton by default too.
Therefore in order to make them thread safe you have to make sure that the operations that take place inside the service must be thread safe, in case of changing the state of an object inside the service ie. a list.
In case of using a rdbms then you have a transaction related problem.
If you use spring and Jpa, the transaction manager will take care for your updates provided that you use #Transactional. In case of plain jdbc method then you can either use pure jdbc and do the transaction handling on your own or use spring-jdbc that comes with a transaction manager.
If you want the database rows not to be changed in case of a write in progress then you have to take into consideration row-locking related mechanisms. – gkatzioura Feb 7 at 15:23
In case of JPA using #Transactional will do the work. However depending on your application you might have to consider locking. Check this article on locking with jpa.
Controllers are singletons, therefore they should be implemented in a thread safe manner.
Design your application in a way that controllers are stateless. Add transactional support in your #Repository layer.
Example:
public class GenericRepository<T, Serializable> {
#Transactional
public void save(T object) {
// save user
}
}
You could use Spring declarative transaction management mechanism. The #Transactional annotation itself defines the scope of a single database transaction.
Your controller looks thread safe. As there is no instance variable storing the state. User object will be different for each request and will be resolved by the MVC framework.

Seam #Transactional annotation not working?

I'm using the #Transactional annotation on a seam component similar to:
#Name( "myComponent" )
#AutoCreate
public class MyComponent
{
public void something() {
...
doWork();
}
...
#Transactional
protected void doWork() {
try {
log.debug( "transaction active: " + Transaction.instance().isActive() );
} catch (Exception ignore) {}
// some more stuff here that doesn't appear to be inside a transaction
}
}
In the "some more stuff" section, I'm modifying some Hibernate entities and then had a bug where an Exception was thrown. I noticed that the Exception wasn't causing the transaction to be rolled back (the modified entities were still modified in the db) so I added the "transaction active" logging. When this code executes, isActive() returns false.
Is there something I'm missing? Why isn't the transaction active?
In case it matters, I'm using the Seam component from inside another component that is using RESTEasy annotations to trigger my method calls.
I'm not familiar with how Seam works so my apologies in advance if this answer does not apply.
I noticed that the method that is #Transactional is protected. This implies to me that it is being called by another internal method.
With Spring's AOP, you mark the public methods with #Transactional which are wrapped and replaced with a transaction proxy. When an external class calls the public method, it is calling the proxy which forms the transaction. If the external class calls another public method that is not marked with #Transactional which then calls an internal method which is, there will be no transaction created because the proxy is not being called at all.
In Spring, even if you change your doWork() method to be public, the same problem would happen. No transaction because the proxy object is not being called. Method calls made inside of the class are not making calls to the proxy object.
A quick read of some documentation seems to indicate that, like Spring AOP, Seam is using CGLib proxying. The question is if it is able to proxy all methods -- even if they are called from within the proxied object. Sorry for wasting your time if this answer does not apply.

How to call a custom rollback method in Spring Transaction Management?

Environment: Spring 3, Custom Transaction Management, JDBC Transactions
I just read the Spring docs on using the transaction template to handle transaction management. It seemed overly complex so I want to ask:
Most of my transactions are JDBC related, meaning I just declare an #Transactional on my service. But now I am making a REST service call to another site which needs to rollback if any of the following JDBC operations fail, I'll provide the rollback code in this case.
As I progress in my method, in my transaction - I want to save a reference to the REST service call (needed to roll back that action), and upon exception I just want a method myCustomRollback() called which can access the previously stored object.
Why not just provide a map in the transactionTemplate for storing stuff and define a custom rollback method on the #Transactional annotation?
This is the way I think about it, I'm not following the way Spring thinks about this. Can someone help me bridge the gap between what I want and how I accomplish it most efficiently in Spring? I only need to do this for a few special case operations.
To anyone still reading this:
I solved a similar problem with spring events - as suggested by Den Roman in option 3.
Here's the basic idea (scenario is fictional):
Whenever I perform external operations that need to be rolled back together with the transaction, I publish an event inside my #Transactional method using support from spring (org.springframework.context.ApplicationEventPublisher):
#Transactional
public String placeOrder(Order order) {
String orderId = orderServiceGateway.createOrder(order);
applicationEventPublisher.publishEvent(new OrderCreatedEvent(orderId));
workflowService.startWorkflow(orderId);
return orderId;
}
The event itself can be any object - I created a POJO with details about the remote entity to be deleted.
Then I registered a special event listener that is bound to a transaction phase - in my case to the rollback:
#TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void rollBackOrder(OrderCreatedEvent orderCreatedEvent) {
String orderId = orderCreatedEvent.getOrderId();
orderServiceGateway.deleteOrder(orderId);
}
Of course, it's recommended to catch & log the exception from rollback operation, not to lose the original exception from the placeOrder() method.
By default these events are synchronous, but they can be made async by additional configuration.
Here's a very good article on this mechanism, including detailed configuration and pitfalls: Transaction Synchronization and Spring Application Events (DZone)
While I don't like the solution 100% because it clutters the business logic with event publishing stuff and binds to spring, it definitely does what I expect it to do and makes it possible to pass context from the transactional method to the rollback method - which is not available through a traditional try/catch block outside of the transactional method (unless you put your context in the exception itself, which is not very nice).
I've re-read your question a few times and am not sure I understand your question completely. I assume your executing someCode and if that fails you would like to execute myCustomRollback which has some information about someCode. So I'll try to provide a Generic answer.
If you want spring to rollback some code. It will only rollback that which is rollBackAble, like jdbc transactions. Assume you have a method which performs 2 calls.
#Transactional
public void doStuff(SomeEntity entity, File file) {
persist(entity);
customFileService.createOnFileSystem(file);
throw new RunTimeException();
}
So the code above will always rollback. It will undo the persisting of your entity, but not the creation of your file, since that is not managed by Spring transactions, unless you provide custom implementation for it to be.
Second, Spring provides 2 ways of working with transactions:
Spring AOP: a proxy is created at runtime which will decorate your code with transactional stuff. If your class would be named MyClass, then Spring will create a class names MyClassProxy, which will wrap your code in transactional code.
AspectJ: at compile time your .class file will be adjusted and transactional code will be embedded inside your method.
The aspectJ approach seems harder to configure, but isn't so much and is way easier to use. Since anything which is annotated with #Transactional will be embedded (weaved) with code. For Spring AOP this is not the case. Transactional inner method calls for instance in Spring will be ignored! So aspectJ provides a more intuitive approach.
Back to what I think your question is (the code is all in 1 class):
public void doSomeCode() {
Object restCall = initialize();
try {
execute(restCall);
} catch (CustomException e) {
myCustomRollback(restCall; e);
}
}
#Transactional(rollbackFor = CustomException.class)
private void execute(Object restCall) throws CustomException {
// jdbc calls..
restCall = callRest(restCall);
throw new CustomException();
}
void myCustomRollback(Object restCall, CustomException e) {
...
}
The code above will only work with AspectJ! Since your making inner method calls which also seems to be private! AOP at runtime cannot handle this.
So what happens is everything (which is rollbackAble) in execute will be rollbacked. And in doStuff you have information about the objects which were used in execute, you now can use in myCustomRollback to rollback your REST stuff manually.
Not sure if I answered this question properly, but I hope it helps someone with a similar problem.
1 solution is to implement your own transactional manager by extending a one
2 solution is to use TransactionSynchronizationManager class
3 solution is to use #TransactionalEventListener in case you have Spring 4
Spring transaction management the default behavior for automatic rollback is for unchecked exceptions
so for a custom exception,
#Transactional(rollbackFor = CustomException.class, noRollbackFor = RuntimeException.class)
public void doSomething(...
)
the transaction be rolled back if it there is an exception that matches the specified. If an exception not matches, it is propagated to caller of the service or TransactionRolledBackException wrapper
if you use use the org.springframework.transaction.PlatformTransactionManager it is more manageable handling exceptions than template
check the documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
you can use the AfterThrowing advice (when an exception is thrown) & call your method (myCustmRollback()) there, you can use TransactionSynchronizationManager class to get thecurrent transaction & roll it back...
alternatively.. you can use the AroundAdvice to begin & commit/rollback your transaction (this way you can use the spring provided transaction manager by using the TransactionSynchronizationManager class)

Categories