在为实体组提交事务后,再次提交App Engine 检查中使用的实体组的上次更新时间 交易。如果自我们的初始检查以来它已经发生了变化,App Engine 抛出异常
我有两个关于在两个并发事务中执行new Entity("TestEntity",1)
的事务数据存储的测试用例。
test1:将实体放入第一个事务中,将实体放入第二个事务中,然后提交两个事务。在开发服务器和独立单元测试中运行时,此测试通过(即抛出ConcurrentModificationException
),但在生产服务器中运行时失败(即执行时不会抛出异常)。
test2:将实体放在第一个事务中并提交它,然后将实体放入第二个事务并提交它。此测试总是失败。
test3:尝试在两个事务中获取(不存在的)实体,然后执行test2。此测试总是通过抛出ConcurrentModificationException
。
从这些测试中我得出结论,beginTransaction
和put
都不能保证执行“初始检查”,我需要支付 get 为了保证交易的完整性。那是对的吗?
@Test(expected=ConcurrentModificationException.class)
//put1 put2 commit1 commit2
public void test1() {
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Transaction txn1 = ds.beginTransaction();
Transaction txn2 = ds.beginTransaction();
ds.put(txn1,new Entity("TestEntity",1));
ds.put(txn2,new Entity("TestEntity",1));
txn1.commit();
txn2.commit();
}
@Test(expected=ConcurrentModificationException.class)
//put1 commit1 put2 commit2
public void test2() {
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Transaction txn1 = ds.beginTransaction();
Transaction txn2 = ds.beginTransaction();
ds.put(txn1,new Entity("TestEntity",1));
txn1.commit();
ds.put(txn2,new Entity("TestEntity",1));
txn2.commit();
}
@Test(expected=ConcurrentModificationException.class)
//get1 get2 put1 commit1 put2 commit2
public void test3() throws InterruptedException, ExecutionException {
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
ds.delete(KeyFactory.createKey("TestEntity", 1));
Transaction txn1 = ds.beginTransaction();
Transaction txn2 = ds.beginTransaction();
Assert.assertNull(getTestEntity(ds, txn1));
Assert.assertNull(getTestEntity(ds, txn2));
ds.put(txn1,new Entity("TestEntity",1));
txn1.commit();
ds.put(txn2,new Entity("TestEntity",1));
txn2.commit();
}
答案 0 :(得分:4)
从某种意义上说,你是正确的。 (MVCC)一致性不会要求时间戳,直到事务观察到可变数据快照的第一个事件。
想一想:如果没有任何读取而突变单个记录的事务如何违反一致性?由于它没有发布任何读取,因此它基本上不做任何假设。因此,没有任何假设可以被破解以导致写 - 写冲突。
最重要的是,无论如何,您都可以获得一致性的安全优势。在发出第一个事务性读取之前,强制执行该一致性不需要时间戳。