我必须在XG事务中生成一个唯一的发票号,其中包括数据模型中的以下3实体组:
这是DAO实现的基本部分(删除了无关的业务规则、检查等):
public void saveInvoice(final Invoice invoice) throws BusinessRuleException {
final Objectify ofy = ObjectifyService.factory().begin().cache(true);
ofy.transact(new Work<Void>() {
@Override
public Void run() {
CustomerSettings customerSettings = ofy.load()
.key(Key.create(CustomerSettings.class, CustomerSettings.ID)).safeGet();
Contact contact = ofy.load().key(createContactKey(invoice.getContactId()).safeGet();
contact.setContactType(ContactType.CLIENT);
ofy.save().entity(contact).now();
String invoiceNumber = generateSequence(ofy, customerSettings);
invoice.setInvoiceNumber(invoiceNumber);
ofy.save().entity(invoice).now();
return null;
}
});
}以及生成下一个序列号的简化版本,其中下一个序列号在下一个调用中增加,CustomerSettings必须通过事务方式更新(我已经同步了,但我想这并不是真正有用的):
private synchronized String generateSequence(Objectify ofy, CustomerSettings settings) {
String ret = "";
int sequence = settings.getNextSequence();
settings.setNextSequence(sequence + 1);
ofy.save().entity(settings).now();
ret = "" + sequence;
return ret;
}这就是我的单元测试对于变量线程计数的情况:
private void test(final int threadCount) throws InterruptedException, ExecutionException {
final Environment currentEnvironment = ApiProxy.getCurrentEnvironment();
Callable<String> task = new Callable<String>() {
@Override
public String call() {
ApiProxy.setEnvironmentForCurrentThread(currentEnvironment);
return generateInvoiceNumber();
}
};
List<Callable<String>> tasks = Collections.nCopies(threadCount, task);
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
List<Future<String>> futures = executorService.invokeAll(tasks);
List<String> resultList = new ArrayList<String>(futures.size());
// Check for exceptions
for (Future<String> future : futures) {
// Throws an exception if an exception was thrown by the task.
resultList.add(future.get());
}
// Validate the IDs
Assert.assertEquals(futures.size(), threadCount);
List<String> expectedList = new ArrayList<String>(threadCount);
for (long i = 1; i <= threadCount; i++) {
expectedList.add("" + i);
}
Collections.sort(resultList);
Assert.assertEquals(expectedList, resultList);
}
@SuppressWarnings("unchecked")
private String generateInvoiceNumber() {
InvoiceDAO invoiceDAO = new InvoiceDAO();
Invoice invoice = ... create a valid invoice
invoiceDAO.saveInvoice(invoice);
log.info("generated invoice number : " + invoice.getInvoiceNumber());
return invoice.getInvoiceNumber();
}例如,当我在32个线程同时运行时:
@Test
public void test32() throws InterruptedException, ExecutionException {
test(32);
},但是后续线程没有看到先前的事务增加了发票编号序列.。
其结果是:
junit.framework.AssertionFailedError: expected:<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32>但was:<1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3>
我已经看过几次文档了,不知道为什么这不管用吗?
如果在事务中访问多个实体组,则具有XG事务的事务。如果您只访问一个,则不会访问。5 EGs的标准限制适用于所有事务。对象化事务文档
我做错什么了?
发布于 2012-10-31 18:38:07
这段代码使代码不具有事务性:
最后的对象化ofy = ObjectifyService.factory().begin().cache(true); Ofy.transact(新工作){.Ofy.save().entity(设置).now(); }
因为我重用了非事务性的objectify实例。要在事务工作中获取实例,您必须始终像这样询问实例:
ObjectifyService.ofy()
更多信息在小组讨论这里。
查看ObjectifyService的实现,您可以看到新的实例被推送/弹出到/从堆栈;
除此之外,测试用例仍未运行。最好的测试方法大概是同时触发http请求;
https://stackoverflow.com/questions/13019565
复制相似问题