对J2EE中死锁问题的研究 - 编程入门网
形之2:单线程、多冲突数据库连接
对同一线程执行嵌套的EJB调用时还会出现第二种跨资源死锁情形,此情形即使在非高负载系统中通常也会发生。同上面的示例一样,两个EJB调用使用不同的连接来连接到同一个数据库。因为只有嵌套调用完成后调用方才能继续,所以调用方的数据库连接实际上被嵌套调用的数据库连接阻塞了,虽然数据库没有注意到这种关系。如果第一个(外部)连接已获取第二个(内部)连接所需要的数据库锁,则第二个连接将永久阻塞第一个连接,并等待第一个连接被提交或回滚,这就出现了死锁情形。因为数据库没有注意到两个连接之间的关系,所以数据库不会将此情形检测为死锁。 作为一个具体的示例,考虑一个数据加载EJB调用。此EJB调用获取一个大型对象,并在不同阶段中将其保存在数据库中。当它执行数据加载时,它会更新一个单独的表,以记录挂起数据加载操作的状态。我们希望状态更新立即可见,但不希望在未完成的状态下看到加载的数据,所以要通过调用“RequiresNew” EJB来完成。总的来说,这种不完善的数据加载方法如清单1中的代码所示。 清单1 对J2EE中死锁问题的研究(3)时间:2011-01-05 bea Michael Nonemacher在上面的示例中,使用updateBatchStatus方法执行“RequiresNew” EJB调用实际上可以更新batch_status数据库表,即使没有看到当前事务的效果,也能立即看到状态的改变。对executeUpdate的调用不是EJB调用,所以它和bulkLoadData的其他部分在同一个事务中执行。 如上所述,即使不存在并发,此代码也将导致死锁。当bulkLoadData调用executeUpdate方法时,它更新现有的数据库行,这涉及为该行获取写锁。对updateBatchStatus的嵌套EJB调用将在单独的数据库连接上执行,并尝试执行一个非常相似的查询,但它将阻塞,因为不能获取必需的写锁。从数据库的角度来说,只要提交或回滚第一个连接的事务,第二个连接就可以继续。但是,Java虚拟机不允许在完成所有对updateBatchStatus的调用前完成bulkLoadD调用,这样就出现了死锁情形。 该示例表明,一个更新会阻塞另一个更新,所以它会在任何数据库中导致死锁。如果初始更新查询是一个简单的选择查询,那么该示例仅在使用基于锁的并发控制的数据库上导致死锁,在这种数据库中,一个连接的读锁可以阻止另一个连接获取写锁。不管在哪种情况下,此类死锁即不依赖于同步,也不依赖于负载,而且线程转储将显示一个等待数据库响应的Java线程,但该线程与两个有效的数据库连接相关联。在这些数据库连接中,有一个将处于空闲状态,但会阻塞其他连接。 此情形有多种具体的变种,可以涉及多个线程和两个以上的数据库连接。例如,外部EJB调用的数据库连接可能已经获取了数据库锁,该锁阻塞了另一个无关数据库连接的继 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |