Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Weighing the options for Apache Geronimo EJB transactions, Part 1: Container-managed transactions

Learn what Geronimo and OpenEJB can do for you

Jonathan Sagorin (jonathan@javaoncall.com), Freelance software developer, Freelance
Jonathan Sagorin is a freelance developer. He has spent the majority of his 10-year career working as a consultant delivering custom Java solutions. In his spare time he attempts softball and improv (not necessarily at the same time, although his softball teammates might disagree).

Summary:  Explore both Enterprise Java™Beans (EJB) container-managed and bean-managed transactions in Apache Geronimo in this three-part series. In Part 1, find out the differences between these two types of transactions, including how container-managed transactions enable you to avoid the complexity of transaction logic and management so you can focus on the business logic of your enterprise beans. You'll also learn how to implement container-managed transactions in the Geronimo application server and how to free yourself from laborious EJB coding by using Geronimo, OpenEJB, and XDoclet.

View more content in this series

Date:  25 Jul 2006
Level:  Introductory
Also available in:   Japanese

Activity:  4901 views
Comments:  

Introduction

OpenEJB is the chosen EJB container implementation for Apache Geronimo. Although EJB 3.0 is currently available, it won't be supported in Geronimo until Version 2.0, when Geronimo will receive Java 1.5 certification.

In this three-part series, you'll learn about what Geronimo and OpenEJB can bring you and about EJB transaction concepts that you can implement now in EJB 2.1 -- and carry with you well into EJB 3.0.

The EJB framework provides the benefits of using transactions without the pain of transaction API programming. When implementing EJB transactions, you have two options:

  • Tell the EJB container to do all the hard transaction work (container-managed transactions).
  • Let your enterprise beans do some of the transaction work (bean-managed transactions).

In this installment, Part 1 of the series, you'll begin with an overview of transactions, and discuss EJB container-managed transactions as described in EJB 2.1. You'll conclude with some code snippets to show how you can implement container-managed transactions in the Geronimo application server.

In Part 2 you'll get an overview of bean-managed transactions in EJB 2.1 and see some sample code implementations.

In Part 3 you'll bring the two options together and learn about quirks and additional features related to both container-managed and bean-managed transactions.

Transactions -- an overview

So what is a transaction? Why are they so important? Consider this very simplistic case of a banking transaction: You transfer $100 from your checking account to your savings account. On further investigation, this might involve two smaller operations:

  • Your bank subtracts $100 from your checking account.
  • Your bank adds $100 to your savings account.

If the bank reduced your checking balance by $100 but failed to increase your savings balance by $100, you might be a little upset. Personally, I'd like to think of the two operations as one operation. So if $100 is never added to your savings account, $100 should never be subtracted from your checking account!

Similarly, there are business cases in applications that take on this all-or-nothing approach. Some large operations consist of one or more smaller steps. For the operation to complete, all steps within the operations must complete, or none at all. This behavior is known as atomicity.

Atomicity is one of four characteristics (or properties) that transactions must guarantee. The other three properties are:

  • Consistency
  • Isolation
  • Durability

Together these four properties are called the ACID properties.

ACID properties

Transactions exhibit these well-known ACID properties:

  • Transactions are atomic. All operations are considered a single unit of work. This is an all-or-nothing approach, as discussed previously.
  • Transactions are consistent. After a transaction executes, it must leave the system in a consistent (or legal) state. What defines a legal state is up to the system. To follow the earlier example, after any withdrawals, your bank dictates you leave your checking account with a positive balance.
  • Transactions are isolated. Each transaction behaves in isolation of other transactions executing on the same resource. This is achieved through lock synchronization of data.
  • Transactions are durable. Updates to resources must survive system failures, such as hardware or network failures. In distributed systems, recovery processes are needed when networks fail or databases crash.

Transaction models

There are two popular transaction models: flat transactions and nested transactions. EJBs support the flat transaction model.

Flat transactions are a series of operations performed as a single unit of work. There can be only two results from this unit of work: either success or failure. If all steps in a transaction complete successfully, the transaction is committed and all persistent data changes performed by the operation become permanent. If any steps within the transaction fail, the transaction rolls back and reverses any data effects caused by the steps in the transaction.

Nested transactions allow for transactions (or units of work) to be nested in other transactions. Transactions nested in other transactions allow rollbacks to occur without affecting their parent transactions. Failed nested transactions can continue to retry. If failure continues, the parent transactions might be rolled back.


