Last question, promise!

I decided to do what the above exception so kindly suggested and
created a new PersistenceManager as follows:

  PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
  pmfInstance.setNontransactionalRead(true);
  pmfInstance.setNontransactionalWrite(true);

Basically, I set both NontransactionalRead and NontransactionalWrite
to true. This seemed to solve my issue and rolled back the first
transaction if the second update failed. Great! However, I'm not sure
what these two settings do and I'm slightly worried I may be getting
myself into more problems by messing with them. Could someone kindly
tell me if my "fix" is suitable and/or safe?

Thanks

On Jul 18, 10:02 am, mscwd01 <mscw...@gmail.com> wrote:
> Thanks for theupdate. It's a pity you cant check to see if the first
> transaction committed before it leaves an "active" state, that'd make
> things so much easier. I really needed thetwoupdates to occur as
> quickly as possible so relying on the secondupdateto continue
> retying via the task queue, is not ideal. Would running the
> PersistenceManagerFactory with 'NontransactionalRead' and
> 'NontransactionalWrite' set to 'true' allow me to do what I want? I
> cant really find any documentation that describes what thosetwo
> values do.
>
> Thanks again
>
> On Jul 17, 11:46 pm, Nichole <nichole.k...@gmail.com> wrote:
>
>
>
>
>
>
>
> > Good point, I rewrote the code below to better use the available
> > connections
> > and improve the pattern.
>
> >    Regardingupdate1 being committed andupdate2 failing, the
> > first is already committed, yes.  I think one has to use a retry for
> > the
> > 2ndupdate(using the task queue structure) for the 2nd operation to
> > eventually succeed, but on a longer timescale.
>
> > Here's a better approach to the problem:
>
> > import com.climbwithyourfeet.software.twotransaction.util.PMF;
> > import com.google.appengine.api.datastore.Key;
> > import java.util.ArrayList;
> > import javax.jdo.Transaction;
> > import javax.jdo.PersistenceManager;
> > import java.util.logging.Logger;
> > import com.google.appengine.tools.development.LocalDatastoreTestCase;
> > import java.util.List;
> > import org.junit.After;
> > import org.junit.Before;
> > import org.junit.Test;
>
> > /**
> >    Goal:
> >  *    Update2entitieswhich reside in 2 different entity groups.
> >  *     The updates must both pass or both fail.
> >  *
> >  * Solution:
> >  *     Use a different transaction for each entity, configurable in
> >         jdoconfig.xml.
> >  *     (Note that it looks like 2 named PersistenceManagerFactory
> >         connections are possible, but not more than that, and there
> >         is only one transaction for a  PMF connection).
> >  *
> >  *     Solution is essentially check that transaction1 succeeds or
> > fails before
> >  *     committing transaction2.
> >  *
> >  *     The case which needs additional fail-over is the case in which
> >        transaction 1 is committed successfully but transaction2 fails.
> >  *     In this case a retry of transaction2 should be invoked and must
> >        eventually succeed.
> >  *
> >  *     For that reason, any code using this pattern should design
> >        the logic so that the logic in the 2nd transaction can be
> > consistent
> >        on a longer timescale.
> >  *
> >  * @author nichole
> >  */
> > public class TwoOperationPseudoTransactionTest extends
> > LocalDatastoreTestCase {
>
> >     private final Logger log =
> > Logger.getLogger(this.getClass().getName());
> >     private String iden1 = "1234567";
> >     private String iden2 = "1123456";
>
> >     public TwoOperationPseudoTransactionTest() {
> >         super();
> >     }
>
> >     @Before
> >     public void setUp() throws Exception {
> >         super.setUp();
>
> >         try {
> >             PersistenceManager pm = PMF.get().getPersistenceManager();
> >             Transaction tx = pm.currentTransaction();
> >             tx.begin();
> >             UserGameCredits e1 = new UserGameCredits(iden1);
> >             pm.makePersistent(e1);
> >             pm.flush();
> >             tx.commit();
>
> >             PersistenceManager pm2 =
> > PMF.get2().getPersistenceManager();
> >             tx = pm2.currentTransaction();
> >             tx.begin();
> >             UserAccount e2 = new UserAccount(iden2);
> >             pm2.makePersistent(e2);
> >             pm2.flush();
> >             tx.commit();
> >         } catch (Throwable t) {
> >             String msg = t.getMessage();
> >         }
> >     }
>
> >     @After
> >     public void tearDown() throws Exception {
> >         super.tearDown();
> >     }
>
> >     @Test
> >     public void test2() throws Exception {
>
> >         PersistenceManager pm = PMF.get().getPersistenceManager();
> >         PersistenceManager pm2 = PMF.get2().getPersistenceManager();
>
> >         final Transaction tx = pm.currentTransaction();
> >         final Transaction tx2 = pm2.currentTransaction();
>
> >         final List<Boolean> completedOp1 = new ArrayList<Boolean>();
> >         final List<Boolean> completedOp2 = new ArrayList<Boolean>();
>
> >         try {
>
> >             // change to for tests
> >             final boolean commit1 = true;
> >             final boolean commit2 = false;
>
> >             tx.setSynchronization(new
> > javax.transaction.Synchronization() {
> >                 public void beforeCompletion() {
> >                     log.info("before transaction 1");
> >                 }
> >                 public void afterCompletion(int status) {
> >                     switch (status) {
> >                         case
> > javax.transaction.Status.STATUS_MARKED_ROLLBACK :
> >                             // fall through
> >                         case
> > javax.transaction.Status.STATUS_ROLLEDBACK :
> >                             log.severe("rollback transaction 1");
> >                             break;
> >                         case
> > javax.transaction.Status.STATUS_COMMITTED:
> >                             log.info("committed transaction 1");
> >                             completedOp1.add(Boolean.TRUE);
> >                             break;
> >                         case javax.transaction.Status.STATUS_UNKNOWN:
> >                             // treat as rollback both?
> >                     }
> >                 }
> >             });
> >             tx2.setSynchronization(new
> > javax.transaction.Synchronization() {
> >                 public void beforeCompletion() {
> >                     log.info("before transaction 2");
> >                 }
> >                 public void afterCompletion(int status) {
>
> >                     switch (status) {
> >                         case
> > javax.transaction.Status.STATUS_MARKED_ROLLBACK :
> >                             // fall through
> >                         case
> > javax.transaction.Status.STATUS_ROLLEDBACK :
> >                             log.severe("rollback transaction 2");
> >                             if (!completedOp1.isEmpty() &&
> > completedOp1.get(0)) {
> >                                 log.severe("1st transaction committed,
> > but 2nd did not");
> >                                 //TODO this is the case we need to
> > apply application logic for
> >                                 retry2ndOperation();
> >                             }
> >                             break;
> >                         case
> > javax.transaction.Status.STATUS_COMMITTED:
> >                             log.info("committed transaction 2");
> >                             completedOp2.add(Boolean.TRUE);
> >                             break;
> >                         case javax.transaction.Status.STATUS_UNKNOWN:
> >                             // treat as rollback both?
> >                     }
> >                 }
> >             });
>
> >             tx.begin();
>
> >             Key key1 = UserGameCredits.createKey(iden1);
> >             UserGameCredits e1 =
> > pm.getObjectById(UserGameCredits.class, key1);
> >             e1.setVariable("updated");
>
> >             pm.flush();
>
> >             if (commit1) {
> >                 tx.commit();
> >             }
>
> >             if (!completedOp1.isEmpty() && completedOp1.get(0)) {
>
> >                 tx2.begin();
>
> >                 Key key2 = UserAccount.createKey(iden2);
> >                 UserAccount e2 = pm.getObjectById(UserAccount.class,
> > key2);
> >                 e2.setVariable("updated");
>
> >                 pm2.flush();
>
> >                 // test structure that shouldn't be in place for real
> > code!
> >                 // (the retry is in the sync code above)
> >                 if (commit2) {
> >                     tx2.commit();
> >                 } else {
> >                     log.severe("1st transaction committed, but 2nd did
> > not");
> >                     //TODO this is the case we need to apply
> > application logic for
> >                     retry2ndOperation();
> >                 }
> >             }
>
> >         } catch (Throwable t) {
>
> >             String msg = t.getMessage();
>
> >         } finally {
>
> >             boolean rollback =
> >                  ((tx != null) && tx.isActive()) ||
> >                  ((tx2 != null) && tx2.isActive());
>
> >             if (rollback) {
> >                 if (tx.isActive())
> >                     tx.rollback();
> >                 if (tx2.isActive())
> >                     tx2.rollback();
> >                 log.info("both  failed");
> >             } else {
> >                 log.info("both  succeeded");
> >             }
>
> >             if (pm != null) {
> >                 pm.close();
> >             }
> >             if (pm2 != null) {
> >                 pm2.close();
> >    
>
> ...
>
> read more »

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to google-appengine-java@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to