09 transactions new1

42
Professional Open Source™ © JBoss, Inc. 2003, 2004. 1 07/17/04 Transactions Managing concurrent data access

description

 

Transcript of 09 transactions new1

Page 1: 09 transactions new1

Professional Open Source™

© JBoss, Inc. 2003, 2004. 1

07/17/04

TransactionsManaging concurrent data access

Page 2: 09 transactions new1

© JBoss, Inc. 2003, 2004. 2

Professional Open Source™

Transactions

All operations inside a transaction either complete or fail:

Transactionbegin

rollback

commit

Transaction Succeeded

Transaction Failed

Initial State

Page 3: 09 transactions new1

© JBoss, Inc. 2003, 2004. 3

Professional Open Source™

Acid Properties

Atomic—Transactions are made up of one or more activities bundled together as a single unit of work. Atomicity ensures that all the operations in the transaction happen or that none of them happen. If all the activities succeed, the transaction is a success. If any of the activities fail, the entire transaction fails and is rolled back.

Consistent—Once a transaction ends (whether successful or not), the system is left in a state that is consistent with the business that it models. The data should not be corrupted with respect to reality.

Isolated—Transactions should allow multiple users to work with the same data, without each user’s work getting tangled up with the others. Therefore, transactions should be isolated from each other, preventing concurrent reads and writes to the same data from occurring. (Note that isolation typically involves locking rows and/or tables in a database.)

Durable—Once the transaction has completed, the results of the transaction should be made permanent so that they will survive any sort of system crash. This typically involves storing the results in a database or some other form of persistent storage.

Page 4: 09 transactions new1

© JBoss, Inc. 2003, 2004. 4

Professional Open Source™

Programmatic transaction demarcation

In a nonmanaged environment, the JDBC API is used to mark transaction boundaries. You begin a transaction by calling setAutoCommit(false) on a JDBC Connection and end it by calling commit(). You may, at any time, force an immediate rollback by calling rollback().

In a system that manipulates data in several databases, a particular unit of work involves access to more than one resource. In this case, you can’t achieve atomicity with JDBC alone. You need a transaction manager that can handle several resources in one system transaction. Such transaction-processing systems expose the Java Transaction API (JTA) for interaction with the developer. The main API in JTA is the UserTransaction interface with methods to begin() and commit() a system transaction.

Page 5: 09 transactions new1

© JBoss, Inc. 2003, 2004. 5

Professional Open Source™

Hibernate Transaction Interface

Programmatic transaction management in a Hibernate application is exposed to the application developer via the Hibernate

Transaction interface. You aren’t forced to use this API—Hibernate also lets you begin and

end JDBC transactions directly, but this usage is discouraged because it binds your code to direct JDBC.

In a Java EE environment, a JTA-compatible transaction manager is available, so you should call the JTA UserTransaction interface to begin and end a transaction programmatically. However, the Hibernate Transaction interface also works on top of JTA.

Page 6: 09 transactions new1

© JBoss, Inc. 2003, 2004. 6

Professional Open Source™

Hibernate Transaction Interface

org.hibernate.Transaction—Unified transaction demarcation in Hibernate applications. It works in a nonmanaged plain JDBC environment and also in an application server with JTA as the underlying system transaction service. The main benefit, however, is tight integration with persistence context management—for example, a Session is flushed automatically when you commit. A persistence context can also have the scope of this transaction. Use this API in Java SE if you can’t have a JTA-compatible transaction service.

javax.transaction.UserTransaction—Standardized interface for programmatic transaction control in Java; part of JTA. This should be your primary choice whenever you have a JTA-compatible transaction service and want to control transactions programmatically.

Page 7: 09 transactions new1

© JBoss, Inc. 2003, 2004. 7

Professional Open Source™

Contextual sessions

Starting with version 3.0.1, Hibernate added the SessionFactory.getCurrentSession() method. Initially, this assumed usage of JTA transactions, where the JTA transaction defined both the scope and context of a current session.

As of version 3.1, the processing behind SessionFactory.getCurrentSession() is now pluggable. To that end, a new extension interface (org.hibernate.context.CurrentSessionContext) and a new configuration parameter (hibernate.current_session_context_class) have been added to allow pluggability of the scope and context of defining current sessions.

Page 8: 09 transactions new1

© JBoss, Inc. 2003, 2004. 8

Professional Open Source™

CurrentSessionContext

Hibernate comes with three implementations of org.hibernate.context.CurrentSessionContext :