EJB transactions

EJBs are a framework for component development. You develop EJBs that run within an EJB container. Among other things, the EJB container provides the benefit of transactions. The OpenEJB is the EJB container used by Geronimo to provide transaction management.

The EJB architecture supports distributed transactions. Some sample scenarios of when distributed transactions would be needed include:

  • An application in a single transaction to update multiple databases.
  • An application in a single transaction to send or receive messages from a Java Message Service (JMS) destination and update one or more databases.
  • An application in a single transaction to update multiple databases via multiple EJB servers.
  • A Java client to explicitly demarcate transaction boundaries before updating multiple databases on multiple EJB servers.

Transaction boundaries

When implementing EJB transactions, you're demarcating transaction boundaries: who begins the transaction, who commits or aborts the transaction, and when you should use the transactions. It's up to the EJB container and server provider to provide transaction management and a low-level transaction communication protocol.

There are two demarcation options:

  • The declarative option, in which you can delegate transaction implementation to the EJB container. (This option is the focus of the remainder of this article.)
  • The programmatic option, in which the enterprise beans provide the commit or abort information themselves in their code. (This option will be covered in the second part of this series.)

With declarative transaction demarcation, the EJB container applies transaction boundaries on an enterprise bean's methods based on instructions declared by the application developer in the EJB deployment descriptor. This is called a container-managed transaction.

When implementing programmatic demarcation of transactions, the application developer is responsible for programming transaction logic and boundaries into enterprise bean code. This is called a bean-managed transaction.

Which transaction should I use?

Container-managed transactions are simpler and require no implementation of transaction logic in your code. Either your enterprise bean method must run within a transaction or not at all. Also, the Java client invoking the bean cannot abuse your enterprise bean, because the transaction will always start up and end.

If you want full control of transaction boundaries, use bean-managed transactions. This method allows you to directly control where commit or rollback logic will occur in your code.

Session beans and message-driven beans (MDBs) can use bean-managed transactions or container-managed transactions, while an entity bean must always use container-managed transactions. It's illegal for an entity bean to use bean-managed persistence.


Container-managed transactions

Transaction demarcation boundaries are provided through instructions or transactional attributes. These attributes describe how enterprise beans participate in transactions. You can specify different transaction attributes on each bean regardless of the number of beans. You can specify attributes for the entire bean or for individual methods of that bean. Attributes for methods take precedence over the bean.


Transaction attributes for session and entity beans

Possible attribute values for session and entity beans are:

  • Required -- Bean must always run within a transaction. If the client has started a transaction, the bean joins the transaction. If the client has not started one, the EJB container starts a new transaction. Use this attribute when you want your bean to always run within a transaction.
  • RequiresNew -- Bean always starts a new transaction. If the client has started a transaction, this transaction is suspended until the new transaction commits or aborts. After the new transaction completes, the existing transaction resumes. Use this attribute when you want your bean to run as a single unit of work and exhibit all of the ACID properties.
  • Supports -- If the client has started a transaction, the bean joins the transaction. However, the EJB container doesn't start a new transaction if one doesn't exist. Use this attribute for nonmission-critical operations on your enterprise bean.
  • Mandatory -- The client must start a transaction when the bean is invoked. A new transaction can't be created. If there is no transaction already started when the bean is invoked, an exception is thrown. Use this attribute when a bean is part of a larger system. Usually a third party might be responsible for starting the transaction. This is a safe option to use because it guarantees the bean will be part of a transaction.
  • NotSupported -- Bean cannot be involved in a transaction. If the client has started a transaction, the existing transaction is suspended until the bean's method has completed. After completion, the existing transaction is resumed. If the client hasn't started the transaction, a new transaction isn't created. Use this attribute when you don't require your bean to exhibit any of the ACID properties, such as for nonsystem-critical operations like reporting.
  • Never -- If the client has started a transaction, the bean throws an exception. You might never want your bean to participate in a transaction. Use this attribute in those cases.

Transaction attributes for message-driven beans

There are only two transaction attributes used with message-driven bean message listener methods:

  • NotSupported -- Bean cannot be involved in a transaction. If the client has started a transaction, the existing transaction is suspended until the bean's method has completed. After completion, the existing transaction is resumed. If the client hasn't started a transaction, a new transaction isn't created.
  • Required -- Bean must always run within a transaction. If the client has started a transaction, the bean joins the transaction. If the client hasn't started one, the EJB container starts a new transaction.

