Force Hibernate To Save A Specific POJO - java

I have some code calling a webservice and it returns an ID. I am saving this ID in the database using hibernate. I have a filter that opens the session and commits it, rolling back when any exception occurs within the contained code. Since there is no way to get back the ID returned by the webservice I would like to save this in the database EVEN if there is an exception that occurred later on in the code. Is there anyway to do this using the same session?

It depends on who throws the exception. If it is thrown by the hibernate session object you cannot reuse the session anymore as stated in hibernate Session documentation:
If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs.
If the exception is thrown by some other code, then yes, you can do something like this:
Long yourIdFromWebservice = ...
try {
// do some processing that might result in an exception
}
catch(//the interesting exception, but not HibernateException) {
//maybe log it, rethrow it
}
finally {
session.save() //save what needed to be saved
}
or depending on your use case:
try {
// do some processing that might result in an exception
session.save() //save all stuff if no exception
}
catch(//the interesting exception, but not HibernateException) {
session.save() //save only the id from the webservice
}

The right way to do that is to use two transactions: one to save the ID, and one to save the rest of your work.
If you're using EJB, you could do the save of the ID in a bean of its own, and annotate it with a TransactionAttribute of REQUIRES_NEW.
Otherwise, you can look at what control over transactions your environment gives you, and figure out a way to have two of them.

Related

How to handle exceptions during spring-boot start-up?

This isn't about how to handle exceptions in Spring MVC or anything. I specifically need to handle an exception that can happen while spring is starting, i.e. before the whole application context is even initialised.
For a bit of background, the application in question is an IoT node that allows remote access to electronic equipment. It has a little h2 database built in to persist some data. That data is nice to have at some moments, but not really essential for the application to work.
It so happens that the device the application is running on can get its power cut every once in a while, and if that happens while there was a write operation to the database going on, the file is corrupt and a JdbcSQLException will be thrown when the application tries to boot again.
Since the data is not really essential, the easiest way to make the application work again is to just delete the database and let h2 recreate it. But in order to do that, I have to catch the exception so I can react to it. The application does not have to continue starting, it will be booted up again by systemd. I really just need to identify the exception and delete the file, that's it.
There is one obvious way to do it, which is to put SpringApplication.run in a try-catch block. But it's also really ugly, because I get the exception I'm looking for nested inside a gazillion spring exceptions that were caused by h2 failing to start.
It was also suggested that I catch the exception in the bean that instantiates the database, but unfortunately there is no bean instantiating it. The DB serves as a Quartz job-store and as such is fully managed by spring. Its entire presence in the code are the following entries in the properties file:
spring.quartz.job-store-type=jdbc
spring.quartz.properties.org.quartz.jobStore.misfireThreshold=900000
spring.datasource.name=h2
spring.datasource.url=jdbc:h2:file:${config.folder}controller
spring.datasource.driverClassName=org.h2.Driver
My question is, is there a way to register some kind of exception handler, or other means, to handle the exception directly when it happens, when I can identify it much more easily?
Depends how you've declared the bean. What's wrong with simply wrapping the bean like this?
#Configuration
class Conf {
#Bean
public DB foo() throws JdbcSQLException
{
try
{
return new DB();
}
catch(JdbcSQLException e)
{
deleteDatabase();
throw JdbcSQLException;
}
}
public static void deleteDatabase()
{
//...
}
}

Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: JDBC rollback failed