1) org.hibernate.context.JTASessionContext - current sessions are tracked and scoped by a JTA transaction. The processing here is exactly the same as in the older JTA-only approach.

2) org.hibernate.context.ThreadLocalSessionContext - current sessions are tracked by thread of execution.

3) org.hibernate.context.ManagedSessionContext - current sessions are tracked by thread of execution. However, you are responsible to bind and unbind a Session instance with static methods on this class, it does never open, flush, or close a Session.

Page 9: 09 transactions new1

© JBoss, Inc. 2003, 2004. 9

Professional Open Source™

hibernate.current_session_context_class

The hibernate.current_session_context_class configuration parameter defines which org.hibernate.context.CurrentSessionContext implementation should be used.

For backwards compatibility, if this config param is not set but a org.hibernate.transaction.TransactionManagerLookup is configured, Hibernate will use the org.hibernate.context.JTASessionContext.

Typically, the value of this parameter would just name the implementation class to use; for the three out-of-the-box implementations, there are two corresponding short names, "jta", "thread", and "managed".

Page 10: 09 transactions new1

© JBoss, Inc. 2003, 2004. 10

Professional Open Source™

Programmatic transactions in Java SE

Following is the configuration required in Java SE :– The hibernate.transaction.factory_class option defaults to

org.hibernate.transaction.JDBCTransactionFactory, which is the correct factory for the Transaction API in Java SE and for direct JDBC.

After you commit the transaction (or roll it back), the database connection is released and unbound from the Session. Beginning a new transaction with the same Session obtains another connection from the pool.

Page 11: 09 transactions new1

© JBoss, Inc. 2003, 2004. 11

Professional Open Source™

Hibernate in an environment with managed resources

Page 12: 09 transactions new1

© JBoss, Inc. 2003, 2004. 12

Professional Open Source™

Programmatic transactions with JTA

Following is the configuration to be done to switch to JTA :– The hibernate.transaction.factory_class option must be set to

org.hibernate.transaction.JTATransactionFactory.– Hibernate needs to know the JTA implementation on which you’re

deploying, for two reasons:• First, different implementations may expose the JTA UserTransaction, which

Hibernate has to call internally now, under different names.

• Second, Hibernate has to hook into the synchronization process of the JTA transaction manager to handle its caches.

You have to set the hibernate.transaction.manager_lookup_class option to configure both: for example, to org.hibernate.transaction.JBossTransactionManagerLookup.

Page 13: 09 transactions new1

© JBoss, Inc. 2003, 2004. 13

Professional Open Source™

Configuring for JTA

In a managed environment, Hibernate no longer creates and maintains a JDBC connection pool—Hibernate obtains database connections by looking up a DataSource object in the JNDI registry. Hence, your Hibernate configuration needs a reference to the JNDI name where managed connections can be obtained.

hibernate.connection.datasource=java:/MyDatasource hibernate.transaction.factory_class =

org.hibernate.transaction.JTATransactionFactory hibernate.transaction.manager_lookup_class = org.hibernate.transaction.JBossTransactionManagerLookup

Page 14: 09 transactions new1

© JBoss, Inc. 2003, 2004. 14

Professional Open Source™

Sample code using UserTransaction

Page 15: 09 transactions new1

© JBoss, Inc. 2003, 2004. 15

Professional Open Source™

With default settings, it’s also your responsibility to flush() each Session manually to synchronize it with the database. You also have to close all Sessions manually.

you can enable the hibernate.transaction.flush_before_completion and/or the hibernate.transaction.auto_close_session configuration options and let Hibernate take care of session flushing and closing automatically. Hibernate will flush and close the session when the JTATransaction ends.

Page 16: 09 transactions new1

© JBoss, Inc. 2003, 2004. 16

Professional Open Source™

What does JTATransactionFactory do?

It enables correct Session scoping and propagation for JTA if you decide to use the SessionFactory.getCurrentSession() method instead of opening and closing every Session manually.

– The current Session is bound automatically to the current JTA system transaction. When the transaction completes, either through commit or rollback, the persistence context is flushed and the internally bound current Session is closed.

– It tells Hibernate that you’re planning to call the JTA UserTransaction interface in your application to start, commit, or roll back system transactions.

– It also switches the Hibernate Transaction API to JTA, in case you don’t want to work with the standardized UserTransaction. If you now begin a transaction with the Hibernate API, it checks whether an ongoing JTA transaction is in progress and, if possible, joins this transaction. If no JTA transaction is in progress, a new transaction is started. If you commit or roll back with the Hibernate API, it sets the system transaction to commit or roll back.

