Cannot delete from sql using #Transactional with Spring and Hibernate - sql

I have #Transactional set up correctly, however with the following method "success" is returned but the record is not deleted from the table:
#Transactional
public void deleteLimXrefHvo(LimitXrefHvo limitXrefHvo){
getSession().delete(getTableId(limitXrefHvo));
}
I tried with the method getTableId annotated with #Transactional as well and that does not solve the problem. I've also called getTableId and stored the return value in a variable before passing it into delete() and that did not work, either.
The only thing that works that I've tried is to add getSession().flush(); after the delete transaction. If I have #Transactional set up, then I shouldn't need to flush after. What am I missing?

The session may live longer than a single transaction. This seems to be the case here. From the JSR-220 5.6:
A container-managed persistence context may be defined to have either
a lifetime that is scoped to a single transaction or an extended
lifetime that spans multiple transactions, depending on the
PersistenceContextType that is specified when its EntityManager is
created. This specification refers to such persistence contexts as
transaction-scoped persistence contexts and extended persistence
contexts respectively.
I know you said 'Spring' and not Java EE container but I believe it boils down to the same behavior.
This is to say that session-scope is not equal transaction-scope. For your specific problem you may check:
Is ´deleteLimXrefHvo()´ called from another #Transactional method (hint: what about transaction propagation)?
What flush mode does the transaction have (manual?)?
Investigate your logs, in particular I would set the logging level to DEBUG on your transaction manager to see exactly what it's doing.

it was getTableId that was causing the problem. getTableId calls its own getSession(), and because of that, I have to flush(). there is no getting around it. makes sense, though.

Related

Nhibernate: Is it possible to throw an exception if Save() is called without beginning a transaction

I was wondering if we can some how extend NHiberate to throw an exception if a piece of code attempted to save an object to a database without beginning a transaction? Since beginning a transaction is a requirement for calling Save() to work properly, I can't see a programmer calling Save() without beginning a transaction in the first place.
Solution is not in the exception throwing. It is about keeping us (developers on the project) aware of what and where we are doing
1) Project shared approach. Firstly, explain to the team how the Architecture of application works. All team members should now, that Unit of Work, or Session per Request patterns are in place.
2) The FlushMode. Secondly, explain the concept of the Session object. ISession. Save() or Update() is far away from SQL execute INSERT or UPDATE. What count is the ISession.Flush(). And (based on the first step) we can decide when that Flush() happens.
I would suggest setting the FlushMode to on Commit or None (with explict call). And then, if a team member would like to Execute any write command - one standard place, one common way (used on the project) will guide hin/her.
The call Session.Flush() should/will/must be wrapped in a transaction.

#MessageDriven transactions and redelivery semantics

