并发只写事务

时间:2013-03-08 03:03:40

标签: java google-app-engine google-cloud-datastore

datastore documentation说:

  

在为实体组提交事务后,再次提交App Engine   检查中使用的实体组的上次更新时间   交易。如果自我们的初始检查以来它已经发生了变化,App Engine   抛出异常

我有两个关于在两个并发事务中执行new Entity("TestEntity",1)的事务数据存储的测试用例。

  • test1:将实体放入第一个事务中,将实体放入第二个事务中,然后提交两个事务。在开发服务器和独立单元测试中运行时,此测试通过(即抛出ConcurrentModificationException),但在生产服务器中运行时失败(即执行时不会抛出异常)。

  • test2:将实体放在第一个事务中并提交它,然后将实体放入第二个事务并提交它。此测试总是失败。

  • test3:尝试在两个事务中获取(不存在的)实体,然后执行test2。此测试总是通过抛出ConcurrentModificationException

  • 来完成

从这些测试中我得出结论,beginTransactionput都不能保证执行“初始检查”,我需要支付 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();
}

1 个答案:

答案 0 :(得分:4)

从某种意义上说,你是正确的。 (MVCC)一致性不会要求时间戳,直到事务观察到可变数据快照的第一个事件。

想一想:如果没有任何读取而突变单个记录的事务如何违反一致性?由于它没有发布任何读取,因此它基本上不做任何假设。因此,没有任何假设可以被破解以导致写 - 写冲突。

最重要的是,无论如何,您都可以获得一致性的安全优势。在发出第一个事务性读取之前,强制执行该一致性不需要时间戳。