Page 17: 09 transactions new1

© JBoss, Inc. 2003, 2004. 17

Professional Open Source™

Why to use JTA’s UserTransaction insteadof Hibernate Transaction?

U can’t use the Hibernate Transaction interface together with the getCurrentSession() feature and JTA. You need a Session to call beginTransaction(), but a Session must be bound to the current JTA transaction—a chicken and egg problem.

This again emphasizes that you should always use JTA ‘s UserTransaction when possible and Hibernate Transaction only if you can’t use JTA.

Page 18: 09 transactions new1

© JBoss, Inc. 2003, 2004. 18

Professional Open Source™

JNDI-bound SessionFactory

If you deploy your application in an environment that supports JNDI, Hibernate can bind a SessionFactory to JNDI, and you can look it up there when needed.

The Hibernate SessionFactory automatically binds itself to JNDI if the hibernate.session_factory_name property is set to the name of the JNDI node. If your runtime environment doesn’t provide a default JNDI context you need to specify a JNDI initial context using the hibernate.jndi.url and hibernate.jndi.class properties.

hibernate.session_factory_name = java:/hibernate/MySessionFactory hibernate.jndi.class = com.sun.jndi.fscontext.RefFSContextFactory hibernate.jndi.url = file:/auction/jndi The SessionFactory is bound to JNDI when you build it, which means

when Configuration.buildSessionFactory() is called. To keep your application code portable, you may want to implement this build and the lookup in HibernateUtil, and continue using that helper class in your data access code

Page 19: 09 transactions new1

© JBoss, Inc. 2003, 2004. 19

Professional Open Source™

Hibernate transaction support

Hibernate supports system transactions withA. JDBC transaction management if we use a connection pool directly

B. JTA transactions in Application Servers

C. any custom TransactionFactory and Transaction implementation

The Hibernate Transaction API hides the underlying

strategy and keeps our persistence layer code portable.

Page 20: 09 transactions new1

© JBoss, Inc. 2003, 2004. 20

Professional Open Source™

Controlling concurrent access

Databases attempt to ensure transaction isolation, meaning that, from the point of view of each concurrent transaction, it appears that no other transactions are in progress.

This isolation is implemented by Locking.

Page 21: 09 transactions new1

© JBoss, Inc. 2003, 2004. 21

Professional Open Source™

Transaction isolation issues

A lost update occurs if two transactions both update a row and then the second transaction aborts, causing both changes to be lost. This occurs in systems that don’t implement locking. The concurrent transactions aren’t isolated.

A dirty read occurs if a one transaction reads changes made by another transaction that has not yet been committed. This is dangerous, because the changes made by the other transaction may later be rolled back, and invalid data may be written by

the first transaction.

Lost Update Dirty Read

Page 22: 09 transactions new1

© JBoss, Inc. 2003, 2004. 22

Professional Open Source™

Transaction isolation issues

An unrepeatable read occurs if a transaction reads a row twice and reads different state each time. For example, another transaction may have written to the row and committed between the two reads

A special case of unrepeatable read is the second lost updates problem. Imagine that two concurrent transactions both read a row: One writes to it and commits, and then the second writes to it and commits. The changes made by the first writer are lost.

Unrepeatable read

Page 23: 09 transactions new1

© JBoss, Inc. 2003, 2004. 23

Professional Open Source™

Transaction isolation issues

A phantom read is said to occur when a transaction executes a query twice, and the second result set includes rows that weren’t visible in the first result set or rows that have been deleted.This situation is caused by another transaction inserting or deleting rows between the

execution of the two queries

Page 24: 09 transactions new1

© JBoss, Inc. 2003, 2004. 24

Professional Open Source™

Read Uncommitted isolation

A system that permits dirty reads but not lost updates is said to operate in read uncommitted isolation.

One transaction may not write to a row if another uncommitted transaction has already written to it. Any transaction may read

any row, however. This isolation level may be implemented in the database management system with exclusive write locks.

Page 25: 09 transactions new1

© JBoss, Inc. 2003, 2004. 25

Professional Open Source™

Read Committed isolation

A system that permits unrepeatable reads but not dirty reads is said to implement read committed transaction isolation.

This may be achieved by using shared read locks and exclusive write locks.

Reading transactions don’t block other transactions from accessing a row. However, an uncommitted writing transaction blocks all other transactions from accessing the row.