What's the best way to accomplish the following?
#MessageDriven bean does some work on database
on failure, I want to roll back the DB transaction
but I also want the JMS message NOT to be redelivered, i.e., don't re-try.
I can think of a few ways that might work. Are there any others, and which is the best?
use #TransactionManagement(type=BEAN) and UserTransaction, and explicitly roll back after catching exception. e.g.:
catch (Exception e) {
e.printStackTrace();
utx.rollback();
}
Use container-managed transactions, specify #TransactionAttribute(value=NOT_SUPPORTED) on onMessage and then delegate DB activity to a separate method with #TransactionAttribute(value=REQUIRED).
Leave the transaction handling alone and re-configure the retry property in the server. I'm using Glassfish 3.1.1, and I'm not exactly sure how to set this.
Leave everything alone and explicitly check the message for re-delivery in the onMessage body, and exit out if re-delivered. (message.getJMSRedelivered()?)
What has worked well out there? Is there a standard/best-practice way for dealing with this?
Simplest and most portable approach is use #TransactionAttribute(value=NOT_SUPPORTED) on onMessage() as you state and to move the DB work to another bean with #TransactionAttribute(REQUIRES_NEW)
Be careful about the separate method approach as this will not work. In a JMS MDB the onMessage() method is the only method where #TransactionAttribute can be used.
Personally I never do any work in the MDB, but dispatch immediately to an (injected) session bean.
This bean then does the DB work. It either starts a new transaction, or I catch any exception from the bean and log it (but don't let it propogate, so no redelivery).
This also has the advantage that the business logic is easly reusable from other places.

How should NHibernate update properties mapped as Version

Using fluent NHibernate I have a property on a class mapped using Version
Version(x => x.Version);
When I save the object, the Version property gets incremented in the database as I would expect, but the value of the property on the object only seems to change sometimes.
using (var tx = session.BeginTransaction())
{
session.Merge(item);
tx.Commit();
item.Version; // Sometimes this is still 1, when I expect it to be 2.
}
The problem is then that if it remains as 1 and I make more changes and save again I get a StaleObjectStateException.
What's weird is that sometimes it works fine and the item.Version value does get correctly incremented, but I can't figure out the difference between the cases where it does and the cases where it doesn't.
I've tried searching but can't seem to find any documentation on this. Can anyone explain what NHibernates expected behaviour is with the Version mapping?
[NHibernate version 2.1.2]
From the ISession.Merge documentation:
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session.
So, it will not modify item.
(I might add I have never used Merge in my apps. You might want to review how you are dealing with attached and detached entities)
Did you try
item = session.Merge(item);
tx.Commit();
?
You need to flush the session before the updated version will propagate up to your entities. Unless you flush the session, you are responsible for keeping the entities up to date yourself.
You should TYPICALLY let the session flush on its own when its closed. However, in some instances where you rely on database updates that happen via nhibernate and not settings you make to the entity itself, you might need to flush the session yourself after a commit. In this case be aware that when you flush the session ANY entities that are dirty will be committed. This may not be desirable so be sure that the scope is very limited.

How to wrap lazy loading in a transaction?

I am using nhibernate and the nhibernate profile what keeps throwing this alert.
Use of implicit transactions is discouraged"
I actually wrap everything in a transaction through ninject
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope()
.OnActivation(StartTransaction)
.OnDeactivation(CommitTransaction);
}
public void CommitTransaction(ISession session)
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void StartTransaction(ISession session)
{
if (!session.Transaction.IsActive)
{
session.BeginTransaction();
}
}
}
So this should wrap everything in a transaction and it seems to work with anything that is not lazy loading.
If it is lazy loading though I get the error. What am I doing wrong.
This is, in fact, still an implicit transaction, or relatively close to it. The injector is blissfully ignorant of everything that's happened between activation and deactivation and will happily try to commit all your changes even if the state is incorrect or corrupted.
What I see is that you're essentially trying to cheat and just have Ninject automatically start a transaction at the beginning of every request, and commit the transaction at the end of every request, hoping that it will stop NH from complaining. This is extremely bad design for several reasons:
You are forcing a transaction even if the session is not used at all (i.e. opening spurious connections).
There is no exception handling - if an operation fails or is rolled back, the cleanup code simply ignores that and tries to commit anyway.
This will wreak havoc if you ever try to use a TransactionScope, because the scope will be completed before the NH transaction is.
You lose all control over when the transactions actually happen, and give up your ability to (for example) have multiple transactions within a single request.
The NH Profiler is exactly right. This isn't appropriate use of NH transactions. In fact, if you're lazy loading, the transaction might end up being committed while you're still iterating the results - not a good situation to be in.
If you want a useful abstraction over the transactional logic and don't want to have to twiddle with ISession objects then use the Unit Of Work pattern - that's what it's designed for.
Otherwise, please code your transactions correctly, with a using clause around the operations that actually represent transactions. Yes, it's extra work, but you can't cheat your way out of it so easily.

How to ensure that NHibernate is inside a transaction when saving, updating or deleting?

I'd like to ensure, that when I'm persisting any data to the database, using Fluent NHibernate, the operations are executed inside a transaction. Is there any way of checking that a transaction is active via an interceptor? Or any other eventing mechanism?
More specifically, I'm using the System.Transaction.TransactionScope for transaction management, and just want to stop myself from not using it.
If you had one place in your code that built your session, you could start the transaction there and fix the problem at a stroke.
I haven't tried this, but I think you could create a listener implementing IFlushEventListener. Something like:
public void OnFlush(FlushEvent #event)
{
if (!#event.Session.Transaction.IsActive)
{
throw new Exception("Flushing session without an active transaction!");
}
}
It's not clear to me (and Google didn't help) exactly when OnFlush is called. There also may be an implicit transaction that could set IsActive to true.
If you had been using Spring.Net for your transaction handling, you could use an anonymous inner object to ensure that your DAOs/ServiceLayer Objects are always exposed with a TransactionAdvice around their service methods.
See the spring documentation for an example.
To what end? NHProf will give you warnings if you're not executing inside a transaction. Generally you should be developing with this tool open anyway...