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

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...

Related

Cannot delete from sql using #Transactional with Spring and Hibernate

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.

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 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.

Monorail, nhibernate and session-per-request pattern

I need some insights and thoughts about a refactoring I'm about to do to our web-app.
We initially used the session-per-request pattern with NHibernate and ActiveRecord by using the On_BeginRequest / On_EndRequest in the HttpApplication to create and dispose the session. Later on, we realized that any DB-related exceptions got thrown outside of our monorail-context, meaning that our rescues didn't kick in. As another sideeffect, we didn't have the option to fully skip creation of NHibernate sessions in any action, which in some cases would be desirable.
So we rewrote it to create sessions in Initialize() / Contextualize() in our base controller, and disposed them in the Dispose() of our base controller. We also Rollback the session in our rescue controller to prevent any half written changes to the DB. So far, so good. The reason for doing it in the Dispose() is because we want it to live through the view-rendering, because of lazy-loading reasons aswell as viewcomponents that needs to get a session (we could switch to units-of-work for the viewcomponents, but they don't seem to have a Dispose()...)
However, I'm experiencing some deadlock issues where we have started transacations in the DB that isn't getting rollbacked nor committed and I can't get my head around it, mostly because of the mess we've made with this approach...
So I found this article: http://hackingon.net/post/NHibernate-Session-Per-Request-with-ASPNET-MVC.aspx
And I thought, "Filters, we can use that in MonoRail too!", because it can kick in on BeforeAction and AfterRendering.
My questions then are:
What happens if an Exception occurs in the filter?
Will AfterRendering fire even if an Exception occurs in the action or the rendering?
Would you recommend this approach, if not, what are your suggestion instead?
Any pointers are very much appreciated!
You need an application error handler to care of exception handling.
Attach a debugger and find out.
Probably not (even though it is my article). It doesn't work with RenderAction. Best to use an IoC container to control the lifetime of connections.