Implicit Transaction Management


Implicit transaction management represents a very simple introduction to transactions. The developer of the application logic must be an expert in a particular application domain. Normally, he or she will not be an expert in transactions. Therefore, the complexity of transaction management and control should remain largely hidden.

Implicit transaction management is based on the separation of the actual application logic from the logic of the transaction management. The bean provider develops the application logic, while in creating the complete application, the application assembler defines the transaction management using transaction attributes.

With implicit transactions the EJB container takes over the transaction management. For every call to a bean method the EJB container ensures that a suitable transaction exists. In the deployment descriptor, a determination is made for each method as to whether a transaction is needed, and if so, of what type. If a call occurs with an unsuitable or missing transaction, the EJB container attempts to generate a suitable transaction. If this is impossible, this operation causes an error, and the EJB container triggers an exception.

Figure 7-5 presents an example of an implicit transaction. The client calls a bean method. Here the client assumes no responsibility for the transaction management. However, the execution of the called method requires a transaction. Since the EJB container has been notified of this with the deployment descriptor of the bean, the EJB container can launch the necessary transaction. After the successful execution of the method, the EJB container ends the transaction with a commit. In case of error, if an exception has occurred, then the EJB container terminates the transaction with a rollback.

click to expand
Figure 7-5: An example of data flow in an implicit transaction.

The called method can itself call additional methods. The transaction context is thereby further transmitted. The EJB container checks whether a suitable transaction exists for the called method. In the example the existing transaction can be used again.

A called method can also use a defined service of the EJB architecture. Examples are access to a database and to a messaging service. An entity bean may use the database implicitly through the storage of persistent data. These transactional systems manage the data affected by the transaction. For proper management of these data they use the transmitted transaction context and communicate directly with the transaction service over JTS.

Certain properties result from the particular objectives of implicit transactions, namely, the reduction of complexity for the application developer. The following list should provide an overview. The individual points are gone into in greater detail in the following sections with the help of concrete programming examples:

  • Implicit transactions are declarative transactions. The transactional behavior is declared in the deployment descriptor.

  • The transactional behavior of a bean is defined in the deployment descriptor. A transaction attribute can be given for each method (see the subsection on transaction attributes later in this chapter).

  • An implicit transaction cannot extend over more than one client function call. As a rule, though, this suffices if on the server side the requisite interfaces are available.

  • If an error situation arises in a bean, then the bean can compel the running transaction to be rolled back upon completion. However, the bean has no way to end the running transaction and in general, no mechanism to start a new one.

  • A session bean can have itself informed by the EJB container about the state of a transaction and thereby has the ability of ensuring additional consistency conditions.

These particular properties of implicit transactions lead naturally to certain limitations. The EJB concept is nevertheless considerably shaped by the division of responsibility among the various players. Implicit transactions are an important step toward this goal, and were therefore deliberately chosen as a fundamental component of the EJB concept.

Whoever wishes to profit from the advantages of the EJB architecture should intensively promote the use of implicit transactions. The use of explicit transaction management, to be introduced in the next section, always indicates the partial surrender of the division of responsibility. The logic of transaction management is defined during the implementation and is not apparent in the deployment descriptor. The decision to use explicit transaction management is a far-reaching design decision that should remain the exception rather than the rule.

The following comparison of the advantages and limitations of implicit transactions should facilitate the choice of the correct mode for a particular application.

Advantages

  • Quality and maintenance: The developer of the application logic is freed from the complexities of transaction management. This has a positive influence on both quality and maintainability. Each contributor to the development process does what he or she does best, and the complexity is reduced for each.

  • Reusability: The reusability of a bean is much enhanced, since it is not until the time of deployment that the transactional behavior of this component must be determined.

Limitations

  • Limited flexibility: The possibilities for development are limited purely on the side of the client. With declarative transactions the client cannot combine beans on the server to create new transactions. Furthermore, there are applications in which the application logic of the bean requires a particular transaction management, and thus this separation is disadvantageous. Due to these limitations the EJB concept provides for explicit transaction management.

  • Simple tasks become complex: The division of responsibilities and the resulting action model make the development of simple prototypes unnecessarily complicated. The concept pays off only with larger projects.