After you've decided on the correct transaction attributes for your enterprise bean methods, you can configure your EJB deployment descriptor.


Configure the EJB deployment descriptor

For each enterprise bean, you configure the following two pieces of a transaction in your deployment descriptor:

  • Specify whether your bean should use container-managed or bean-managed transactions using the <transaction-type> element in your EJB deployment descriptor. Possible values are container or bean. Since entity beans must use container-managed transactions, this is required only for session beans and message-driven beans.
  • For container-managed transactions, you optionally specify the transaction attributes for your enterprise bean's methods. This is specified in the <container-transaction> portion of the EJB deployment descriptor. The general form for each method is shown in Listing 1.

Listing 1. General form for each method
<method>
            <ejb-name>EJBNAME</ejb-name>
            <method-name>METHODNAME</method-name>
            <trans-attribute>TRANSATTRIBUTE</trans-attribute>
</method>

Possible values for TRANSATTRIBUTE are:

  • NotSupported
  • Required
  • Supports
  • RequiresNew
  • Mandatory
  • Never

It's also possible to specify transaction attributes for all methods for an enterprise bean. Use * for the <method-name> attribute.

Listing 2 shows a sample of how transaction attributes are specified for a container-managed enterprise bean. The ClaimRecord enterprise bean assigns all methods the Required attribute, with the exception of the updateClaimNumber method, which has been assigned the Mandatory attribute. The Coverage bean assigns all methods the RequiresNew attribute.


Listing 2. Transaction attributes in the ejb deployment descriptor file
<ejb-jar>
...
<assembly-descriptor>
...
<container-transaction>
      <method>
            <ejb-name>ClaimRecord</ejb-name>
            <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
      <method>
             <ejb-name>ClaimRecord</ejb-name>
      <method-name>updateClaimNumber</methodname>
      </method>
     <trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
	<method>
		<ejb-name>Coverage</ejb-name>
		<method-name>*</method-name>
	</method>
	<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...
</assembly-descriptor>
...
</ejb-jar>


Geronimo configuration

Now that you understand the general form for specifying transaction attributes in the EJB deployment descriptor, you can look at how to do this in Geronimo using OpenEJB. When developing EJBs in Geronimo, you can save time by using XDoclet to generate a large portion of the tedious EJB programming artifacts that are required. As part of these artifacts, XDoclet generates the EJB deployment descriptor.

As part of the normal development process, specify JavaDoc-style markup tags in your enterprise beans. By declaring markup tags in your enterprise beans, XDoclet generates ejbjar.xml. This includes any transaction attribute defined. You don't directly edit the deployment descriptor yourself (ejb-jar.xml).

Transaction attributes are specified in XDoclet using the @ejb.transaction markup. When you want to use it, you declare it above the method of the enterprise bean.

Sample XDoclet configuration and ejbjar.xml generation

The code snippets below show a simplistic sample session bean and entity bean and the resulting ejbjar.xml file generated by XDoclet. First, Listing 3 shows a stateless session bean called SampleSession. Pay attention only to the portions relevant to transactions (shown in bold).


Listing 3. Session bean
package org.my.package.ejb;
/**
 * Sample session bean. 
 * Declare all my XDoclet tags here
 * ...
 * ... 
 * @ejb.bean name="SampleSession"
 *   type="Stateless"
 *   local-jndi-name="java:comp/env/ejb/SampleSessionLocal"
 *   jndi-name="org.my.package.ejb/SampleSessionLocal/Home"
 *   view-type="both"
 *
 * @ejb.permission unchecked="true"
 *
 * @ejb.interface generate="local,remote"
 *   remote-class="org.my.package.ejb.SampleSession"
 *   local-class=" org.my.package.ejb. SampleSession Local"
 * @ejb.home generate="local, remote"
 *  	remote-class="org.my.package.ejb.SampleSession Home"
 *    local-class="org.my.package.SampleSession LocalHome"
 * @ejb.util generate="physical"
 * ...
 * ...
 */
public abstract class SampleSessionBean implements javax.ejb.SessionBean {

