Printed from A Developer website designed for Developers

NHibernate: Transactions

Transaction Interface

The ITransaction interface provides methods for declaring the boundaries of a database transaction.

The BeginTransaction() method of the Persistent Manager (ISession) is invoked to begin a database transaction.

The Commit() method of the Persistent Manager (ISession) commits the underlying transaction, and NHibernate sychronizes the Session state with the database. This process is called flushing.

NHibernate doesn't flush before every query, but if changes are held in memory that would affect the results of the query, NHibernate will, by default, synchronize first.

NHibernate defines the Persistent Manager (ISession) FlushMode property to control the flush behaviour.

Property Value Property Description
FlushMode.Auto Default. If changes are held in memory that would affect the results of a query, NHibernate will synchronize state with the database.
FlushMode.Commit NHibernate won't flush the session before query execution. This could result in modifications made to objects in memory conflicting with the results of the query.
FlushMode.Never NHibernate will only synchronize state with the database when an explicit call to the Flush() method is invoked.

It is generally not recommended to change this setting from the default.

Transaction Isolation Levels

Setting the transaction isolation level in NHibernate allows you to choose a good default locking strategy for all your database transactions. NHibernate doesn't add additional semantics and it uses whatever is available within a given database.

The standard isolation levels that are defined are: Read Uncommitted, Read Committed, Repeatable Read and Serializable.

Isolation Level Description
Read Uncommitted Any transaction may read any data row in the database, but a transaction may not write to a data row if another uncommitted transaction has already written to it.
It is possible that changes made by one transaction that ends up being rolled back could be committed anyway, because they could be read and then propagated by another transaction that is successful.
Read Committed An uncommitted writing transaction blocks all other transactions from accessing the data row in the database.
Using read-committed isolation for all database transactions is acceptable when using the functionality available in NHibernate for versioned data.
Repeatable Read Reading transactions block writing transactions only, and allow other reading transactions to access the data row in the database. Writing transactions block all other transactions.
It is possible that a transaction executes a query twice, and the second result set includes rows that weren't visible in the first result set. Caused by another transaction inserting new rows between the execution of the two queries.
Serializable Emulates serial transaction execution, as if transactions had been executed one after another, serially, rather than concurrently.
This isolation level tends to scale poorly and few existing applications use serializable isolation in production.

Every ADO.NET connection to a database uses the database's default isolation level. To overwrite the transaction isolation level for the ADO.NET connection, set the hibernate.connection.isolation configuration property in the NHibernate configuration.

NHibernate will then set this isolation level on every ADO.NET connection obtained from a connection pool before starting a transaction.

Transaction Locking

Locking is a mechanism that prevents concurrent access to a particular item of data. A pessimistic lock is a lock that is acquired when an item of data is read and that is held until transaction completion.

NHibernate allows you to explicitly specify a more restrictive lock for a particular transactions using a pessimistic lock. In certain circumstances, pessimistic locks may be used to prevent database-level deadlocks, which can result in transaction failure.

NHibernate defines several lock modes: LockMode.None, LockMode.Read, LockMode.Upgrade and LockMode.UpgradeNoWait.

Lock Mode Description
LockMode.None Only query the database if the object is not cached.
LockMode.Read Bypass both levels of the cache, and perform a version check to verify that the object in memory is the same version that currently exists in the database.
LockMode.Upgrade Bypass both levels of the cache, do a version check, and obtain a database-level pessimistic upgrade lock, if that is supported.
LockMode.UpgradeNoWait Bypass both levels of the cache, do a version check, and obtain a database-level pessimistic upgrade lock, if that is supported. But don't wait for release of concurrent locks.

By specifying an explicit LockMode other than LockMode.None, NHibernate is forced to bypass both levels of the cache and go all the way to the database.

The recommended practice is not to use an explicit LockMode unless absolutely necessary. Most of the time caching is more useful than pessimistic locking.