Record (Row) locking auto-magically with CMP?

T

Tom Purvis

I'm writing a J2EE app that uses CMP to manage all entity beans'
persistance. I'd like to use a pessimistic concurrency approach,
where a user will be blocked from opening an entity (record) if
some other user already has it open. When my code asks the container
to open an entity that another client thread has open, I'd like to
have the container throw an exception.

I'm using a Stateless Session bean to operate on the Entity Bean.
A Servlet instantiates the Session bean, then provides the ID of
the record it wants to open. The session bean calls findByPrimaryKey
using the ID.

Once I've used the bean to populate a Form on the client's returned
page, I put a reference to the bean's Local Interface into the
HttpSession obj. This keeps a reference to it in the client thread,
but the container may passivate it. I had hoped that keeping this
reference would effectively lock the row so that other attempts to
pull up the entity would fail. If the session times out, the bean
would be closed and freed.

So I opened a record for editing, then logged a second user on and
had that user attempt to open the same record. Both users could open
the same record, and stomp on each others' changes.

I'm new enough to EJBs that I wasn't sure if it should be working this
way. Then I found a key in standardjbosscmp-jdbc.xml and standardjaws.xml
called <row-locking>. I set it from False to True and bounced JBoss.
I hoped that would change make my approach work, but no dice. I still
have very optimistic concurrency.

I am using JBoss to develop, and will most certainly move the app
to production on JBoss. My development environment is JBoss 3.2.1
with MySQL 4.0.13 as the Data Store. When I go to production,
the datastore will probably be MS SQL Server (horrors!). Not my
favorite DBMS, but it is more likely to support advanced features
like row-level locking. MySQL is supposed to support RLL as of
version 4.0x, but I'm wondering if it isn't just a problem with
my choice of datasource.

So the questions:

1. Am I even on the right track expecting this to work? Is there a
better J2EE approach to avoiding this concurrency problem? I can code
a locking scheme, but naturally I'd rather have the container do my
locking for me if it's at all possible.

2. Is it possible that this is failing because I'm using MySQL as
my datasource? I'm using version 4.0.13 of MySQL with InnoDB, and
I'm using InnoDB AFAIK. In other words, if everything else was right,
would this approach work?

TIA for any advice or info.
 
D

Doug Pardee

1. Am I even on the right track expecting this to work? Is there a
better J2EE approach to avoiding this concurrency problem? I can code
a locking scheme, but naturally I'd rather have the container do my
locking for me if it's at all possible.

No, I'm afraid that you are not on the right track.

A useful generalization: an entity bean contains valid row data only
during the time that it is involved in a transaction.

Prior to its being involved in a transaction, it either contains no
row data, old and possibly obsolete row data, erroneous row data from
a failed transaction, or possibly row data for an entirely different
row.

When the first call is made to the entity bean within a transaction,
the container will first call the entity bean's ejbLoad() method to
read in the row data from the database.

If/when the transaction commits, the container will call the entity
bean's ejbStore() method to write the row data to the database. After
the transaction commits (or rolls back), the container considers the
entity bean's internal state to be worthless.

Supposedly, if you select Commit Option A, the container can keep the
row locked and thereby assume that the entity bean's internal state is
still valid after the end of the transaction. This is covered in
Section 9.1.11 of the EJB 1.1 Specification, Section 10.5.10 of the
EJB 2.0 Specification (CMP), and Section 12.1.10 of the EJB 2.0
Specification (BMP):
"The container acquires exclusive access to the entity object's
state in the database. The container activates a single instance
and serializes the access from multiple transactions to this
instance. The commit-time option A in Subsection 9.5.4 [EJB 1.1]
10.5.9 [EJB 2.0 CMP] 12.4.4 [EJB 2.0 BMP] applies to this
type of container."
Although this certainly sounds like what you are looking for, the
implementations that I have seen of Commit Option A require that the
deployment descriptor assure the container that the database is simply
not shared with any other applications. This leads me to believe that
"acquiring exclusive access" is *not* being done by row-locking, but
rather by being assured that the container has exclusive access to the
whole database at all times. I'm not a JBoss person, but my reading of
Fleury's Blue paper suggests to me that Fleury tends to think in terms
of a dedicated database.

Besides... you probably don't *really* want to lock up database rows
for any length of time. I don't know about MySQL, but when you get to
MS SQLServer you run the risk of triggering "lock escalation", where
the database finds that it can't keep up with all of the individual
row-level locks and just locks the whole danged table.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top