Example Producer

The example Producer should provide a gentle introduction to programming transactions. This is a simple simulation of a supply chain. The session bean Producer is a producer that creates a product out of certain raw materials. The entity bean Stock simulates the storage of the raw materials and the end product.

Producer is a classic example of a transaction. The product can be produced only if the necessary raw materials are present and there is storage available for the end product. As long as there is only one client, this situation is trivial. Using transactions, the situation is also trivial for parallel access by several clients.

An important method for working with transactions is setSessionContext for session beans, setMessageDrivenContext for message-driven beans, and setEntityContext for entity beans. Here the bean is notified of its context, which contains information about the user and the transaction. Moreover, the context provides the bean limited influence over the transaction. The method setRollbackOnly forces a rollback. With getRollbackOnly it is possible to query as to whether the transaction can still be successfully completed.

We shall first consider the entity bean Stock. The constructor requires three parameters: a unique ID for each stock bean, the maximum capacity, and the current amount. Furthermore, the home interface (see Listing 7-1) defines the requisite findByPrimaryKey method.

Listing 7-1: StockHome: the home interface of the entity bean Stock.

start example
 package ejb.supplychain.stock; import javax.ejb.CreateException; import javax.ejb.EJBHome; import javax.ejb.FinderException; import java.rmi.RemoteException; public interface StockHome extends EJBHome {     public Stock create(String stockId,                         int maxVolume,                         int aktVolume)         throws CreateException,                RemoteException;     public Stock findByPrimaryKey(String primaryKey)         throws FinderException,                RemoteException; } 
end example

In the remote interface (see Listing 7-2) we see the functionality of the Stock bean. The method get allows material to be withdrawn from storage, and with the method put, material is stored. Both methods trigger a ProcessingErrorException if the action is impossible. The method getVolume allows one to query the current amount in storage.

Listing 7-2: Stock: the remote interface of the entity bean Stock.

start example
 package ejb.supplychain.stock; import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface Stock extends EJBObject {     public void get(int amount)         throws ProcessingErrorException, RemoteException;     public void put(int amount)         throws ProcessingErrorException, RemoteException;     public int getVolume()         throws RemoteException; } 
end example

Once the functionality has been defined, we can determine the database design in Listing 7-3.

Listing 7-3: Database design for the entity bean Stock.

start example
 CREATE TABLE STOCK   (STOCKID VARCHAR(10) NOT NULL,    VOLUME INT,    MAXVOLUME INT) ALTER TABLE STOCK ADD   CONSTRAINT PRIMKEY   PRIMARY KEY (STOCKID) 
end example

We shall use the method get as a model for the implementation of the methods (see Listing 7-4). The method assumes that it will be executed in a transaction. First, the new count of what is in storage is computed, and then a check is made as to whether the amount is valid.

Listing 7-4: StockBean.get: this method reduces the amount in storage.

start example
 ...     public void get(int amount)         throws ProcessingErrorException     {         int newStockVolume = this.getStockVolume() - amount;         if(newStockVolume >= 0) {             this.setStockVolume(newStockVolume);         } else {             throw new ProcessingErrorException("volume too small");         }     } ... 
end example

If it is a valid amount, the persistent variable stockVolume is updated. The EJB container ensures that this change is transaction-securely written to the database.

An invalid amount means an error for the method. The reaction to an error in a transaction can take one of two forms:

  • Exception: The method triggers an exception and thus leaves the decision as to whether the transaction should be rolled back to the caller. If in a declarative transaction the exception is not caught by any bean in the calling hierarchy, the EJB container aborts the transaction and issues a rollback.

  • setRollbackOnly: A call to this method of the bean context causes the transaction to be aborted with a rollback. This makes sense if data have already been changed in the database and thus an invalid intermediate state is present. The rollback is not immediately executed, but only after the transaction is ended. The decision for a rollback is final, and thus there is no sense in taking measures to recreate a valid state within this transaction. An exception can be triggered to shorten the further processing of the transaction.

