Hibernate Doesn't Flush Fast Enough to Catch DB Exceptions - java

I have a method, inside a Try/Catch block, which calls a Hibernate DB Save operation to insert a row.
The method completes successfully even though there are DB problems (e.g. when I insert a NULL into a non-NULL column). Then, at some later point, Hibernates attempts to "flush" or complete the transaction, and that's when errors get thrown.
This messes up the flow of my code because I depend on my method completing successfully to do other things, e.g. send out emails. After calling my method, I go on to send out emails based on the assumption that no errors have happened (otherwise I would have been thrown out of my code flow and into my Catch block, but this is not happening).
Does anyone have any ideas how to deal with this situation?

The trivial answer is to simply call Session.flush() and any pending SQL will get run, causing any SQL exceptions that might be lurking to happen at that time.
On a sort of larger scope, you may want to look at options for validating your data at the application level, rather than relying on SQL exceptions to detect errors. There are up and downsides to either way of course.

Related

JAVA SQL Database Locked Error

I am having trouble running my code. Every time I enter user information to sign up a user i get the the error:
java.sql.SQLException: database is locked
The error is most likely a result of incomplete operations you have started and not finished elsewhere against the database, such as transactions you haven't committed. You should close all resources. Something somewhere didn't get closed properly, causing the lock to stay on.
Result of your query() method - the result set - is never closed.
It is helpful to tell which database are you using, since they have different ways of handling locks.
Also, you may wish to add simple debug points, like "System.out.println" to each of your database operations. This helps you to see the flow of database statements which end up with a lock.
Once you have an exception, you shall keep the exception call stack. This helps to identify on which SQL operation did you get the lock - and helps focusing on the real problem.
(May I suggest considering MVC or a light DDD to isolate gui and db code to keep your code clean, and avoiding doing any database operation from the event handling thread since that will eventually introduce lockups on your gui, once you get as big as spotify. :))

Synchronizing spring transaction

We use Spring and Hibernate in our project and has a layered Architechture. Controller -> Service -> Manager -> Dao. Transactions start in the Manager layer. A method in the service layer which updates an object in the db is called by many threads and this is causing to throw a stale object expection. So I made this method Synchronized and still see the stale object exception thrown. What am I doing wrong here? Any better way to handle this case?
Thanks for the help in advance.
The stale object exception is thrown when an entity has been modified between the time it was read and the time it's updated. This can happen inside a single transaction, but may also happen when you read an object in a transaction, modify it (in the controller layer, for example), then start another transaction and merge/update it (in this case, minutes or hours can separate the read and the update).
The exception is thrown to help you avoid conflicts between users.
If you don't care about conflicts (i.e. the last update always wins and replaces what the previous ones have written), then don't use optimistic locking. If you're concerned about conflicts, then StaleObjectExceptions will happen, and you should popup a meaningful message to the end user, asking him to reload the data and try to modify it again. There's no way to avoid them. You must just be optimistic and hope that they won't happen often.
Note that your synchronized trick will work only if
the exception happens only when reading and writing in the same transaction
updates to the entity are only made by this service
your application is not clustered.
It might also reduce the throughput dramatically, because you forbid any concurrent updates, regardless of which entities are updated by the concurrent transactions. It's like if you locked the whole table for the duration of the whole transaction.
My guess is that you would need to configure optimistic locking on the Hibernate side.

How can I configure Hibernate to immediately apply all saves, updates, and deletes?

