Spring Data Mongo : Rollback if exception occurs - spring

I'm working on a project using Spring Data and MongoDB.
I'm wondering if there is some kind of solution to rollback when some exception (standard or custom) occurs.
I tried this solution but unfortunately it didn't work :
#Transactional(rollbackFor = SomeException.class)
For the moment I'm doing the rollback manually by saving what's already deleted and vis-versa.
NOTE: The exception may occur when contacting a foreign micro-service using http.
NOTE2 : I'm using an Exception handler, I removed it and still not working.

Related

What can cause a LazyInitatializationException whereas Spring Open In View is enabled?

I am analysing a "classic" Hibernate error :
org.hibernate.LazyInitializationException : could not initialize proxy – no Session.
I am wondering how it could happen whereas the Spring Open In View mode is enabled?
If you have any documentation or knowledge on a possible reason, please share.
Thanks
Here are some feebacks on my context, and an example of what could cause LazyInitializationException event if Spring Open In View is enabled.
Context
My application is a REST API server developed with Spring Boot 2.5.3.
Spring Open In View is kept enabled by default.
A lot of Services are annotated with #Transactional methods.
Spring-data is used, and Entitymanager too, to create some native queries.
The error
One REST API request, that generates a lot requests to the database (both selections and insertions), fails with LazyInitializationException.
Debugging
By setting a breakpoint when LazyInitializationException is thrown, I discovered that the exception is thrown in org.hibernate.proxy.AbstractLazyInitializer#initialize, because the session is null. Then I discovered that the session is set to null, when the method EntityManager.clear is called. For any reason I don't know, this method was explicitely called in the code.
Fixing
So I just removed the call to EntityManager.clear, and the request works. I'm still wondering why previous developers wanted to clear the EntityManager, probably because they were confused with the transaction management.
Conclusion
Even in Spring Open In View is enabled, and as a result, event if a Hibernate Session is opened, calling EntityManager.clear unset the session to the entities loaded before. Then trying to access a Lazy Loaded field on those entities throws LazyInitializationException.
I hope this will help someone.
Here is the documentation from the latest hibernate version.
As you can see
Indicates an attempt to access not-yet-fetched data outside of a
session context. For example, when an uninitialized proxy or
collection is accessed after the session was closed.
Most probably somewhere you read some entity and then outside of a transaction you try to read some collection which was by default lazy loaded. So then another request needs to be done to database, but since you are out of transaction you receive this exception.
This usually occurs in case you load an entity without the annotation #Transactional or some other configuration to load it inside a transaction and then you give this to your controller to be returned to the user. Then the controller will use jackson or some other library to convert the entity object into a json and will try to read any field. At this point trying to read any lazy loaded collections from the entity, will result in this exception since the read will be outside of a transaction.

spring #transactional noRollbackFor unexpectedly rollsback...any clue?

I have following problem :
Servers runs on WL 12.
The main code is in a EAR, in methods with #Transactional explicitly written as NoRollbackFor=RuntimeException.class
When the exception occurs inside the EAR code, the noRollbackFor is correctly taken into account.
However, when the error occurs in a remote call to another WAR, the transaction is flagged as setRollbackOnly, and subsequent calls to the dabatase (read operations) fail (even if the exception is trapped in the calling code).
Any idea as to why this happens / how to avoid this ?
Thanks !
Make sure that your exception is of type RuntimeException, which triggers a rollback, but checked exception does not

Handling exception when using HibernateDaoSupport