   /**
    * Perform a business operation. Add something
    * @param someParam the value
    * @ejb.interface-method view-type="both"
    * @ejb.transaction      type="Required"
    */
   public void doSomething(java.lang.String someParam)) {
  	...
   }

   /*
    * Perform another business operation. Add something
    * @param someParam the value
    * @ejb.interface-method view-type="both"
    * @ejb.transaction      type="RequiresNew"
    */
   public void doSomethingElse(java.lang.String someParam)) {
  	...
   }
   /**
    * @ejb.create-method
    * @ejb.transaction type="Required"
    */
   public void ejbCreate ()
           throws javax.ejb.CreateException
   {
   }

   public void ejbPostCreate ()
           throws javax.ejb.CreateException
   {
   }

   protected javax.ejb.SessionContext _ctx = null;

   public void setSessionContext( javax.ejb.SessionContext 	ctx )
   {
        _ctx = ctx;
   }

   protected javax.ejb.SessionContext getSessionContext()
   {
        return _ctx;
   }
}

The same markup @ejb.transaction is used to specify the transaction attributes for this entity bean. Listing 4 shows how transaction attributes are specified for an entity bean. Again, pay attention to the markup in bold only.


Listing 4. Entity bean
package org.my.package.ejb;

/**
 *
 * @ejb.bean 
 *    type="CMP" 
 *    cmp-version="2.x"
 *    name="ClaimEntry" 
 *    local-jndi-name="org.my.package.ejb/ClaimLocalHome"
 *    view-type="local"
 *    primkey-field="name"
 *    
 *
 * @xx-ejb.data-object
 *    container="true"
 *    setdata="true"
 *    generate="true"
 *    
 * @ejb.value-object
 *
 * @ejb.transaction type="Required"
 * @ejb.permission unchecked="true"
 * @struts.form include-all="true"
 *
 * @web.ejb-local-ref
 *    name="ejb/ClaimLocal"
 *    type="Entity"
 *    home="org.my.package.ejb.ClaimLocalHome"
 *    local="org.my.package.ejb.ClaimLocal"
 *    link="PhoneBookEntry"
 *
 * @ejb.persistence table-name="Claim"
 *
 */
public abstract class ClaimBean 
       implements javax.ejb.EntityBean
{

 * ... EJB entity bean implementation here   
}

When XDoclet is executed during the build process, ejb-jar.xml is generated. Listing 5 shows the transaction-relevant parts of the file. Notice the <transaction-type> and <trans-attribute> elements shown in bold.


Listing 5. Generated ejb-jar.xml snippet
...
<ejb-jar >

   <description><![CDATA[No Description.]]></description>
   <display-name>Generated by XDoclet</display-name>

   <enterprise-beans>

      <!-- Session Beans -->
      <session >
         <description><![CDATA[Sample session
 bean.]]></description>

         <ejb-name>SampleSession</ejb-name>

         <home>org.my.package.ejb.SampleSessionHome</home>
         <remote>org.my.package.ejb.SampleSession</remote>
<local-home>org.my.package.ejb.SampleSessionLocalHome
</local-home>
         <local>org.my.package.ejb.SampleSessionLocal</local>
        
 <ejb-class>org.my.package.ejb.SampleSessionSessionSession
</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Container</transaction-type>
      </session>
...

      <!-- Entity Beans -->
      <entity >
         <description><![CDATA[]]></description>
         <ejb-name>Claim</ejb-name>
         <local-home>
 org.my.package.ejb.ClaimLocalHome</local-home>
         <local>org.my.package.ejb.ClaimLocal</local>
         <ejb-class>org.my.package.ejb.ClaimCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>java.lang.String</prim-key-class>
         <reentrant>False</reentrant>
         <cmp-version>2.x</cmp-version>
         <abstract-schema-name>Claim</abstract-schema-name>
...
      </entity>
