Google 网上论坛不再支持新的 Usenet 帖子或订阅项。历史内容仍可供查看。

EJB Transactions help

已查看 0 次
跳至第一个未读帖子

Linus Nikander

未读,
2002年11月22日 08:00:152002/11/22
收件人
I'm running an application where several concurrent sessionsbeans (BeanA)
access the same entitybean (BeanB).

The businessmethod orderStuff in BeanB updates, inserts and deletes post in
the DB. Amongst these is data which is loaded during the ejbLoad of BeanB.

BeanA has a method buyStuff which first accesses orderStuff in BeanB and
then some other methods in other beans.

I've specified buyStuff in BeanA to transactionally "RequiresNew" and
orderStuff in BeanB to be "Mandatory" in ejb-jar.xml . I use weblogic, so in
weblogic-ejb-jar.xml they are set to be "TRANSACTION_READ_COMMITTED".

The problem is that when I start running multiple concurrent clients I can
see that the updates i make during orderStuff when the first instance
accesses the bean aren't available when a second instance performs its
ejbLoad, the values that the first instance read are returned. I.e i get
dirty-reads.

Can anyone offer me some pointers as to where i might be going wrong ?

Is there any way to follow a transaction through all the methods it
traverses ? I.e can i monitor a transaction to make sure it's taking the
path I want it to take ?

//Linus Nikander - li...@nikander.net


Martin Backschat

未读,
2002年11月23日 05:47:062002/11/23
收件人
Hello,
maybe I didn't get the point, but the effect you have seems to be in
compliance with your configuration.

> I've specified buyStuff in BeanA to transactionally "RequiresNew" and
> orderStuff in BeanB to be "Mandatory" in ejb-jar.xml . I use weblogic, so in
> weblogic-ejb-jar.xml they are set to be "TRANSACTION_READ_COMMITTED".

TRANSACTION_READ_COMMITTED means: the transaction cannot(!) read
uncommitted data, i.e. data that is being changed by a different
transaction.

> The problem is that when I start running multiple concurrent clients I can
> see that the updates i make during orderStuff when the first instance
> accesses the bean aren't available when a second instance performs its
> ejbLoad, the values that the first instance read are returned. I.e i get
> dirty-reads.

"aren't available": ... So, I understand you do not(!) get
dirty-reads.

A Dirty-read occurs, when a transaction reads/sees(!) uncommitted
changes made by another (ongoing) transaction.

So, with TRANSACTION_READ_COMMITTED set, in the second instance you
will not see the changes made by the first instance (given of course,
that the first one is not committed yet).

Martin.

Linus Nikander

未读,
2002年11月23日 06:50:052002/11/23
收件人
Maybe my explanation wasn't all that clear ;)

"Martin Backschat" <Martin.B...@mgm-edv.de> wrote in message
news:aef160a1.02112...@posting.google.com...


> Hello,
> maybe I didn't get the point, but the effect you have seems to be in
> compliance with your configuration.
>
> > I've specified buyStuff in BeanA to transactionally "RequiresNew" and
> > orderStuff in BeanB to be "Mandatory" in ejb-jar.xml . I use weblogic,
so in
> > weblogic-ejb-jar.xml they are set to be "TRANSACTION_READ_COMMITTED".
>
> TRANSACTION_READ_COMMITTED means: the transaction cannot(!) read
> uncommitted data, i.e. data that is being changed by a different
> transaction.
>
> > The problem is that when I start running multiple concurrent clients I
can
> > see that the updates i make during orderStuff when the first instance
> > accesses the bean aren't available when a second instance performs its
> > ejbLoad, the values that the first instance read are returned. I.e i get
> > dirty-reads.
>
> "aren't available": ... So, I understand you do not(!) get
> dirty-reads.
>
> A Dirty-read occurs, when a transaction reads/sees(!) uncommitted
> changes made by another (ongoing) transaction.
>

Ok, maybe I used the term dirty-read erroneosly. What I meant was that the
second transaction is allowed to read the value which the first transaction
updates within its scope. Maybe I've misunderstood the transaction concept
within EJBs. Perhaps you could answer me this then, within the scope of a
transaction, how do i "lock for update" the tables that I will be
manipulating (this is essentially what i want/need to do) ?


> So, with TRANSACTION_READ_COMMITTED set, in the second instance you
> will not see the changes made by the first instance (given of course,
> that the first one is not committed yet).
>

Yes I can see what you mean, I suspect my approach to the whole transaction
issue might have been wrong.

> Martin.


Martin Backschat

未读,
2002年11月24日 08:15:542002/11/24
收件人
Hello Linus,