I have an application which contains a webservice that use Spring and hibernate in order to retrieve data from database.
Other applications invoke this webservice in their application.
The flow of webservice :
Webservice class method (calls manager class method) --> Manager class method ---> that calls DAO method )
Webservice class :
public List getXXX(){
managerClass.getXX();
}
manager Class:
#Transactional(readOnly=true)
Public List getXX(){
DAOClass.getX();
}
DAO class(It is using hibernate and logic to retrieve data) :
public List getX(){
Criteria query
=getSessionFactory().getCurrentSession()
.createCriteria(dataObject.class);
query.add(Restrictions.eq(dataObject.type, systemId));
query.addOrder(Order.asc(dataObject.TYPE));
query.addOrder(Order.asc(dataObject.code));
return query.list();
}
This Webservice method(by calling manager and DAO classes) giving the list from database. It is working fine all the time except sometimes.
I am not updating or inserting any data,I am just getting the data
(The flow is : Webservice --> manager Class--> DAO --> hibernate)
One client is accessing this method to get the List in their application.he is getting the data properly all the time.But sometimes he is getting this Exception :
javax.xml.ws.soap.SOAPFaultException: Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: JDBC rollback failed
at org.apache.axis2.jaxws.marshaller.impl.alt.MethodMarshallerUtils.createSystemException(MethodMarshallerUtils.java:1346)
at org.apache.axis2.jaxws.marshaller.impl.alt.MethodMarshallerUtils.demarshalFaultResponse(MethodMarshallerUtils.java:1072)
at org.apache.axis2.jaxws.marshaller.impl.alt.DocLitWrappedMethodMarshaller.demarshalFaultResponse(DocLitWrappedMethodMarshaller.java:593)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.getFaultResponse(JAXWSProxyHandler.java:559)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.createResponse(JAXWSProxyHandler.java:497)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.invokeSEIMethod(JAXWSProxyHandler.java:404)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.invoke(JAXWSProxyHandler.java:208)
According to Spring default behavior, whenever the exception is thrown, it tries to roll back.That is what it is trying, but somehow could not rollback. As it is declarative transaction by using annotations, How can I track exact reason for this exception? based on the exception, I definitely know the DAO class method is throwing exception.but I am not able to track the exact reason(whether connection closed issue or any other thing).i just want to use exception handling in DAO class in order to know the exact reason.Can I use try/catch block in DAO class method to have stack trace that prints the exact reason?
I just want to remind once again, it is working fine all the time, but sometimes it is not working because of this exception.
I hope I clearly explained my problem.Please do the needful by giving solution.

Spring transaction management

