package net.oxbeef.transaction; import java.util.Collection; import java.util.Iterator; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Stateless @Remote(DriverRemote.class) public class Driver implements DriverRemote { @PersistenceContext protected EntityManager em; // MAIN ENTRY POINT @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void growLegs() throws Exception { Collection c = em.createQuery("from Tiger t order by t.numLegs desc") .getResultList(); Tiger t; int size = c.size(); for (Iterator i = c.iterator(); i.hasNext();) { t = (Tiger) i.next(); t.setNumLegs(t.getNumLegs() + 1); // 50% chance of fail overall double prob = Math.pow(0.5, 1. / size); if (Math.random() > prob) { // Emulated failure causes rollback // throw new RollingException(); try { forbidden(t); } catch( Exception e ) { throw new RollingException(); } } // Synchronize the persistence context to the DB // All flushed updates will be removed from the DB // if the transaction is rolled back em.flush(); } } // execution has 50% chance of reaching here. It does get here, but doesn't fail. @TransactionAttribute(TransactionAttributeType.NEVER) protected void forbidden(Tiger t) { System.out.println("trying to do something here"); t.setNumLegs(0); em.flush(); // why didn't it fail with an EJBException?? } // just return a list of what's in the db public int[] getValues() { int[] list; try { Collection c = em.createQuery( "from Tiger t order by t.numLegs desc").getResultList(); list = new int[c.size()]; int count = 0; for (Iterator i = c.iterator(); i.hasNext();) { list[count++] = ((Tiger) i.next()).getNumLegs(); } } catch (Exception e) { e.printStackTrace(); return null; } return list; } }