"Linus Nikander" <li...@nikander.net> wrote in message news:<3ddf6815


> Perhaps you could answer me this then, within the scope of a
> transaction, how do i "lock for update" the tables that I will be
> manipulating (this is essentially what i want/need to do) ?

Transactions in the EJB world things are a little bit confusing. To
clarify, things I summarize the essential things of
(container-managed) transactions and entity beans:

a) You configure container-managed transaction demarcation through
your transaction attribute settings in ejb-jar.xml (required,
mandatory etc.).

b) Entity beans usually run within a transaction (i.e. you cannot have
bean- or client-managed transaction demarcation, and the "Supports",
"NotSupported" and "Never" attributes should not be used - see page
352 in the EJB 2.0 spec)

c) If a client in transaction context A calls an entity object (the
logical object as seen by him), then the container delegates the call
to an entity bean instance (say, EJB-A). Until the transaction
commits, this instance is only(!) accessible wihtin the transaction
context A.
This means, that another client and/or another transaction context
calling this entity object will not(!) be delegated to EJB-A, but to
another entity bean instance EJB-B. EJB-A and EJB-B represent the same
logical entity object and both can be understood as being in-memory
copies (caches) of the same database table row data, to which the
entity object maps to by its primary key. The in-memory copies are
synchronized with the database as controlled by the container (see e)
below).

Please be aware of the essential difference of entity bean objects and
entity bean instances! Bean objects are logical, "virtual" objects as
seen by a client. (Actually, each table row "is" the raw data for an
entity bean object.)
Bean objects are identified by their primary key object value.
The container maps bean objects to bean instances internally. The
instances are actually the bean class instances. There is no 1:1
relationship between entity bean objects and instances - you can have
billions of bean objects, and even have millions of references without
much memory foot-print in the container.

Another thing to note is, that bean instances are always
single-threaded! This means, the container ensures, that only one
thread can run the instance's code at a time! (This also means, you
need/must not use the synchronized keyword in you EJB code!)

d) Statement c) only refers to accessing entity beans, i.e. the "EJB
world". Another aspect is transaction isolation, which is somehow
independent of c). Database accesses, which are enrolled in a
transaction, can be isolated with regard to other data accesses in
other transactions. You usually have four levels of transaction
isolation available, ranging from the weakest "read uncommitted" to
the strongest "serializable". How to set it is not touched by the EJB
specification; the ejb-jar.xml has no attribute for this. Thus, you
usually configure it in the container specific deployment descriptors,
as you did.

The difference of the isolation levels is classified by three effects,
"non-repeatable reads" (RR), "dirty reads" (DR) , "phantom reads"
(PR):

Isolation Level RR DR PR
Read uncommitted X X X
Read committed - X X
Repeatable read - - X
Serializable - - -

X here means, that the effect (RR, DR or PR) can occur. Search Google
for a description of RR, DR, PR - they are database concepts.

e) Aspects c) and d) come together in a situation called
Synchronization. Synchronization means, that data is either read from
the database into an entity bean instance or written from the instance
to the database. Synchronizations can be seen as a "cache flush".
After a synchronizations, the entity bean instance, e.g. EJB-A, and
the database have the same data. But the synchronized data in the
database becomes visible to others only if:

- the transaction is committed, or
- the others run in an transaction with an isolation level which
permits to see the data. For example "Read uncommitted".

Synchronization is controlled by the container, but it informs you
when it happens by calling "ejbLoad()" or "ejbStore()". (Note: in
container-managed persistence these methods usually do nothing, in
bean managed persistence they must do the load/store work to/from the
database by themselfes.)

When does Synchronization happen? This is again a little bit
complicated. The easiest answer is: the first bean access in a new
transaction reads from the database, and after the transaction is
committed the data is written to the database. This mode is called
"Commit Option C", which means "no caching outside of transactions".
These options, as isolation levels, are not part of the EJB
specification, and again cannot be configured in ejb-jar.xml but only
in the container specific deployment descriptors. Besides option C,
you usually have option A and B which allow caching of entity bean
instance data after a transaction commit. (For example Weblogic has an
option "db-is-shared" which is similar to option A when set to
"true".) An entity bean instance with cached data can be re-used by
the container for the specific entity bean object later.

The commit options concern only reading from the database. All options
will write to the database after a commit. (So usually, you cannot
have read-only data; for this Weblogic, for example, offers another
property/option "read-only".)

Another key point concerning synchronization is, that the container
controls them. This means, it can of course make additional
synchronizations during a transaction, if it likes to. For these
synchronizations, database isolations play a role, because you then
have the situation, that uncommitted data is written to the database.
But note: these "in-between" synchronizations may or may not happen,
all being subject to the container's management policy. The EJB 2.0
specification, page 169, states:

"... the container can synchronize the state of the instance with the
state of the entity in the underlying data source whenever it
determines the need to, in the process invoking the ejbLoad() and
ejbStore() methods zero or more times. A business method can be
invoked on the instance zero or more times. Invocations of the
ejbLoad() and ejbStore() methods can be arbitrarily mixed with
invocations of business methods."


Now back to your situation: As I understand, you want changes to
entity bean instance EJB-A to be seen from entity bean instance EJB-B,
even when both transactions are not yet committed (EJB-A/B represent
the same entity object, i.e. have the same primary key).

As noted in c) and d), containers hold the entity bean instances' data
in-memory, and write back to the database arbitrarily, but usually
always after a commit. Unless data is written back from EJB-A, you
have no chance to ensure that you always see the data in EJB-B, even
if you specifiy "read-uncommitted".
Actually, the whole point of transactions and the reason for entity
beans (compared to plain persistent objects) is isolation (besides the
other ACID properties). Demanding uncommitted data to be shared is
contrary to these concepts. For this, I would propose two solutions
(which will not work in a clustered scenario!):

- Use plain Java objects or Session beans to access the database with
isolation level "read uncommitted".

- Use bean-managed persistence and keep your persistent attributes in
shared data objects. Use e.g "static Hashtable objectStates;" and
collect the attributes in a data object, which is kept in the
hashtable. (Be aware, this is really a bad hack!)

- Alternatively, re-think your data access/persistency design.

Hope this helps,

Greetings, Martin.

Martin Backschat

未读,
2002年11月24日 08:21:052002/11/24
收件人
Sorry,

I just noted, a got the isolation table wrong in my previous posting.
This is correct:

The difference of the isolation levels is classified by three effects,

"dirty reads" (DR), "non-repeatable reads" (NRR), "phantom reads"
(PR):

Isolation Level DR NRR PR


Read uncommitted X X X
Read committed - X X
Repeatable read - - X
Serializable - - -


Martin.

Linus Nikander

未读,
2002年11月25日 04:19:312002/11/25
收件人
First of all, thank you very much for taking the time to write such an
extensive response.

Secondly, a few follow-up questions and some clarifications.

>
> Synchronization is controlled by the container, but it informs you
> when it happens by calling "ejbLoad()" or "ejbStore()". (Note: in
> container-managed persistence these methods usually do nothing, in
> bean managed persistence they must do the load/store work to/from the
> database by themselfes.)
>

When you say that in BMP ejbStore and ejbLoad MUST persist/load data from
the datastore, how would that apply to the follwing:

I've got a BMP entity bean. I use ejbLoad to fill the bean with its data,
BUT i use the beans business-methods to persist changes to the objects data,
ejbStore is empty. Is this an ok approach, or is it a dangerous one, and if
so why ?


> Another key point concerning synchronization is, that the container
> controls them. This means, it can of course make additional
> synchronizations during a transaction, if it likes to. For these
> synchronizations, database isolations play a role, because you then
> have the situation, that uncommitted data is written to the database.
> But note: these "in-between" synchronizations may or may not happen,
> all being subject to the container's management policy. The EJB 2.0
> specification, page 169, states:
>
> "... the container can synchronize the state of the instance with the
> state of the entity in the underlying data source whenever it
> determines the need to, in the process invoking the ejbLoad() and
> ejbStore() methods zero or more times. A business method can be
> invoked on the instance zero or more times. Invocations of the
> ejbLoad() and ejbStore() methods can be arbitrarily mixed with
> invocations of business methods."
>

Ok, but surely this can only happen between business-method calls and not
during ?


>
> Now back to your situation: As I understand, you want changes to
> entity bean instance EJB-A to be seen from entity bean instance EJB-B,
> even when both transactions are not yet committed (EJB-A/B represent
> the same entity object, i.e. have the same primary key).
>

Not quite, I don't want EJB-B to be allowed to start reading from the DB
until EJB-A commits. Let me elaborate a bit more on my scenario:

In my scenario I have 3 beans with the following methods:

SellTicket (Sessionbean)
- sellTicket
TicketPoolSF (Sessionbean)
- sellTicket
TicketPool (Entitybean)
- sellTicket

A call to SellTicket from the facade (not represented here) goes through all
3 of these methods in the above order.
A transaction is started at the top-most sessionlevel
(SellTicket.sellTicket) and both TicketPoolSF.sellTicket and
TicketPool.sellTicket are marked as mandatory so they join in that
transaction.

