• Post Reply Bookmark Topic Watch Topic
  • New Topic

Caching for EJBs based on transactions

 
Jorge Ribeiro
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi!

I need to implement a very specific caching mechanism. Basically I have a system with several stateless beans. These beans interact quite frequently, invoking one or more methods on each other. Each sequence of method calls involves the access to a big amount of information that I would like to put in my cache, in the form of business objects. I would like to have different caches for each transaction that is taking place. The best idea I had was to bind my cache (a map or a collection of business objects) in the jndi tree, using the transaction id as identifier. Therefore all the ejbs belonging to this transaction will be able to access/change the cache. The cache is created after the transaction starts and is removed when the transaction finishes. Do you have any better solution to this problem?

Many thanks

Paulo
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 35709
408
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paulo,
Why not just pass the data to the session beans called later on in the transaction?
 
Reid M. Pinchback
Ranch Hand
Posts: 775
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
And if you don't want to pass the data as an argument,
you could try using a BMP entity bean as the cache.
The "id" wouldn't be a transaction id, it would be
an entity id that all your other beans would use. If
they were in the same transaction, they'd get the
same bean. I wouldn't try this in a clustered
environment or with any funky performance tuning options
that caused you to have parallel copies of entity beans
floating around, but otherwise it should work fine.
 
Jorge Ribeiro
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Guys,

Thanks for your help. Let me try to present an example to clarify this problem. Let�s say that I have session bean A, B, C and D. Each one of them provides a kind of session fa�ade to a certain type of data, using DAO. So, within the same transaction, whenever retrieving data I want to keep a local copy of it (that I�m designating by cache) so I can use it whenever needing to access the same data again in the same transaction. For example I have a session bean X invoking a method in A (uses the DAO to retrieve the data from the database and to create a local cache), invoking a method in B (creates its cache as well), invoking the same method in A again (and here I want to use the cache instead of retrieving the data from the database again). Stateful beans are not a possibility.
I guess that passing the data in the method call would require me to change the API and I�m not allowed to do it. Also, I would like to keep the cache local to each session bean. Therefore I wouldn�t like to pass A�s cache back to X so I can pass it as argument in the next time I invoke a method in A.
The approach of a BMP seems to be quite interesting. So if I understand correctly, I would create a BMP for each pair transaction/session bean. I would take care of the code so my BMP would represent a cache entity. I could define a simple primary key (a string with the name of each session bean) and then I could just get that entity bean during the transaction. Even if I had two transactions going parallel, and if I tried to look for the same BMP with the same primary key in each of the transactions, each transaction would provide access to a BMP with different content, reflecting the changes that have been done during the transaction. Did I understand your approach correctly?

Thanks!
Paulo
 
Roger Chung-Wee
Ranch Hand
Posts: 1683
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In my view, you would have to have some compelling reason to go to the trouble of writing a BMP bean when all you have to do is make a few small chnages to the existing SLSBs.
 
Jorge Ribeiro
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roger,

Could you please elaborate a bit more about what do you mean with small changes to the existing stateless session beans?

Thanks!
Paulo
 
Reid M. Pinchback
Ranch Hand
Posts: 775
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, in particular, how is a change to a *stateless* bean going to result in transaction-specific caching? The only options that seem to jump out are the JNDI option Paulo was considering, passing an argument as Jeanne suggested, or using the container to provide the cache. A *stateful* bean could be changed to maintain a cache (and again, you would need to pass the reference around as an argument), but I'm durned if I see how you could achieve that safely with a stateless bean.
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 35709
408
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paulo,
I can understand not being able to change the API if others are relying on it. My next question is why you need to cache based on transaction rather than on parameters. If two different users ask for the same data, does it matter they are in different transactions? It would matter if the data is being updated, but this is something to think about.

Regardless of your approach, you need to introduce a caching layer before calling the DAO. The caching layer could use the JNDI. Or you could cache on the parameters. This would give you more flexibility if you decide to cache by data rather than transaction id. And if you do want to cache on the specific transaction, that could be the key.
 