Page 26: 09 transactions new1

© JBoss, Inc. 2003, 2004. 26

Professional Open Source™

Repeatable Read Isolation

A system operating in repeatable read isolation mode permits neither unrepeatable reads nor dirty reads.

Phantom reads may occur.

Reading transactions block writing transactions (but not other reading transactions), and writing transactions block all other transactions.

Page 27: 09 transactions new1

© JBoss, Inc. 2003, 2004. 27

Professional Open Source™

Serializable Isolation

Serializable provides the strictest transaction isolation. This isolation level emulates serial transaction execution, as if transactions were executed one after another, serially, rather than concurrently.

Serializability may not be implemented using only row-level locks. There must instead be some other mechanism that prevents a newly inserted row from becoming visible to a transaction that has already executed a query that would return the row.

Page 28: 09 transactions new1

© JBoss, Inc. 2003, 2004. 28

Professional Open Source™

Choosing an isolation Level

First, eliminate the read uncommitted isolation level. It’s extremely dangerous to use one transaction’s uncommitted changes in a different transaction. The rollback or failure of one transaction will affect other concurrent transactions.

Secondly, most applications don’t need serializable isolation and this isolation level tends to scale poorly.

Repeatable read isolation level eliminates the possibility that one transaction can overwrite changes made by another concurrent

transaction (the second lost updates problem) if all data access is performed in a single atomic database transaction. A read lock held by a transaction prevents any write lock a concurrent transaction may wish to obtain. This is an important issue, but enabling repeatable read isn’t the only way to resolve it.

Page 29: 09 transactions new1

© JBoss, Inc. 2003, 2004. 29

Professional Open Source™

Choosing an isolation Level

The combination of the persistence context cache and versioning already gives you most of the nice features of repeatable read isolation. In particular, versioning prevents the second lost updates problem, and the persistence context cache also ensures that the state of the persistent instances loaded by one transaction is isolated

from changes made by other transactions. So, read-committed isolation for all database transactions is acceptable if you use versioned data.

Page 30: 09 transactions new1

© JBoss, Inc. 2003, 2004. 30

Professional Open Source™

Setting an isolation level

Every JDBC connection to a database is in the default isolation level of the DBMS—usually read committed or repeatable read. You can change this default in the DBMS configuration. You may also set the transaction isolation for JDBC connections on the application side, with a Hibernate configuration option:

hibernate.connection.isolation = 2

The sensible values for this option are as follows : 1—Read uncommitted isolation 2—Read committed isolation 4—Repeatable read isolation 8—Serializable isolation

Page 31: 09 transactions new1

© JBoss, Inc. 2003, 2004. 31

Professional Open Source™

Optimistic concurrency control

An optimistic approach always assumes that everything will be OK and that conflicting data modifications are rare. Optimistic concurrency control raises an error only at the end of a unit of work, when data is written. Multiuser applications usually default to optimistic concurrency control and database connections with a read-committed isolation level.

Page 32: 09 transactions new1

© JBoss, Inc. 2003, 2004. 32

Professional Open Source™

A Scenario

Let’s assume that two users select the same piece of data at the same time. The user in conversation A submits changes first, and the conversation ends with a successful commit of the second transaction. Some time later ,the user in conversation B submits changes. This second transaction also commits successfully. The changes made in conversation A have been lost, and modifications of data committed in conversation B may have been based on stale information.

Page 33: 09 transactions new1

© JBoss, Inc. 2003, 2004. 33

Professional Open Source™

U have three choices for how to deal with lost updates in these second transactions in the conversations:

Last commit wins—Both transactions commit successfully, and the second commit overwrites the changes of the first. No error message is shown.

First commit wins—The transaction of conversation A is committed, and the user committing the transaction in conversation B gets an error message. The user must restart the conversation by retrieving fresh data and go through all steps of the conversation again with nonstale data.

Merge conflicting updates—The first modification is committed, and the transaction in conversation B aborts with an error message when it’s committed. The user of the failed conversation B may however apply changes selectively, instead of going through all the work in the conversation again.

Page 34: 09 transactions new1

© JBoss, Inc. 2003, 2004. 34

Professional Open Source™

If you don’t enable optimistic concurrency control, and by default it isn’t enabled, your application runs with a last commit wins strategy

Obviously, first commit wins is much more attractive. If the application user of conversation B commits, he gets an error message

Hibernate uses managed versioning for optimistic locking to implement the second and third strategy

Page 35: 09 transactions new1

