1 Reply Latest reply on Sep 8, 2006 11:39 AM by hitman_in_wis

    @TransactionAttribute being ignored by Transaction Manager

    hitman_in_wis

      I believe I must have something configured incorrectly, or I misunderstand transaction management performed by the container. Though I have my datasource declared as local-tx, which I believe allows transactions, it appears that my a call to a remote function in a stateless session bean is completely executed in one single transaction, regardless of the @TransactionAttribute tags.

      In my example, I call a function with @TransactionAttribute = REQUIRED. This is the OUTER FUNCTION. This function inserts a record into the cust table of our database. Then this function calls a second function with @TransactionAttribute = REQUIRES_NEW. This is the INNER FUNCTION.

      This function should, according to spec, start up a new transaction independant of the first function. However, the INNER function can select the (un-committed) cust record from the OUTER function. The INNER function then proceeds to add a cust record of its own to the database.

      Control then returns to the OUTER function, which can succesfully read the cust record inserted by the INNER function, which is to be expected because the INNER function should have had its transaction committed. However, my program then throws a RuntimeException in order to force a rollback, and this rollback removes both the cust record inserted by the OUTER function and the cust record inserted by the INNER function.

      To further my belief that the transaction manager is ignoring my @TransactionAttribute annotations, I change the TransactionAttributeType of the INNER function to "NEVER". According to spec, the code should throw an exception when this function is called within a managed transaction. However, when I run the code I get the exact same behavior as when the INNER function is "REQUIRES_NEW".

      I would greatly appreciate if anyone has any insight into what I am doing wrong. Thanks!




      Client Program that Invokes TestTransImpl Stateless Session Bean
      ------------------------------------------------------------------------------------

      public class Client{
      
       public static void main(String[] args) throws Exception {
       try{
       Properties env = new Properties();
       env.setProperty(Context.SECURITY_PRINCIPAL, "guest");
       env.setProperty(Context.SECURITY_CREDENTIALS, "guest123");
       env.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099");
       env.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
       env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
      
       InitialContext ctx = new InitialContext(env);
       TestTransRemote ttr = (TestTransRemote)ctx.lookup("TestTransImpl/remote");
       ttr.testTransactions();
      
      
       }catch(Exception e){
       e.printStackTrace();
       throw e;
       }
      
       }
      }


      Remote Interface for TestTransImpl Stateless Session Bean
      --------------------------------------------------------------------------------
      public interface TestTransRemote extends Serializable {
       public void testTransactions() throws Exception;
      }


      TestTransImpl Stateless Session Bean
      ---------------------------------------------------------------------------------
      @Stateless
      @Remote(TestTransRemote.class)
      public class TestTransImpl implements TestTransRemote {
       private static final long serialVersionUID = 1L;
      
       @TransactionAttribute(TransactionAttributeType.REQUIRED)
       public void testTransactions() throws Exception{
       java.sql.Connection conn = getConnection();
       java.sql.PreparedStatement ps;
      
       ps = conn.prepareCall("insert into cust(loc,cust_no) values ('001',20)");
       ps.execute();
       System.out.println("OUTSIDE FUNCTION - Customer 20 created");
      
       requiredNewFunction();
      
       ps = conn.prepareCall("Select cust_no from cust where loc = '001' and cust_no = 24");
       java.sql.ResultSet results = ps.executeQuery();
       results.next();
       System.out.println("OUTSIDE FUNCTION - Customer Read - Cust No = " + results.getLong("cust_no"));
      
       throw new RuntimeException();
       }
      
       @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
       private void requiredNewFunction() throws Exception{
       java.sql.Connection conn = getConnection();
       java.sql.PreparedStatement ps;
      
       ps = conn.prepareCall("Select cust_no from cust where loc = '001' and cust_no = 20");
       java.sql.ResultSet results = ps.executeQuery();
       results.next();
       System.out.println("INSIDE FUNCTION - Customer Read - Cust No = " + results.getLong("cust_no"));
      
       ps = conn.prepareCall("insert into cust(loc,cust_no) values ('001',24)");
       ps.execute();
       System.out.println("INSIDE FUNCTION - Customer 24 created");
       }
      
       private java.sql.Connection getConnection() throws Exception{
       javax.sql.DataSource ds;
       javax.naming.InitialContext ic = new javax.naming.InitialContext();
       ds = (javax.sql.DataSource)ic.lookup("java:MyOracleDS");
       java.sql.Connection conn = ds.getConnection();
       return conn;
       }
      }


      Datasource XML File
      --------------------------------------------------------------------------------
      <?xml version="1.0" encoding="UTF-8"?>
      <datasources>
       <local-tx-datasource>
       <jndi-name>MyOracleDS</jndi-name>
       <connection-url>jdbc:oracle:thin:XXXXX(DB Host):1521:XXXXX(DB Sid)</connection-url>
       <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
      
       <user-name>XXXXX(username)</user-name>
       <password>XXXXX(password)</password>
      
       <min-pool-size>5</min-pool-size>
       <max-pool-size>100</max-pool-size>
      
       <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
      
       <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
       <metadata>
       <type-mapping>Oracle10g</type-mapping>
       </metadata>
       </local-tx-datasource>
      </datasources>
      


      Program Output
      -------------------------------------------------------------------------------
      08:43:41,093 INFO [STDOUT] OUTSIDE FUNCTION - Customer 20 created
      08:43:41,125 INFO [STDOUT] INSIDE FUNCTION - Customer Read - Cust No = 20
      08:43:41,140 INFO [STDOUT] INSIDE FUNCTION - Customer 24 created
      08:43:41,140 INFO [STDOUT] OUTSIDE FUNCTION - Customer Read - Cust No = 24