I am using Spring Hibernate integration in my application and DAO classes are extending HibernateDaoSupport.
Suppose I save some object using the code
getHibernateTemplate().save(object);
As Spring Hibernate integration doesn't mandate to write try-catch block, but suppose if any exception is thwron while saving that object.
Then what is the best way to handle it? I means should I catch it in the service layer and wrap it in some user defined excpetions.
Do I need to write try-catch in DAO layer method itself in case I want to log which method in DAO throws exception?
I have never used HibernateDaoSupport or Hibernate Template before so ignorant about exception handling. Please provide me your valuable inputs
The idea behind Spring using RuntimeException is that generally there are different types of exception:
Exceptions that you want to recover from (such as a DuplicateKeyException if a record that you're trying to insert already exists or the more general DataIntegrityViolationException if there was a DB constraint that was violated as a result of user input)
Exceptions that you can't recover from (the database is down)
For the first case, you may well handle the exception (either through a custom business exception, so that the view layer can redirect to the input page and provide a meaningful message)
For the second case, it would be easier to let the exception bubble up and have it handled by a generic exception handler that then displays a generic error page to the user. For this scenario it doesn't make sense to wrap the exception in a custom exception as you won't be able to recover. A blown up DB tends to be fatal.
So what I would do:
try {
getHibernateTemplate().save(object);
} catch (DataIntegrityViolationException dive) {
throw new BusinessValidationException(dive, "You've got the data wrong");
}
Spring exception hierarchy is well documented.
Usually you can't do much if you have a data access exception, because in the working system this may be caused by the shortage of diskspace on the DB server, or network connection problems etc.
Such exceptions are usually need to be logged and investigated as soon as possible.
There some recoverable errors, they can be handled with spring exception hierarchy, but imho most of them should be avoided during the developing phase, so your web server should validate as many things as possible, before it goes to the db.
If you want to set the exception logging see the similar questions:
Exception handler in Spring MVC
Spring MVC Best Practice Handling Unrecoverable Exceptions In Controller

Exception "Unable to commit: transaction marked for rollback" when using camel-jpa and JTA Transactions

I am currently working on a Tutorial to show camel-jpa on Karaf together with JTA Transactions. I use the following route:
from("jpa://net.lr.tutorial.karaf.camel.jpa2jms.model.Person").id("jpa2jms")
.transacted()
.marshal(df)
.bean(new ExceptionDecider())
.to("jms:person");
So I checked if the transactions work by throwing an exception in ExceptionDecider. When I do this I get the following Exception:
https://gist.github.com/3150591
Any ideas what I do wrong? I suspect it might be the way I setup the transaction manager.
You can find my whole project on github:
https://github.com/cschneider/Karaf-Tutorial/tree/master/cameljpa/jpa2jms
This happens when the transaction is marked inside an exception handler but the exception is swallowed. Normally such exceptions should bubble up and cause the whole transaction to rollback.
If the exception is swallowed instead then camel tries to commit at the end which results in the above exception.

Transaction not rolling back

I have mybatis 3.0.4 with mybatis-spring integration 1.0.1 deployed within Fuse (OSGi). I've created a basic database within SQLServer 2008. In Spring I've configured a TransactionAwareDataSourceProxy data source and a DataSourceTransactionManager transaction manager.
Now I've created my own bundle to be deployed within Fuse which inserts some rows into the database. I've told the bundle to use the configured data source and transaction manager. The method which carries out the logic looks like this:
#Transactional(propagation=Propagation.REQUIRED)
public void go(RecsCashContext context) throws ActionException {
When this method throws an exception I can follow Spring through seeing the expected behaviour triggered. This leads me to Springs JtaTransactionManager and doRollBack(..).
So everything looks promising, except that when I look at the database, sure enough it's in an unstable state as previous inserts have not been roll back.
I'm at a loss on this one and I'm struggling to find any information online. Any thoughts?
What kind of exception is being thrown? Unless you tell Spring to explicitly rollback when a particular exception is thrown, it will proceed. By default, Spring's transaction handling only rolls back when an unchecked exception (e.g. RuntimeException) is thrown. In your case, if you're expecting the rollback to occur when ActionException occurs, you're out of luck unless you make the following modification:
#Transactional(rollbackFor={ActionException.class})
public void go(RecsCashContext context) throws ActionException {
More details are in here, specifically in section 10.5.6.1, #Transactional settings
As it turns out Fuse (servicemix) already exposes a transaction manager via an OSGi service within bundle org.apache.aries.transaction.manager_0.2.0.incubating [49]. As a result when I was looking up the transaction manager service, the one exposed by bundle 49 got picked up first.
This was resolved by clearly specifying the transaction manager I was interested in. At the moment I am doing this using the bean-name propery:
<osgi:reference id="transactionManager" bean-name="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
Though this could also be done by using a filter, but preferably we'll just make use of the transaction manager service that's already being expose as opposed to providing our own.

Resources