...
   <container-transaction >
      <method >
         <ejb-name>Claim</ejb-name>
          <method-name>*</method-name>
       </method>
       <trans-attribute>Required</trans-attribute>
    </container-transaction>
   <container-transaction >
      <method >
         <ejb-name>SampleSession</ejb-name>
         <method-intf>Local</method-intf>
         <method-name>doSomething</method-name>
         <method-params>
            <method-param>java.lang.String</method-param>
         </method-params>
      </method>
      <trans-attribute>RequiresNew</trans-attribute>
   </container-transaction>
   <container-transaction >
      <method >
         <ejb-name>SampleSession</ejb-name>
         <method-intf>Remote</method-intf>
         <method-name>doSomething</method-name>
         <method-params>
            <method-param>java.lang.String</method-param>
         </method-params>
      </method>
      <trans-attribute>RequiresNew</trans-attribute>
   </container-transaction>
   <container-transaction >
      <method >
         <ejb-name>SampleSession</ejb-name>
         <method-intf>Local</method-intf>
         <method-name>doSomethingElse</method-name>
         <method-params>
            <method-param>java.lang.String</method-param>
         </method-params>
      </method>
      <trans-attribute>Required</trans-attribute>
   </container-transaction>
   <container-transaction >
      <method >
         <ejb-name>SampleSession</ejb-name>
         <method-intf>Remote</method-intf>
         <method-name>doSomethingElse</method-name>
         <method-params>
            <method-param>java.lang.String</method-param>
         </method-params>
      </method>
      <trans-attribute>Required</trans-attribute>
   </container-transaction>
...

</ejb-jar>

Transaction synchronization

Container-managed transactions allow the EJB container to specify transaction boundaries, so the work is simplified for you. However, when transactions are aborted, you might need to perform some recovery of your bean state. For stateless session beans, a simple exception can be thrown. Stateful session beans represent conversational states (or business processes), which might span several bean method calls.

If you require your stateful session bean to be informed of transaction boundary status events, code your enterprise bean to implement the optional javax.ejb.SessionSynchronization interface. You'll have to implement the following methods defined on the interface:

  • afterBegin() -- The session bean is notified after a new transaction has begun but before the business method has been invoked. The bean instance can do any database reads it might require before the transaction is committed. This is useful when caching data needed by the transaction.
  • beforeCompletion() -- The session bean is notified after the business method is completed but before the transaction is committed. If there's any cached data, it can be updated to the database. The bean can also perform a manual rollback of the transaction by invoking setRollBackOnly() on its session context.
  • afterCompletion(boolean committed) -- The session bean is notified after a transaction is committed. The Boolean committed indicates whether a commit or an abort occurred. If true, the transaction was successful. If false, the transaction was aborted. At this point, the conversational state/instance variable for the bean can be restored/reset.

Methods to avoid

Since the EJB container is responsible for controlling transaction boundaries, you should not invoke any method that might interfere with the container's demarcation of these boundaries. If you're implementing container-managed transactions, make sure your enterprise bean methods don't invoke the following:

  • The commit, setAutoCommit, and rollback methods of java.sql.Connection
  • The getUserTransaction method of javax.ejb.EJBContext
  • Any method of javax.transaction.UserTransaction

Rolling back

In some cases you might want to explicitly abort a transaction. There are two ways to roll back a container-managed transaction:

  • Let the container automatically roll back the transaction. This occurs if a runtime exception is thrown by any of your enterprise bean's methods.
  • Invoke the setRollBackOnly() method of the EJBContext interface. This allows you to control when rollback occurs. Perhaps if some validation check fails or if you have a data integrity problem, you might want to roll back the entire transaction and throw an application exception. An application exception doesn't automatically cause the container to roll back an exception.

Summary

In this first part of this series, you were briefed on transactions and introduced to options for EJB transactions. You have seen how container-managed transactions let you focus on the business logic of your enterprise beans, leaving the complexity of transaction logic and management to the EJB container.

With container-managed transactions, you only need to be concerned with how enterprise beans participate in transactions, and you can accomplish this through simple configuration in the EJB deployment descriptor. The Geronimo application server, OpenEJB, and XDoclet help you simplify how to specify container-managed settings and free you from the tedious task of coding the EJB artifacts yourself.

Stay tuned for Part 2 of this series, where you'll learn about bean-managed transactions, and for Part 3, where you'll bring both options together.


Resources

Learn

Get products and technologies

Discuss

About the author

Jonathan Sagorin is a freelance developer. He has spent the majority of his 10-year career working as a consultant delivering custom Java solutions. In his spare time he attempts softball and improv (not necessarily at the same time, although his softball teammates might disagree).

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Java technology, WebSphere
ArticleID=148416
ArticleTitle=Weighing the options for Apache Geronimo EJB transactions, Part 1: Container-managed transactions
publish-date=07252006
author1-email=jonathan@javaoncall.com
author1-email-cc=ruterbo@us.ibm.com