7 Understanding Transaction Processing

This chapter contains the following topics:

7.1 Transaction Processing

You update the JD Edwards EnterpriseOne database by processing a transaction. A transaction is a logical unit of work performed on the database to complete a common task and maintain data consistency. A transaction consists of transaction statements that are closely related and perform interdependent actions. Each transaction statement performs part of the task, but all of the statements are required for completing the task. Transaction processing ensures that related data is added to or deleted from the database simultaneously, thus preserving data integrity. In transaction processing, data is not written to the database until a commit command is issued. When this happens, data is permanently written to the database. You can use one of these ways to commit transactions:

  • Auto commit

  • Manual commit

7.1.1 Auto Commit

An auto commit transaction encompasses individual table updates within a business function call or direct database call from the business service. Each individual update is committed or rolled back immediately. The commitment or rollback does not depend on success or failure or any other call. Transaction processing that uses auto commit does not require an explicit call to commit or roll back data. When you use auto commit, you cannot include another business function or database call as part of the transaction for rollback. You cannot include multiple table updates called from within the business function as part of a transaction for rollback.

7.1.2 Manual Commit

When you use manual commit, the record is held until commit or rollback is explicitly called. Business function and database calls can be strung together and committed or rolled back based on success or failure of any one of the calls. Although business function and database operations can be called within the same published business service or business service transaction boundary, two separate connections are created in the background. When you code for these two types of operations, consider that one should not depend on the other's data. For example, if you are calling insert for a business unit and then you try to add an address book record that contains that business unit, the transaction will fail because the database call hasn't been committed yet.

7.2 Default Transaction Processing Behavior

The business service framework provides two types of default transactions: manual commit connection and auto commit connection.

For a single manual commit transaction, the default behavior is to scope all processing within the published business service method. If any operation within this scope fails, all operations are rolled back, and the published business service method throws an exception. This behavior is recommended when multiple records are committed to multiple tables.

For a single auto commit transaction, the default behavior is that each operation commits or rolls back immediately, which means that each table update within each business function call is either committed or rolled back immediately. This behavior is recommended for queries for which no transaction is needed or when you are committing a single record to a single table.

When you are deciding which type of connection to use, you should always consider the business function behavior.

7.2.1 Published Business Service Boundary for Manual Commit

The startPublishedMethod, finishPublishedMethod, and close methods within the published business service indicate the boundary of the transaction. All activities that occur within the startPublishedMethod and finishPublishedMethod calls will be committed when finishPublishedMethod is called. You must include the close method to clean up all connections.

7.2.2 Published Business Service Boundary for Auto Commit

The startPublishedMethod, finishPublishedMethod, and close methods within the published business service are used to create the auto commit connection and to clean up the connections. All activities that occur within the startPublishedMethod and finishPublishedMethod calls are committed or rolled back immediately because no transaction boundary exists that encompasses more than one operation, including the table updates within the business function. For an auto commit connection, the purpose of finishPublishedMethod is different than for a manual commit because no need exists to commit the transaction. The finishPublishedMethod plays a roll in monitoring and tying the entire business process together. You call the close method to clean up all connections.

For both manual commit and auto commit, you should use a try block to enclose startPublishedMethod and finishPublishedMethod. You call the close method from a finally block to ensure that all transactions are finished and no connections linger.

This code sample shows the structure for defining the transaction processing boundary for the published business service:

public ConfirmAddAddressBook addAddressBook(AddAddressBook vo) throws 
BusinessServiceException {
       return (addAddressBook(null, null, vo));
   }
    protected ConfirmAddAddressBook addAddressBook(IContext context, 
                     IConnection connection,
                     AddAddressBook vo) throws BusinessServiceException{
       //perform all work within try block, finally will clean up any 
       //connections
       try {
           // call start published method, passing null, 
           //will return context object so BSFN can be called later
           //used to indicate transaction boundary as well as used for 
           //logging
           //Start Implicit Transaction
           context = startPublishedMethod(context, "addAddressBook");
           // create a new internal VO.
           InternalAddAddressBook internalVO= new InternalAddAddress
Book();
           messages.addMessages(vo.mapFromPublsihed(context, internal
VO));//
           // start business service addAddressBook passing context and 
           // internal VO published business service Calling business 
           // service
           E1MessageList messages = AddressBookProcessor.addAddressBook
(context, connection, internalVO);
           // published business service will send either warnings in 
           // the Confirm Value Object or throw a published business 
           // serviceException.
           if (messages.hasErrors()) {
               // get the string representation of all the messages
                //RI: Error Handling
               String error = messages.getMessagesAsString());
               // Throw BusinessServiceException.(
               throw new BusinessServiceException(error,context);
           }
           // exception was not thrown, so create the confirm VO from 
           // internal VO
          ConfirmAddAddressBook confirmVO = new ConfirmAddAddressBook
(internalVO);
           confirmVO.setE1MessageList(messages);
           //Call to commit default transaction.
           finishPublishedMethod(context, "addAddressBook");
           // return confirm VO, filled with return values and messages
           return confirmVO;
        }
        finally {
           //Call close to clean up all remaining connections and 
           //resources.
           close(context,"addAddressBook");                
        }
  }

7.3 Explicit Transaction Processing Behavior

Oracle recommends that you use default transaction behavior whenever possible. However, you can define your published business service or business service to explicitly manage transactions. To handle the transaction correctly in the business service, you must understand the detailed transaction behavior of the business function being called.

The published business service protected method and all business service methods are required to have both IContext and IConnection as part of their signature, as are any calls to business functions or database operations. If you are using default transaction processing, the connection can be null. If you use explicit transaction processing, you must provide an explicit connection, either auto or manual commit. When you use an explicit connection, you decide whether having multiple transactions is appropriate and whether they are auto commit or manual commit connections. If you create an explicit transaction from your business service, you are not required to check for null on the connection before using it, because the foundation classes ensure that the connection is never null. If the token is dropped, a runtime connection is thrown, which is consistent with the default transaction processing.

7.3.1 Creating a New Connection

You can create a new transaction in either the published business service or business service, depending on where control begins. Typically, the business service controls the transaction. The context object has exposure to all connections; so to create a new connection, you call a method from the context object. You create either a manual commit or an auto commit method. Both methods are illustrated in this code sample:

IConnection soConnection = context.getNewConnection(IConnection.MANUAL)
;);
//manual commit
IConnection soConnection = context.getNewConnection(IConnection.AUTO);
//auto commit

A manual commit method holds the record until commit or rollback is explicitly called. You create a manual commit method by using IConnection.MANUAL (false) as the parameter in the context object. An auto commit method commits the record immediately without an explicit call to commit the record. With auto commit, the record is committed when the Close method is called. You create an auto commit method by using IConnection.AUTO (true) as the parameter in the context object.

The default connection is available even when an explicit connection is created.

7.3.2 Using an Explicit Transaction

The following scenarios illustrate two ways to use an explicit transaction and achieve the same result. In these scenarios, a business service processes a sales order. Inventory records are updated when each record is processed instead of waiting until the end of the sales order processing to update the inventory records. In each scenario, if an error occurs before the sales order process is completed and committed, an exception message is sent to the caller, and updates that were made to the inventory records are rolled back.

7.3.2.1 Scenario 1

This scenario uses an explicit auto commit transaction that updates the Inventory table and commits and releases the table immediately before continuing with the remainder of the sales order processing. Because inventory records are committed before the sales order is committed, an error could occur during the continued processing of the sales order. If an error occurs, another business function (referred to as a compensating business function) must be called to undo the inventory updates.

You use another explicit transaction to call the compensating business function. You can either reuse the original auto commit connection or create a new connection. The best option is to reuse the original auto commit connection, because this limits the number of objects that are created. You cannot use the default transaction because you want to send an exception message to the caller indicating that the sales order processing failed, and you want to roll back any updates that were made to the inventory records. You use an explicit connection so that you can control the compensating business function to ensure that updates are rolled back, even if an exception is thrown.

This code sample illustrates this scenario:

public E1MessageList processSalesOrder(IContext context, IConnection 
connection, InternalProcessSalesOrder internalVO){
 ...   
     //Create new explicit auto commit connection to add inventory 
     //records
     IConnection invConnection = context.getNewConnection
(IConnection.AUTO);
     
        
        //call method (created by the wizard), which then executes 
Business Function or Database operation
           E1MessageList invMessages =  callInventoryMBF(context, 
                                                      invConnection, 
                                                      internalVO, 
                                                      programId);
           //add messages returned from E1 processing to business 
           //service message list.
           messages.addMessages(invMessages);
           if (!invMessages.hasErrors()) {
              //No errors continue processing SO
           IConnection soConnection = context.getNewConnection
(IConnection.MANUAL);
           try {
                     //Call  SO 
                     E1MessageList soMessages = callSOMBF(context, 
                                                        soConnection, 
                                                        internalVO);
                     //Check for errors, collect in messages.
                     if (!soMessages.hasErrors()) {
                        soConnection.commit();
                     }else{
                        soConnection.rollback();
              //Errors in SO processing, call MBF to compensate for 
              //added inventory
                   E1MessageList compMessages = callInventory
CompensateMBF(context,invConnection,internalVO);
                        if(compMessages.hasErrors()){
                           compMessages.setMessagePrefix("Unable to 
Compensate for Added Inventory");
                        } 
                        messages.addMessages(compMessages);
                     }
                  } 
                  catch (BSSVConnectionException e) {
                     //Create new error and return E1MessageList
                     E1Message txMessage =  new E1Message
(context, "006FIS",  e.getMessage());
                     messages.addMessage(txMessage);
                  }
                  soConnection.close();
               
             }
           
           invConnection.close();
        
     finishInternalMethod(context, "addAddressBook");
     return messages;
  }

7.3.2.2 Scenario 2

This scenario uses an auto commit connection to create a default transaction by calling startPublishedMethod and passing an additional parameter that specifies the auto commit connection—startPublishedMethod(context,"processSalesOrder",IConnection. AUTO). Because inventory records are committed before the sales order is committed, an error could occur during the continued processing of the sales order. If an error occurs, another business function (referred to as a compensating business function) must be called to undo the inventory updates.

To control the transaction and handle a sales order failure, you use a manual commit connection to call the Sales Order Commit business function. Everything within the business function call will roll back. You can call a compensating business function to roll back the inventory records that were automatically committed. You want the default auto commit transaction to call the compensating business function.

This code sample illustrates this scenario:

public E1MessageList processSalesOrder(IContext context, IConnection 
connection, InternalProcessSalesOrder internalVO){
 ...   
       
        //call method (created by the wizard), which then executes 
Business Function or Database operation
           E1MessageList invMessages =  callInventoryMBF(context, 
                                                         connection, 
                                                         internalVO, 
                                                         programId);
           //add messages returned from E1 processing to business 
           //service message list.
           messages.addMessages(invMessages);
           if (!invMessages.hasErrors()) {
              //No errors continue processing SO using manual commit 
              //connection
           IConnection soConnection = context.getNewConnection
(IConnection.MANUAL);
           try {
                     //Call  SO 
                     E1MessageList soMessages = callSOMBF(context, 
                                                       soConnection, 
                                                       internalVO);
                     //Check for errors, collect in messages.
                     if (!soMessages.hasErrors()) {
                        soConnection.commit();
                     }else{
                        soConnection.rollback();
              //Errors in SO processing, call MBF to compensate for 
              //added inventory
              E1MessageList compMessages = callInventoryCompensateMBF
(context,connection,internalVO);
                        if(compMessages.hasErrors()){
                           compMessages.setMessagePrefix
("Unable to Compensate for Added Inventory");
                        } 
                        messages.addMessages(compMessages);
                     }
                  } 
                  catch (BSSVConnectionException e) {
                     //Create new error and return E1MessageList
                     E1Message txMessage =  new E1Message
(context, "006FIS",  e.getMessage());
                     messages.addMessage(txMessage);
                  }
                  soConnection.close();
                         
          }
     finishInternalMethod(context, "addAddressBook");
     return messages;
  }