How can I configure Hibernate to apply all saves, updates, and deletes to the database server immediately after the session executes each operation? By default, Hibernate enqueues all save, update, and delete operations and submits them to the database server only after a flush() operation, committing the transaction, or the closing of the session in which these operations occur.
One benefit of immediately flushing database "write" operations is that a program can catch and handle any database exceptions (such as a ConstraintViolationException) in the code block in which they occur. With late or auto-flushing, these exceptions may occur long after the corresponding Hibernate operation that caused the SQL operation.
Update:
According to the Hibernate API documentation for interface Session, the benefit of catching and handling a database exception before the session ends may be of no benefit at all: "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."
Perhaps, then, the benefit of surrounding an "immediate" Hibernate session write operation with a try-catch block is to catch and log the exception as soon as it occurs. Does immediate flushing of these operations have any other benefits?
How can I configure Hibernate to apply all saves, updates, and deletes to the database server immediately after the session executes each operation?
To my knowledge, Hibernate doesn't offer any facility for that. However, it looks like Spring does and you can have some data access operations FLUSH_EAGER by turning their HibernateTemplate respectively HibernateInterceptor to that flush mode (source).
But I warmly suggest to read the javadoc carefully (I'll come back on this).
By default, Hibernate enqueues all save, update, and delete operations and submits them to the database server only after a flush() operation, committing the transaction, or the closing of the session in which these operations occur.
Closing the session doesn't flush.
One benefit of immediately flushing database "write" operations is that a program can catch and handle any database exceptions (such as a ConstraintViolationException) in the code block in which they occur. With late or auto-flushing, these exceptions may occur long after the corresponding Hibernate operation that caused the SQL operation
First, DBMSs vary as to whether a constraint violation comes back on the insert (or update ) or on the subsequent commit (this is known as immediate or deferred constraints). So there is no guarantee and your DBA might even not want immediate constraints (which should be the default behavior though).
Second, I personally see more drawbacks with immediate flushing than benefits, as explained black in white in the javadoc of FLUSH_EAGER:
Eager flushing leads to immediate
synchronization with the database,
even if in a transaction. This causes
inconsistencies to show up and throw a
respective exception immediately, and
JDBC access code that participates in
the same transaction will see the
changes as the database is already
aware of them then. But the drawbacks
are:
additional communication roundtrips with the database, instead of a single
batch at transaction commit;
the fact that an actual database rollback is needed if the Hibernate
transaction rolls back (due to already
submitted SQL statements).
And believe me, increasing the database roundtrips and loosing the batching of statements can cause major performance degradation.
Also keep in mind that once you get an exception, there is not much you can do apart from throwing your session away.
To sum up, I'm very happy that Hibernate enqueues the various actions and I would certainly not use this EAGER_FLUSH flushMode as a general setting (but maybe only for the specific operations that actually require eager, if any).
Look in to autocommit though it is not recommended. If your work includes more than one update or insert SQL statement, you autocommit some of the work, and then a statement fails, you have a potentially arduous task of undoing the first part of the action. It gets really fun when the 'undo' operation fails.
Anyway, here's a link that shows how to do it.

Catching TransactionRolledbackLocalException in Java

I receive javax.ejb.TransactionRolledbackLocalException in Websphere 7 from the container and I wonder how is it possible to catch this exception? I have a timeout set in Websphere and get this message after this time. I run session beans.
I am trying to find what SQl statement was the cause of this exception. Where can i find that?
As per Sun's docs
Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.
TransactionRolledbackLocalException is an unchecked exception and there is nothing you can do if it happens. You could catch it as Aaron Digulla suggests in his answer, but what is the point ?
If you catch it then you will be messing with the internals of the App Server. You will get an exception on the client and you can call getCause() on the exception you get on the client to properly notify the user.
You have two solutions
Look at what is causing the timeout
(Probably bad SQL)
Increase the timeout
A transaction is rolled back when one of two conditions are met:
There is an exception in your code
There is a timeout
Obviously, you can catch the exception in case #1 by wrapping the outermost code with a try{}catch(). But which code of yours is executed on timeout?
Unless your app server offers an API to attach a listener to such events, this is not possible. See the documentation which you received with the product or call the support for details.
[EDIT] If you want to see the SQL which actually causes the timeout, you have two options:
You can use java.sql.DriverManager.setLogWriter(w); to log all SQL statements to a file. While this always works, it will create a lot of output and it will be hard to match this against the exception unless you can make sure you are the only one running requests.
If you use an OR mapper (like Hibernate and such), you can enable logging for them. See here for Hibernate.
You can use also the [Log4JDBC] (https://code.google.com/p/log4jdbc/).
This allows for logging in front of the driver.
The way it works is that you specify it in the datasource like a proxy.
Of course that if you are using hibernate it is simpler to set the show sql property.
But if you use JDBC this will work because all query's go through here.

Dealing with RollbackException in Java

Is there any way to "replay" transaction?
I mean, sometimes I get RollbackException and rollback the transaction. Can I then "clone" the transaction and try again, or once rollback is called, transaction is lost?
I really need the changes, and really don't want to trace every change for rerunning later...
thanks,
udi
Why do you get the exception in the first place ? This seems to me to be the crux of the matter.
Are you relying on optimistic writing ? If so, then you'll have to wrap your database writes in some form of loop, incorporating (perhaps) a backoff and a number of retries. You can't do this automatically, unfortunately (unless you investigate some form of AOP solution wrapping your database writes with a retry strategy ?)
That depends where that transaction comes from. In Java/JDBC, a transaction is tied to a connection. You start one by setting setAutoCommit() to false (otherwise, every statement becomes its own little transaction).
There is nothing preventing you from reusing the connection after a transaction failed (i.e. you called rollback).
Things get more tricky when you use Spring. Spring wraps your methods in a transaction handler and this handler tries to guess what it should do with the current transaction from the exceptions that get thrown in the method. The next question is: Which wrapper created the current transaction? I just had a case where I would call a method foo() which would in turn call bar(), both #Transactional.
I wanted to catch errors from bar() in foo() and save them into the DB. That didn't work because the transaction was created for foo() (so I was still in a transaction which Spring thought broken by the exception in bar()) and it wouldn't let me save the error.
The solution was to create baz(), make it #Transactional(propagation=Propagation.REQUIRES_NEW) and call it from foo(). baz() would get a new, fresh transaction and would be able to write to the DB even though it was called from foo() which already had a (broken) transaction.
Another alternative is to use JDBC savepoints to partly roll back.

Categories