In the Stock bean, errors are determined by checking the preconditions, before persistent data are changed. Therefore, a setRollbackOnly is pointless. An exception is triggered, and the caller can react to it.

The crucial question is now how one ensures that the methods are always executed in a transaction. For this one can specify in the deployment descriptor attributes for transactions for each method. The value Required always deals with a transaction. Either the running transaction is used, or a new transaction is launched by the EJB container. In the following subsection we provide a thorough description of the permitted values. Listing 7-5 shows the relevant portions of the deployment descriptor for the stock bean.

Listing 7-5: Portion of the deployment descriptor of the entity bean Stock.

start example
 <?xml version="1.0" ?> <ejb-jar version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">   ...   <enterprise-beans>     <entity>       <ejb-name>Stock</ejb-name>       <home>ejb.supplychain.stock.StockHome</home>       <remote>ejb.supplychain.stock.Stock</remote>       <ejb-class>ejb.supplychain.stock.StockBean</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>StockBean</abstract-schema-name>       <cmp-field>         <field-name>stockId</field-name>       </cmp-field>       <cmp-field>         <field-name>stockVolume</field-name>       </cmp-field>       <cmp-field>         <field-name>maxStockVolume</field-name>       </cmp-field>       <primkey-field>stockId</primkey-field>     </entity>     ...   </enterprise-beans>   <assembly-descriptor>     <container-transaction>       <method>         <ejb-name>Stock</ejb-name>         <method-name>get</method-name>       </method>       <method>         <ejb-name>Stock</ejb-name>         <method-name>put</method-name>       </method>       ...       <trans-attribute>Required</trans-attribute>     </container-transaction>   </assembly-descriptor> </ejb-jar> 
end example

Instances of the stock bean are used by the producer bean, which is a stateful session bean. It takes a unit from storage S1 and two units from S2 and uses them to generate a product, which it places in storage T1.

The home interface of the producer bean is shown in Listing 7-6; it offers only the standard create method.

Listing 7-6: ProducerHome: home interface of the session bean Producer.

start example
 package ejb.supplychain.producer; import javax.ejb.CreateException; import javax.ejb.EJBHome; import java.rmi.RemoteException; public interface ProducerHome extends EJBHome {     public Producer create()         throws CreateException, RemoteException; } 
end example

The remote interface in Listing 7-7 defines only the method produce, which implements the production method described previously.

Listing 7-7: Producer: remote interface of the session bean Producer.

start example
 package ejb.supplychain.producer; import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface Producer extends EJBObject {     public int produce(int amount)         throws UnappropriateStockException, RemoteException; } 
end example

The implementation of the bean itself consists mostly of familiar elements. Listing 7-8 shows the framework for the class definition.

Listing 7-8: ProducerBean: class definition.

start example
 package ejb.supplychain.producer; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.FinderException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.ejb.SessionSynchronization; import javax.naming.NamingException; import ejb.supplychain.stock.ProcessingErrorException; import ejb.supplychain.stock.Stock; import ejb.supplychain.stock.StockHome; import ejb.util.Lookup; public class ProducerBean implements SessionBean, SessionSynchronization {     public static final String STOCK_HOME =         "java:comp/env/ejb/Stock";     public static final String SOURCE_ID1 =         "java:comp/env/idSource1";     public static final String SOURCE_ID2 =         "java:comp/env/idSource2";     public static final String TARGET_ID =         "java:comp/env/idTarget";     private Stock source1;     private Stock source2;     private Stock target;     private SessionContext sessionCtxt = null;     ... } 
end example

For the initialization an internal method, openResources(), is called in the ejbCreate method and in the ejbActivate method (see Listing 7-9). This ensures that all necessary resources are available. To this end it searches all stock beans in use and stores a reference in the variables source1 and source2 for the raw materials stores and in the variable target for the end product store. The stock bean that was used will later be marked as a reference in the deployment descriptor. The IDs of the stock beans are environment variables of the bean and are read using JNDI. These, too, will later be taken up in the deployment descriptor. Access to JNDI is encapsulated in the auxiliary class ejb.util.Lookup. The source code of this auxiliary class together with all the source code for this chapter is available with the code source for this book.

