Nested transactions on google app engine datastore

2019-09-13 22:51发布

Question is: does ds.put(employee) happen in transaction? Or does the outer transaction get erased/overriden by the transaction in saveRecord(..)?

  1. Once error is thrown at line datastore.put(..) at some point in the for-loop (let's say i==5), will previous puts originating on the same line get rollbacked?
  2. What about puts happening in the saveRecord(..). I suppose those will not get rollbacked.

    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService()
    Transaction txn = datastore.beginTransaction();
    try {
        for (int i=0; 1<10; i++) {
            Key employeeKey = KeyFactory.createKey("Employee", "Joe");
            Entity employee = datastore.get(employeeKey);
            employee.setProperty("vacationDays", 10);

            datastore.put(employee);

            Entity employeeRecord = createRecord("record", employeeKey);
            saveRecord(employeeRecord);
        }
    txn.commit();
    } finally {
        if (txn.isActive()) {
            txn.rollback();
        }
    }

    public void saveRecord(Entity entity) {
       datastore.beginTransaction();
       try {
          // do some logic in here, delete activity and commit txn
          datastore.put(entity);
       } finally {
        if (datastore.getCurrentTransaction().isActive()) {
          datastore.getCurrentTransaction().rollback();
        }
       }
    }

1条回答
再贱就再见
2楼-- · 2019-09-13 23:14

OK, I'll assume you are using low-level Datastore API. Note that getTransaction() does not exist. I'll assume you meant datastoreService.getCurrentTransaction().

DatastoreService.beginTransaction() will return a Transaction, that is considered a current transaction on the same thread until you call beginTransaction() again. Since you call beginTransaction() in a loop inside "outer" transaction, it breaks your "outer" code: after the loop is finished ds.getCurrentTransaction() does not return the same transaction. Also, put() implicitly uses current transaction.

So first you must fix outer code to save transaction as shown in example:

public void put(EventPlan eventPlan) {
  Transaction txn = ds.beginTransaction();
  try {
    for (final Activity activity : eventPlan.getActivities()) {
      save(activity, getPlanKey(eventPlan)); // PUT

      // IMPORTANT - also pass transaction and use it
      // (I assume this is some internal helper method)
      ds.put(txn, activity, getSubPlanKey(eventPlan)); //subplan's parent is eventPlan
    }
    txn.commit();
  } finally {
    if (txn.isActive()) 
      txn.rollback();
  }
}

Now on to questions:

  1. Yes, because all puts are now part of the same transaction (after you fix the code) and you call txn.rollback() on it in case of errors.

  2. No, of course not. They are part of different transactions.

查看更多
登录 后发表回答