I can't find information about how JTA transaction cooperates (initiates?) internal datebase transaction, for example a transaction in MySQL datebase which is added to JEE servers datebase tx resources. This lack of knolwedge triggers some questions qbout how Optimistic Lock works (is implemented).
I will try to submit the problem in three steps to make it more clear (it is a little bit complicated). Maybe somebody will see what I mean.
1. I' m not sure whether each time JTA transaction starts (for example in CMT EJB) and some operation are made on datebase resource (even without JPA interface, it may be just injected DataSource ) Transaction Manager opens an interenal transaction in that datebase resource (for example the native MySQL transaction). In other words how closely is JTA transaction mapped on real interanl datebase native transaction? This is the first question for the whole problem.
2. The first point (above) makes another doubt. Let's see such example: I have CMT stateless EJB with Container-Manged Entity Manager which uses my JPA class. The methods codes of that EJB are conducted in JTA container manged transacions. Persistence.xml settings of my JPA indicate my MySQL datebase. In one method of my EJB I call "find()" (or Select Query) to get entity object, then I make some state changes to that entity object (some fileds values) and then I "flush()" it to the datebase. As far as I know, in this moment ("flush()" call) the changes made to entity object are flushed to final datebase source (MySQL db) as an update of a record. But this update is made in scope of datebase native transaction so that if the JTA transaction in my EJB method rollbacks this update will be rollbacked as well. The quetion is (connected with first point) when that native datebase transaction starts?
A. Does it start on my first method call on Entity Manger (find(), or Query )?
B. Does it starts on "flush()" call?
It is important question because my MySQL datebase is run in Repeatable Read isolation as default. If its native transaction starts at "find()" (or Select Query) then chosen record are blocked for writing for other transactions (threads) for the whole that transaction. If "find()" was made as separate call (automatically commited) then untill "flush()" is called, other threads can modify my record.
3. And here we get to the Optimistic Lock. If my JPA class will use Optimistic Lock (implementing field marked with @Version annotation) and the internal, native datebase transaction starts as it is described in case "A" then, concering that my datebase uses Repeatable Read isolation, the Optimistic Lock is completely useless because datebase isolation doesn't allow for modifying record which was previously read by another transaction. If native transaction starts as it is described in "B" point, then despite Repeatable Read isolation, Optimistic Lock is still useful because the record can be changed by another transaction between reading it by first thread (my EJB method) and calling "flush()" in that thread.
So the main quetsion is how JTA transaction cooperates with internal datebase transaction.
Sorry for troubling but solving this question will help me a lot.
# 1 - Yes, the database transaction starts the first time the JTA managed resource (JTA DataSource/JDBC connection) is accessed in the JTA transaction. It is committed/rolled-back occur with the JTA commit/rollback.
# 2 - Well, this depends on how you have configured things, and what JPA provider you are using.
Normally A would be true, the transaction would start on the first database access, i.e. the find().
However, if you specify a non-jta-data-source in addition to a jta-datasource in your persistence.xml then the JPA provider may optimize things to avoid the database transaction until flush() or any other operation that requires a transaction, such as a native query, update-all, or pessimistic lock. EclipseLink does this optimization when you specify a non-jta-data-source, or when not using JTA. You can configure the transaction to begin early instead by setting the eclipselink.jdbc.exclusive-connection.mode persistence property.
Also if your JPA provider is caching (EclipseLink enables caching by default). The find may not even access the database, but get a cache hit. In this case the database transaction will not occur until flush().
# 3 - Repeatable Read is generally a very bad idea except for very specific types of applications. It is a good way to reduce the concurrency of your application to only support a single user at a time, and to deadlock your database. Everything you read will be locked, even shared or common data that every user will be reading. I would definitely recommend Read Committed instead. If you really need to lock some data, then you can use pessimistic locking, just on that data.
With Repeatable Read you are basically pessimistic locking everything you read, so yes, there is no point to also optimistic locking it, well, sort of.
You see, most applications, especially web applications, read data in one transaction. Then write the data in another transaction. Repeatable Read (and pessimistic locking) are completely useless when you do this, and the data that is being written was read in another transaction, and was not locked in between. This is why optimistic locking is important, as long as your merge the original version field, then a lock contention will still be detected across transaction boundaries.
Thank you for your answer. I am really grateful for this help.
I know that Repeatable Read is a slow datebase mode. Your advise about using Read Committed with double transaction (separate for read and write) is an interesting one. I am a new in this issue so such knowledge is for me precious. I am not exactly sure how to build such double transaction construction. Do you have any link to an example code?
The problem that I see is whether those two transactions are placed in one method of EJB or do they have separate methdos. I don't know how to pass Persistence Context from "read transaction" to "write transaction". I assume that the same Context (with the same entity objects) in is necessary to use Optimistic Lock. As far as I know, in container managed Entity Manager with JTA transaction there is only transaction scoped Persistence Context for stateles EJBs so Context can be propagated only within the scope of one transaction. So I suppose the only way to build this double transaction model is to use stateful EJBs?
Joined: Oct 01, 2007
The same persistence context is not required for optimistic locking. You only need to merge the original version field from the original transaction. JPA merge() will automatically do this.
Joined: Feb 05, 2012
Do you mean smth like this:
1. reading from datebase transaction, at the end all rceived entity objectes are detached
2. processing received date (e.g. by client)
3. passing detached entity objects to some kind of EJB where they are merged to datebase records in transaction to safe the updates. During that @Version field check is performed ?