© JBoss, Inc. 2003, 2004. 35

Professional Open Source™

Application Transaction: An example

Two system administrator edit the same user account and submit:

Last commit wins: Both succeed, the second update overwrites the changes, no error message is shown.

First commit wins: The first succeeds and the second administrator gets an error message, he restarts the process with fresh data.

Merge conflicting changes: The first succeeds and the second administrator merges his changes manually.

Hibernate can help:– The first strategy is the default if we don't change anything

– Hibernate uses managed versioning for optimistic locking to implement the second and third strategy.

Page 36: 09 transactions new1

© JBoss, Inc. 2003, 2004. 36

Professional Open Source™

Managed versioning

A timestamp/version is incremented every time the data is updated– we have to add a new property to our persistent class

– we have to map it with <version> or <timestamp>– If we are using <timestamp>, instance variable should

be Date

public class Item { ... private int version; ... private void setVersion(int version) { this.version = version; } private int getVersion() { return version; }}

<class name="Item" table="ITEM"> <id ..... <version name="version" column="VERSION"/> ...</class>

Page 37: 09 transactions new1

© JBoss, Inc. 2003, 2004. 37

Professional Open Source™

Managed versioning in action

Hibernate will– automatically set the value of the version/timestamp property

– increment it automatically whenever an item is modified

– throw an exception if the version has been increment meanwhile

– use only a single UPDATE by default (checking the return value)

If this update returns zero updated records, someone has increment this version of the record already and we have stale data!

update ITEM setDESCRIPTION='New Description',SELLER=45,VERSION=3

whereID=123

andVERSION=2

Page 38: 09 transactions new1

© JBoss, Inc. 2003, 2004. 38

Professional Open Source™

Managed version without a version/timestamp property

Optimistic concurrency can be used without extra columns:Hibernate will use the "old" object state to check all columns for modification

when updating and throw an exception if anything changed.

Only works for version checks in a single Session, no detached objects!

<class name="Item" table="ITEM" optimistic-lock="all"> <!-- we might also use "dirty" for only changed values --> <id ..... ...</class>

update ITEM setDESCRIPTION='New Description', SELLER=45

where ID=123and DESCRIPTION='Old Description'and SELLER=45

Page 39: 09 transactions new1

© JBoss, Inc. 2003, 2004. 39

Professional Open Source™

Explicit pessimistic locking

Consider the following example :

This unit of work executes two reads. The first retrieves an entity instance by identifier. The second read is a scalar query, loading the description of the already loaded Item instance again. There is a small window in this unit of work in which a concurrently running transaction may commit an updated item description between the two reads. The second read then returns this committed data, and the variable description has a different value than the property i.getDescription().This example is simplified, but it’s enough to illustrate how a unit of work that mixes entity and scalar reads is vulnerable to reads, if the database transaction isolation level is read committed. nonrepeatable

Page 40: 09 transactions new1

© JBoss, Inc. 2003, 2004. 40

Professional Open Source™

Instead of switching all database transactions into a higher and nonscalable isolation level, you obtain stronger isolation guarantees when necessary with the lock() method on the Hibernate Session:

Using LockMode.UPGRADE results in a pessimistic lock held on the database for the row(s) that represent the Item instance. Now no concurrent transaction can obtain a lock on the same data .

Page 41: 09 transactions new1

© JBoss, Inc. 2003, 2004. 41

Professional Open Source™

The Hibernate lock modes

LockMode.NONE—Don’t go to the database unless the object isn’t in any cache.

LockMode.READ—Bypass all caches, and perform a version check to verify that the object in memory is the same version that currently exists in the database.

LockMode.UPDGRADE—Bypass all caches, do a version check (if applicable), and obtain a database-level pessimistic upgrade lock, if that is supported. This mode transparently falls back to LockMode.READ if the database SQL dialect doesn’t support

a SELECT ... FOR UPDATE option. LockMode.UPGRADE_NOWAIT—The same as UPGRADE, but use

a SELECT …FOR UPDATE NOWAIT, if supported. This disables waiting for concurrent lock releases, thus throwing a locking exception immediately if the lock can’t be obtained.

Page 42: 09 transactions new1

© JBoss, Inc. 2003, 2004. 42

Professional Open Source™

The Hibernate lock modes

LockMode.FORCE—Force an increment of the objects version in the database, to indicate that it has been modified by the current transaction.

LockMode.WRITE—Obtained automatically when Hibernate has written to a row in the current transaction.