My problem at present is that, at the TicketPool.sellTicket level a counter
keeps track of each tickets-id.
TicketPool.sellTicket also updates this counter to reflect that a ticket has
been sold.
In order for each ticket to recieve a unique id TicketPool.sellTicket must
commit its change to this counter before any other instance is allowed to do
an ejbLoad().

As of yet I haven't been able to achieve this. I have deployed
TicketPool.sellTicket as SERIALIZABLE, but ejbLoad's are still being
performed by other instances of the ticket before the first call commits.
From your answers I can see that I'm going to have to look closer at the
Weblogic specific deployment-descriptors, maybe i'll find my answer there.
Apart from that, do you see any obvious errors in my thinking ?

Thank you again for your response,

Linus Nikander.

Linus Nikander

未读,
2002年11月25日 04:45:182002/11/25
收件人
I've just experimented a bit with the weblogic deployment descriptors. By
setting my concurrency-strategy to:

<concurrency-strategy>Exclusive</concurrency-strategy> for the particular
bean, I think i've achived what I wanted. Atleast the system now performs
without problems. My only gripe is that i still feel the strategy I
described previously SHOULD work, and probably more effiiciently at that.
Now all calls, even those that return data which never changes, have to wait
in line because the bean is "locked" and that's not quite what I was after.
I only wanted to lock the database when a specific method was called.

//Linus

backschat

未读,
2002年11月25日 05:45:442002/11/25
收件人
Linus Nikander wrote:
>>Synchronization is controlled by the container, but it informs you
>>when it happens by calling "ejbLoad()" or "ejbStore()". (Note: in
>>container-managed persistence these methods usually do nothing, in
>>bean managed persistence they must do the load/store work to/from the
>>database by themselfes.)
>
> When you say that in BMP ejbStore and ejbLoad MUST persist/load data from
> the datastore, how would that apply to the follwing:
>
> I've got a BMP entity bean. I use ejbLoad to fill the bean with its data,
> BUT i use the beans business-methods to persist changes to the objects data,
> ejbStore is empty. Is this an ok approach, or is it a dangerous one, and if
> so why ?

Your approach should work, ok, but it's really complete opposite to the
entity bean concept. This means, the container's management of entity
beans shield you from determining the synchronization by yourself. Let
the container manage it. Also, you would usually (always?) want database
access to be minimized in order to reduce communication, invocation
latency etc. For this, you would want delay writing data back until the
transaction commits - this is the way the container does it for you.
(BTW: for entity beans, only the container knows when the transaction
commits.)


>>Another key point concerning synchronization is, that the container
>>controls them. This means, it can of course make additional
>>synchronizations during a transaction, if it likes to. For these
>>synchronizations, database isolations play a role, because you then
>>have the situation, that uncommitted data is written to the database.
>>But note: these "in-between" synchronizations may or may not happen,
>>all being subject to the container's management policy. The EJB 2.0
>>specification, page 169, states:
>>
>>"... the container can synchronize the state of the instance with the
>>state of the entity in the underlying data source whenever it
>>determines the need to, in the process invoking the ejbLoad() and
>>ejbStore() methods zero or more times. A business method can be
>>invoked on the instance zero or more times. Invocations of the
>>ejbLoad() and ejbStore() methods can be arbitrarily mixed with
>>invocations of business methods."
>>
>
> Ok, but surely this can only happen between business-method calls and not
> during ?

Yes: it does not happen during a business method' execution.

The easiest way would be to handle this ID in the same way as a primary
key ID - The "Unique PK" problem is well covered and solved, see for
example "EJB Design Patterns", or the Counter EJB shipped with the Orion
Application Server, or search Google for it.

Basically, you build a seperate entity bean just for the counter
functionality.

Here's implementation proposal:
The entity beans maps to a counter table (each row represents a named
counter, e.g. "ticketCounter", "customerId", ...), or a Oracle sequence.
For performance, you might facade the counter functionality by a
stateful session bean as a buffer for a specific client, which grabs ID
blocks from the entity bean (say X). With this session bean, in X calls
it must access the entity bean only once, with the other X-1 calls
simply incrementing the ID internally.

If you need more information on this, let me know.

Martin.

--
_______________________________________________________________
"Creativity is more important than knowledge."
-- Albert Einstein
_______________________________________________________________
Martin.B...@mgm-edv.de | Tel. ++49 +89 358680-58 | Fax -88
MGM EDV-Beratung GmbH | Frankfurter Ring 105a | D-80807 München
_______________________________________________________________
Visit the Enterprise JavaBeans Special Interest Group (EJB-SIG)
http://www.ejb-sig.org

0 个新帖子