Listing 7-9: Initialization of ProducerBean.

start example
 ...     public void ejbCreate()         throws CreateException     {         try {             this.openResources();         } catch(Exception ex) {             throw new CreateException(ex.getMessage());         }     }     public void ejbActivate() {         try {             this.openResources();         } catch(Exception ex) {             throw new EJBException(ex.getMessage());         }     }     private void openResources()         throws FinderException, NamingException     {         try {             // get stock IDs             String idSource1 =                 (String)Lookup.narrow(SOURCE_ID1, String.class);             String idSource2 =                 (String)Lookup.narrow(SOURCE_ID2, String.class);             String idTarget =                 (String)Lookup.narrow(TARGET_ID, String.class);             // get home             StockHome stockHome = (StockHome)                 Lookup.narrow(STOCK_HOME, StockHome.class);             // get stocks             this.source1 = stockHome.findByPrimaryKey(idSource1);             this.source2 = stockHome.findByPrimaryKey(idSource2);             this.target = stockHome.findByPrimaryKey(idTarget);         } catch(java.rmi.RemoteException e) {             throw new EJBException(e.getClass().getName()                                    + ": " + e.getMessage());         }     } ... 
end example

The producer bean stores the session context, which is passed to it in the method setSessionContext (see Listing 7-10), in the variable sessionCtxt.

Listing 7-10: ProducerBean.setSessionContext: setting the session context.

start example
 ...     public void setSessionContext(SessionContext ctxt) {         this.sessionCtxt = ctxt;     } ... 
end example

With the method produce in Listing 7-11 things get interesting. This method assumes that it is executed in a transaction. It reduces the quantity of stored raw materials and increases that of stored end product. There is no prior check whether the execution of these actions is possible. If an error occurs, the entire transaction is simply rolled back. For this the method setRollbackOnly of the session context in the catch block is called. With this error not only is an exception triggered, but also setRollbackOnly is called, since a stock bean's value may have been changed, resulting in an invalid intermediate state in the database.

Listing 7-11: ProducerBean.produce: Business logic of the session bean Producer.

start example
 ...     public int produce(int amount)         throws UnappropriateStockException     {         int ret;         try {             System.out.println("starting produce");             this.source1.get(amount);             this.source2.get(amount*2);             this.target.put(amount);             ret = amount;         } catch(ProcessingErrorException e) {             this.sessionCtxt.setRollbackOnly();             throw new UnappropriateStockException();         } catch (java.rmi.RemoteException re) {             this.sessionCtxt.setRollbackOnly();             throw new UnappropriateStockException();         }         return ret;     } ... 
end example

The definitions of the producer bean and the stock bean are located in the same deployment descriptor. Listing 7-12 shows the relevant parts of the deployment descriptor for the producer bean (Listing 7-5 shows the relevant parts for the stock bean). For the method produce of the producer bean, Required is declared in the deployment descriptor as transaction attribute. Also, the environment variables for the producer bean are defined. Additionally, the deployment descriptor contains a reference to the stock bean.

Listing 7-12: Extract from the deployment descriptor of the session bean producer.

start example
 ...   <enterprise-beans>     ...     <session>       <ejb-name>Producer</ejb-name>       <home>ejb.supplychain.producer.ProducerHome</home>       <remote>ejb.supplychain.producer.Producer</remote>       <ejb-class>ejb.supplychain.producer.ProducerBean</ejb-class>       <session-type>Stateful</session-type>       <transaction-type>Container</transaction-type>       <env-entry>         <env-entry-name>idSource1</env-entry-name>         <env-entry-type>java.lang.String</env-entry-type>         <env-entry-value>stock1</env-entry-value>       </env-entry>       <env-entry>         <env-entry-name>idSource2</env-entry-name>         <env-entry-type>java.lang.String</env-entry-type>         <env-entry-value>stock2</env-entry-value>       </env-entry>       <env-entry>         <env-entry-name>idTarget</env-entry-name>         <env-entry-type>java.lang.String</env-entry-type>         <env-entry-value>stock3</env-entry-value>       </env-entry>       <ejb-ref>         <ejb-ref-name>ejb/Stock</ejb-ref-name>         <ejb-ref-type>Entity</ejb-ref-type>         <home>ejb.supplychain.stock.StockHome</home>         <remote>ejb.supplychain.stock.Stock</remote>         <ejb-link>Stock</ejb-link>       </ejb-ref>     </session>   </enterprise-beans>   <assembly-descriptor>     <container-transaction>       ...       <method>         <ejb-name>Producer</ejb-name>         <method-name>produce</method-name>       </method>       <trans-attribute>Required</trans-attribute>     </container-transaction>   </assembly-descriptor> </ejb-jar> 
end example

We have created a test based on the test framework to be presented in Chapter 9 for the producer bean. The complete test, together with many other tests for the examples in this book, is contained within the source code for this book.

Listing 7-13 presents a section from this test for the producer bean, from which can be seen exactly the expected behavior of the producer bean for the method previously described.

Listing 7-13: A section of the test for the session bean Producer.

start example
 ... Stock stock1 = this.stockHome.create("stock1", 500, 200); Stock stock2 = this.stockHome.create("stock2", 500, 500); Stock stock3 = this.stockHome.create("stock3", 100, 0); int step = 1; Producer p = this.producerHome.create(); p.produce(10); this.assertEquals(step+":volume stock1", 190, stock1.getVolume()); this.assertEquals(step+":volume stock2", 480, stock2.getVolume()); this.assertEquals(step+":volume stock3", 10, stock3.getVolume()); step++; p.produce(40); this.assertEquals(step+":volume stock1", 150, stock1.getVolume()); this.assertEquals(step+":volume stock2", 400, stock2.getVolume()); this.assertEquals(step+":volume stock3", 50, stock3.getVolume()); step++; p.produce(50); this.assertEquals(step+":volume stock1", 100, stock1.getVolume()); this.assertEquals(step+":volume stock2", 300, stock2.getVolume()); this.assertEquals(step+":volume stock3", 100, stock3.getVolume()); step++; try {     p.produce(10);     this.fail("Expected UnappropriateStockException"); } catch(UnappropriateStockException ex) {     //as expected } this.assertEquals("final:volume stock1", 100, stock1.getVolume()); this.assertEquals("final:volume stock2", 300, stock2.getVolume()); this.assertEquals("final:volume stock3", 100, stock3.getVolume()); ... 
end example

First, the test generates three stock beans, stock1, stock2, and stock3. The beans stock1 and stock2 are the stores from which the producer bean takes material for constructing the end product. The finished product is then stored in the store stock3 (see again Listing 7-12, the deployment descriptor of the producer bean). After generation of the producer bean, ten units are produced. The test ensures, using the method assertEquals, that stock1 now contains 190 units (200 units were there at the beginning; one unit was taken for each unit of end product); that stock2 contains 480 units (500 units at the beginning, with two units taken for each unit of end product); and that stock3 contains ten units of end product (there were none at the start). Then, forty units are produced, and then 50, and the corresponding numbers checked. In the last step of the test an error is produced. Ten units are produced, which the store stock3 cannot take in, since its maximum capacity was specified to be one hundred units. The test ensures that the method produce triggers an exception on account of the full store stock3 and that after the invalid call to the method produce a consistent state in the stored quantities exists. If the method produce had not been executed in a transaction, then the values of stores stock1 and stock2 would have been reduced by the appropriate quantities, but the amount in stock3 would not have been raised accordingly, since it was full. The data would then have been in an inconsistent state.

Transaction Attributes

Transaction attributes are used to define the transactional behavior for the methods of Enterprise Beans. The attributes are registered in the deployment descriptor, and the EJB container uses them to provide a suitable transaction context for the execution of the methods. Moreover, the transaction attributes define the interplay of the Enterprise Beans among themselves and with the client with regard to transactions.

In the following all transaction attributes are described that are supported by EJB version 2.1 and EJB version 2.0.

NotSupported

A method with the transaction attribute NotSupported in the deployment descriptor does not support transactions. This means that the method will not be executed in a transaction controlled by the EJB container.

In developing such a method this must be taken into account to the extent that that there is no possibility for actions once executed to be undone with a rollback. For access to transactional systems—a database, for example—one works generally only with a local transaction.

A method with the transaction attribute NotSupported is normally addressed by the client (recall that the client can also be an Enterprise Bean) without a global transaction context. If the client should nevertheless use a transaction for the call, this will not be used in the method. The client's transaction is uninfluenced by it. The method's actions are not bound to this transaction. We note once more that the EJB concept does not support nested transactions.

This transaction attribute may not be used by beans that implement the SessionSynchronization interface (see the later subsection on synchronization).

The constant NotSupported can be used in the deployment descriptor in EJB versions 1.1 and beyond. For the serialized deployment descriptor of EJB version 1.0 the corresponding Java constant is TX_NOT_SUPPORTED.

Required

Methods that have the transaction attribute Required are always executed in a transaction.

If the method is called by the client with a global transaction, then this is used for the execution of the method. If the call takes place without a transaction, then the EJB container automatically launches a transaction. This guarantees that the method is always executed within a global transaction.

Access to other beans and transactional systems is thus also ensured, since the global transaction context is inherited.

In the use of the transaction attribute Required it should always be kept in mind that global transactions are expensive. There often is a way to increase performance through doing without global transactions to some extent.

For EJB version 1.0 the corresponding constant is TX_REQUIRED.

Supports

The transaction attribute Supports means that a method can be executed either with or without a transaction.

If there is already a transaction when a call is made, then this is available for use in the execution of the method. If the method is called without a transaction, then there is no transaction available.

Methods for which this transaction attribute is to be used must therefore be able to deal with both these cases. The implementation must be able to perform its tasks with and without a transaction context.

The EJB specification states specifically that the transaction attribute Supports can be used instead of Required to improve performance. If the precise implementation of the method is unknown, then at deployment, caution is advised in the use of the transaction attribute Supports.

This transaction attribute may not be used by beans that implement the SessionSynchronization interface (see also the subsection on synchronization later in this chapter), and it cannot be used by message-driven beans.

For EJB version 1.0 the corresponding constant is TX_SUPPORTS.

RequiresNew

A method with the transaction attribute RequiresNew possesses its own private transaction. Before the method is started the EJB container always launches a new global transaction. After leaving the method, the EJB container always attempts to end the transaction with a commit.

The transaction with which the client (which, as already mentioned, can be an Enterprise Bean) calls the method remains completely isolated. The actions of the method are not bound to this transaction. The new transaction will be inherited in the usual way with access to other beans or with the use of a transactional system.

This transaction attribute cannot be used by message-driven beans. For EJB version 1.0 the corresponding constant is TX_REQUIRES_NEW.

Mandatory

A method with the transaction attribute Mandatory must always be called by a client with a global transaction. If there is no transaction when the method is called, this leads to an error (TransactionRequiredException).

The client's transaction is used for the execution of the method and is also further transmitted. It is guaranteed that the method is always executed in a global transaction context. This transaction attribute cannot be used by message-driven beans. For EJB version 1.0 the corresponding constant is TX_MANDATORY.

Never

A method with the transaction attribute Never may never be called by a client in a transaction context. This would lead to an error (RemoteException).

The method is always executed without a transaction. For development the same restrictions are in force as with the transaction attribute NotSupported.

This transaction attribute may not be used by beans that implement the SessionSynchronization interface (see also the subsection on synchronization), and it cannot be used by message-driven beans.

The transaction attribute Never has been supported since EJB version 1.1.

Transaction Isolation

The isolation level of transactions was described at the beginning of this chapter. We would like to consider again the four isolation levels, only now a bit more deeply:

  1. Read Uncommitted: This level is the weakest level with respect to data consistency and the strongest with respect to performance. If this isolation level is used for access to data (in a database, for example), then the problems of dirty reads, nonrepeatable reads, and phantom reads can occur.

  2. Read Committed: This level is the next strongest after Read Uncommitted with respect to data consistency. In a transaction with this isolation level data that have been changed by other transactions but not yet committed cannot be read. All that can be read is the state that the data have had since the last successfully executed commit. Thus the problem of dirty reads can no longer occur. The problem of nonrepeatable reads and that of phantom reads can still occur.

  3. Repeatable Reads: In comparison to the Read Committed isolation level, data that have just been read by another transaction cannot be changed in this transaction. Write access to the data is blocked until the reading transaction has terminated with commit or rollback. From this behavior it is clear that with increasing data consistency, performance suffers in parallel accesses, since write accesses can be blocked at this level. At this level of isolation only the phantom read problem can occur.

  4. Serializable: On this isolation level none of the problems dirty reads, nonrepeatable reads, and phantom reads can occur. A transaction has exclusive read and write access to the data. Other transactions can neither read nor change the data. Read and write access by other transactions is blocked until the transaction is terminated with commit or rollback. This level is the strongest with respect to data consistency, the weakest with respect to performance.

The developer of a bean can determine the isolation level at which operations in the transaction are to occur. This is specified, as a rule, in the developer-dependent additions to the deployment descriptor. Many developers additionally offer the option of configuring the isolation level to that of the database driver. If a bean accesses a database directly, then it has the option of setting the isolation level for the current transaction via the method setTransactionIsolation of the interface java.sql.Connection.

Setting the isolation level holds great potential for optimization. One must find the proper balance between data consistency and performance. It all depends on the requirements of the application.

Synchronization

For the synchronization of beans with container transactions the bean can implement the interface javax.ejb.SessionSynchronization. Session beans that manage their own transactions do not require this mechanism, since they themselves have full control over the transactions. Nor do entity beans need this interface. It is reserved for stateful session beans that use transactions managed by the container.

The interface consists of three methods, which are called by the EJB container when a transaction is in certain states (see Listing 7-14). The implementation of this interface is optional and necessary only in rare cases.

Listing 7-14: Definition of the interface javax.ejb.SessionSynchronization.

start example
 public void afterBegin()   throws javax.ejb.EJBException,          java.rmi.RemoteException; public void beforeCompletion()   throws javax.ejb.EJBException,          java.rmi.RemoteException; public void afterCompletion(boolean committed)   throws javax.ejb,EJBException,          java.rmi.RemoteException; 
end example

In order to ensure that methods are correctly called by the EJB container there are restrictions with respect to the transaction attributes. Beans that implement the SessionSynchronization interface may use only the transaction attributes Required, RequiresNew, and Mandatory.

The method afterBegin is called to notify a bean that the following method calls are to be executed in a new transaction. The method is not necessarily executed at the beginning of the transaction, but only when the EJB container is aware that a particular bean is to take part in a transaction. This method is used, for example, to enable the caching of database contents for increasing access performance.

The method beforeCompletion is called before a transaction is completed. At this time it is not yet known whether a rollback or a commit will be executed. In this method a rollback (method setRollbackOnly) can still be forced. This method is used to write temporarily stored database contents back to the database or to check additional consistency conditions.

The method afterCompletion is called after the end of a transaction to notify the bean as to whether the transaction was ended with rollback or commit. Warning: When this method is called the transaction is already over. The method is executed outside of all transactions. This method is used to release resources that were needed especially for the transaction. A Boolean parameter is also passed to this method to indicate whether the transaction was committed or rolled back. This parameter can be used to indicate to the developer to reset variables to the correct state for the session bean.




Enterprise JavaBeans 2.1
Enterprise JavaBeans 2.1
ISBN: 1590590880
EAN: 2147483647
Year: 2006
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net