关于J2EE中死锁问题的研究
http://tech.ddvip.com 2006年11月21日 社区交流
本文详细介绍关于J2EE中死锁问题的研究
跨资源死锁情形之2:单线程、多冲突数据库连接
对同一线程执行嵌套的EJB调用时还会出现第二种跨资源死锁情形,此情形即使在非高负载系统中通常也会发生。同上面的示例一样,两个EJB调用使用不同的连接来连接到同一个数据库。因为只有嵌套调用完成后调用方才能继续,所以调用方的数据库连接实际上被嵌套调用的数据库连接阻塞了,虽然数据库没有注意到这种关系。如果第一个(外部)连接已获取第二个(内部)连接所需要的数据库锁,则第二个连接将永久阻塞第一个连接,并等待第一个连接被提交或回滚,这就出现了死锁情形。因为数据库没有注意到两个连接之间的关系,所以数据库不会将此情形检测为死锁。
作为一个具体的示例,考虑一个数据加载EJB调用。此EJB调用获取一个大型对象,并在不同阶段中将其保存在数据库中。当它执行数据加载时,它会更新一个单独的表,以记录挂起数据加载操作的状态。我们希望状态更新立即可见,但不希望在未完成的状态下看到加载的数据,所以要通过调用“RequiresNew” EJB来完成。总的来说,这种不完善的数据加载方法如清单1中的代码所示。
清单1public void bulkLoadData(DataBatch batch) { 在上面的示例中,使用updateBatchStatus方法执行“RequiresNew” EJB调用实际上可以更新batch_status数据库表,即使没有看到当前事务的效果,也能立即看到状态的改变。对executeUpdate的调用不是EJB调用,所以它和bulkLoadData的其他部分在同一个事务中执行。
int batchId = batch.getId();
// Since this executeUpdate call doesn誸 happen in a separate
// transaction, it wouldn't be visible anyway, but the effect is
// far worse: a cross-resource deadlock.
executeUpdate("update batch_status set status='Started' " +
"where batch_id=" + batchId);
validateData(batch);
updateBatchStatus(batchId, "Validated"); // RequiresNew EJB call
loadDataStage1(batch);
updateBatchStatus(batchId, "Stage 1 complete"); // RequiresNew EJB call
loadDataStage2(batch);
updateBatchStatus(batchId, "Stage 2 complete"); // RequiresNew EJB call
finalizeDataLoad(batch);
updateBatchStatus(batchId, "Complete"); // RequiresNew EJB call
}
来源:bea 作者:Michael Nonemacher 责编:豆豆技术应用