Roger Chung-Wee
Ranch Hand
Posts: 1683
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A SLSB instance remains in existence for the duration of the transaction. If the transaction starts in X, then X can cache the data returned from A and B in its instance variables. The cached data can be passed as args in subsequent method calls in the same transaction. The method declarations will be different to the existing ones, but it's easy to change them or declare new (perhaps overloaded) methods.

As A, B, C and D seem to be invoked by another EJB (like X), then they should expose local interfaces. This means that the cached args would be passed value - very efficient. And speaking of efficiency: I don't like JNDI for this sort of solution as it's much slower.
 
Reid M. Pinchback
Ranch Hand
Posts: 775
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A SLSB instance remains in existence for the duration of the transaction.


Huh? EJB 2.0 spec section 7.8 page 87

The term �stateless� signifies that an instance has no state for a specific client.


and later...

Because all instances of a stateless session bean are equivalent, the container can choose to delegate a client-invoked method to any available instance. This means, for example, that the Container may delegate the requests from the same client within the same transaction to different instances, and that the Container may interleave requests from multiple transactions to the same instance.


So I don't see how what you said could be a solution. The spec makes it very clear it isn't a solution. It also isn't logical. A stateless bean instance basically doesn't even truly participate in a transaction so much as it controls how transactional state flows between the other components or resource adapters it interacts with. If this weren't the case, the much-vaunted high scalability of SLSB would be impossible.

Besides, even if this weren't an issue, it still wouldn't address a fundamental design challenge in the original question - multiple existing SLSBs need to share a single cache. You are still back either changing all the method signatures to pass the cache reference, or finding a way for the container to hold a cache reference (JNDI or BMP).

Also note that the idea of using BMP for a container-managed cache via fake id isn't exactly new... goes all the way back to EJB 1.x when sometimes it made more sense to use one bean instance to represent an entire table or multi-row subset instead of a single row. Not much different than using CMP in EJB 2.x with read-mostly row caches.
 
Roger Chung-Wee
Ranch Hand
Posts: 1683
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
quote:
--------------------------------------------------------------------------------
A SLSB instance remains in existence for the duration of the transaction.
--------------------------------------------------------------------------------



Huh? EJB 2.0 spec section 7.8 page 87


quote:
--------------------------------------------------------------------------------
The term �stateless� signifies that an instance has no state for a specific client.

Since when does state have anything to do with a transaction? My statement is entirely correct. The bean instance is only allocated to process the method and the container-managed transaction is scoped at method level, ie it starts when the bean's method is invoked and will end when method completes.
 
Roger Chung-Wee
Ranch Hand
Posts: 1683
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A stateless bean instance basically doesn't even truly participate in a transaction so much as it controls how transactional state flows between the other components or resource adapters it interacts with.

A session bean controls nothing, it's the container which manages the transaction. Even a BMT bean is not in charge - it just demarcates the transaction boundary.


If this weren't the case, the much-vaunted high scalability of SLSB would be impossible.

So, scalability of SLSBs has nothing to do with:
- pooling, which saves time in instantating the EJB classes
- reuse of bean instances which have been unbound from clients after each method call
- not needing to maintain state for a particular client between business method calls
 
Jorge Ribeiro
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you all for the great feedback!
 
Jorge Ribeiro
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried to implement the caching approach that keeps a cache object that is accessible to all EJBs within the same transaction. I was trying something very simple like having a HashMap (although an Hashtable might be a better approach as it is thread safe) that works as a cache container. Within this HashMap I would have a transaction key pointing to a cache object. Therefore, each EJB can access this HashMap and retrieve the cache that is associated with the transaction it�s related to.
My problem is how to get a reference to the transaction whenever using CMTs. With BMTs is quite easy as I can use the getUserTransaction from the EJBContext. With BMTs I�m looking for the TransactionManager in the JNDI tree (java/transaction/TransactionManager) and using its getTransaction method. This way I get the same Transaction object whenever using EJBs that are the in the same transaction. It seems to work. Does anyone foresee any possible problem with this approach?

Regards
Pjrm
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!