I am working on spring4 mvc to introduce in our new web application and currently we are using struts1.x and wanted to use new framework for support html5/ajax request as simple as possible and wanted to use the power of DI and spring webflow support.
Currently in our struts1.x application db transaction management is done at our custom GenericAction which is subclass of Action, In GenericAction we are getting the connection from data source and handover to the subclasses then any exception raised then caught and rollback, otherwise commit such that database atomicity (transaction management )is done at one place. All the module action classes should extends GenericAction such that database connection will be available and performs the module related stuff and after completing connection will be either rollback or commit in GenericAction as said above.
In spring, scope of the Transaction is started with #Transactional annotation and then ends with a method in Service Class since the service class marked as #Transactional. This is not feasible solution for me. I have read several documents related to the spring transaction before starting and below are my questions.
I am using HibernateTransactionManager as transaction manager
Transaction should start from interceptors in case web request or any class (in case of unit testing).
Transaction should ends with the after interceptor is executed in case of web request or any class in case of unit testing.
In case of any exception raised then our HandlerExceptionResolverImpl handler will execute then connection should be rollback.
Any workaround or best practices would be greatly appreciate.
Thanks
Dhorrairaajj
In my opinion, you can achieve this with minimal change on the current application by following what Spring does in its org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(Object, TransactionDefinition). In detail, I think something like following should work:
On the GenericAction, get connection from data source (as you've already done)
Bind the connection via its holder with the current data source:
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
Eventually, commit the transaction as org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DefaultTransactionStatus).
In any case, Spring's http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/support/TransactionTemplate.html can help to achieve any programmatic transactional scenario that you want. Just need to ensure that the right transactional resource is bound to the opening transaction.
Hope this helps.
Thanks for you reply. Your post/suggestion drives to do the following
I written an interceptor called TxtManager and below are methods to perform the transaction management.
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception
{
Session session = sessionFactory.openSession();
SessionHolder hold = new SessionHolder(
session);
TransactionSynchronizationManager.bindResource(sessionFactory, hold);
// passing null would accept the default transaction definition.
status = transactionManager.getTransaction(null);
return true;
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception
{
Exception hanlderEx = (Exception) request
.getAttribute(HandlerExceptionResolverImpl.EXCEPTION_KEY);
if (hanlderEx != null)
{
transactionManager.rollback(status);
}
else
{
transactionManager.commit(status);
}
}
In HandlerExceptionResolverImpl class which responsible for handling things upon exception, put an exception object in request and read the same exception to rollback or commit in afterCompletion method of the interceptor.
In between(preHandler and afterCompletion) we will going to use the standard practices to perform the module related stuff including any other interceptos. Unit testing may not be supported, i will check other alternative for unit testing.
Finally we were able to simulate the existing frame work with your suggestion Thanks
Any suggestion to improves this would be much appreciate !!..
Thanks
Dhorrairaajj

add action in transaction rollback

I have a problem running some code right before a transaction rollback in my application. What I want is to have a rollback when an exception occurs but I also want to store some information in a table about the application's state when that exception happened including any errors or stacktrace.
Here is the code I have:
public void performAction(String approverId, Document document, String action) {
try {
LOG.info(String.format("routing document %s %s %s", approverId, document.getDocumentId(), action));
getDocumentService().route(approverId, document, action);
} catch (Exception e) {
LOG.error(String.format("error routing document %s %s %s", approverId, document.getDocumentId(), action));
LOG.error(e, e);
saveException(document, action, e); //this is what I want
}
}
The saveException() method simply creates an objects and saves it to a table.
Now according to Spring documentation about transactions, This rollback happens by default where the exception is a runtime exception and I have confirmed that the rollback works correctly but it's somehow not allowing my code to run and save the information I need or rolling that one back too (?).
Any help or hints to a solution is appreciated.
This is not an uncommon use case: the transaction failed and we want to roll it back, but we would still like to update some monitoring database table with the error cause.
For doing this in a Spring application use REQUIRES_NEW propagation of the #Transactional annotation.
For doing this, create an application state tracking service, and annotate it with REQUIRES_NEW transaction propagation.
Each method in the state tracking service will run in it's own separate transaction, so when the transaction on the main business method rolls back, the state tracking information will still be available on the database.

EJB3 - handling RollBackExceptions

I have an EJB3 application which consists of some EJB's for accessing a DB, and exposed via a Session Bean as a web service.
Now there are two things I need to find out:
1) Is there any way I can stop SQL exceptions from causing the web service from throwing a SOAP Fault? The transactions are handled by the container, and currently sql exceptions cause a RollBackException to be thrown, and consequently the transaction to be rolled back (desired behaviour) and the web service to throw a fault (not desired).
2) I wish to extend the webservice to be able to take in a list of entities, and the session bean to persist each. However, I want each entity to be executed in its own transaction, so that if one fails the others are not affected (and again the web service should not fault).
For (1) I have tried to catch the RollBackException, but I assume this is thrown somewhere on another thread, as the catch block is never reached. I assume for (2) I will need to look into User Transactions, but firstly would prefer the container to manage this, and secondly do not know how to force the use of user transactions.
Thanks.
no, you can do all this with container managed transactions (and this is definitely preferable, as managing transactions is a pain).
the gist of the solution is to create a second EJB with a local interface only and the transaction semantics you desire. then your "public" ejb, which the web-service is calling directly, calls into this second ejb via its local interface to do the actual work.
something along the lines of:
public class MyPublicEjb {
#EJB
private MyPrivateImpl impl;
public void doSomething() {
try {
impl.doSomething();
} catch(TXRolledBack) {
// handle rollback ...
}
}
}
I know this looks sort of ugly, but trust me, this is far preferable to directly manipulating transactions.
For (1): Debug your code to find out where the exception is being thrown and what is causing it. Then handle the exception there.
For (2): Wrap each instance with beginTransaction() and commit().
for(each Entity){
try{
//begin transaction
//save entity
//commit
} catch(Exception e) {
//handle Exception, but continue on
}
}

Categories