Transactions 在同一资源上具有悲观锁的并行事务
我有以下代码:Transactions 在同一资源上具有悲观锁的并行事务,transactions,jboss7.x,oracle12c,java-ee-7,pessimistic-locking,Transactions,Jboss7.x,Oracle12c,Java Ee 7,Pessimistic Locking,我有以下代码: @实体 公开课Foo{ @身份证 私人长id; 私人身份; //接球手和接球手 } @适用范围 公共类存储库{ @PersistenceContext(unitName=“fooPU”) 私人实体管理者; 公共Foo-get(长id){ 返回em.find(Foo.class,id); } //我加的 公共Foo getAndLock(长id){ Map props=newhashmap(); put(“javax.persistence.query.timeout”,6000
@实体
公开课Foo{
@身份证
私人长id;
私人身份;
//接球手和接球手
}
@适用范围
公共类存储库{
@PersistenceContext(unitName=“fooPU”)
私人实体管理者;
公共Foo-get(长id){
返回em.find(Foo.class,id);
}
//我加的
公共Foo getAndLock(长id){
Map props=newhashmap();
put(“javax.persistence.query.timeout”,60000);
返回em.find(Foo.class,id,LockModeType.悲观的_-WRITE,props);
}
公共Foo更新(Foo f){
返回em.merge(f);
}
}
@无国籍
公共类餐饮服务{
@注入
私人食物储存库;
公共无效数据集(长id){
系统输出控制台(“试图锁定”);
Foo f=fooRepository.getAndLock(id);
System.out.println(“已锁定,状态为=“+f.getStatus()”);
如果(f.getStatus()==200){
dostufwithfoo(f);
}
}
私人无效doStuffWithFoo(Foo f){
//慢代码,500-5000毫秒
System.out.println(“做繁重的工作”);
f、 固定状态(400);
更新(f);
System.out.println(“完成,新状态为=“+f.getStatus()”);
}
}
@WebServlet(name=“…”,urlPatterns={“…”})
公共类FooServlet扩展了AbstractServlet{
@注入
私人餐饮服务;
@凌驾
公共无效数据集(HttpServletRequest请求、HttpServletResponse响应){
System.out.println(“在servlet中”);
doStuff(Long.parseLong(req.getParameter(“fooId”));
}
}
额外资料:
- persistence.xml将事务类型定义为
(因此,容器管理)JTA
- 数据源上的事务隔离级别(在JBoss中设置)设置为默认值(在web界面中显示为空,但我认为是
)REPEATABLE\u READ
fooId
参数调用servlet将从数据库中获取匹配的Foo
实例,并且只有当它的状态==200
时,它才应该执行dostufwithfoo
。此方法通常需要相对较长的时间,但最终应该更新该函数的状态oo实例到400
(在快乐路径中)
当两个请求几乎同时调用servlet时会出现问题:两个请求都获得了正确的Foo
实例,但由于它们都看到状态200
,因此都执行dostufwithfoo
。这不应该发生
我尝试使用一个悲观的\u WRITE
锁来解决这个问题(在名为get
的服务之前,我在存储库中添加了getAndLock
方法)。据我所知,这个锁应该可以防止第二个请求读取数据,只要它被锁定,并且(由于超时)等待锁释放后再继续(如果需要等待太长时间,则抛出超时)
但是,在测试时,我注意到日志中打印了以下内容:
in servlet
in servlet
attempting to lock
attempting to lock
got lock, status is = 200
doing heavy work
done, new status is = 400
got lock, status is = **200**
doing heavy work
done, new status is = 400
因此,锁似乎在处理对doStuffWithFoo
的访问顺序,但我不明白的是,为什么第二个调用从数据库中读取状态为200
,而我预期它是400。我认为锁的全部目的是确保不会发生这种情况
我觉得使用JEE应该可以做到这一点,但我的配置中缺少了一些东西。我的问题是:我可以做些什么来确保第二个请求读取更新的状态(400),最好没有:
- 对实体/数据库的更改(添加一个或多个字段,如版本)
- 强制不相关的调用(具有不同foo id的servlet调用)彼此等待
- 在
方法中添加update
,但这没有效果em.flush
- 将事务隔离级别设置为
和READ_UNCOMMITTED
,但在这两种情况下,这都会中断数据源(无法再连接到数据库,我怀疑jdbc驱动程序不支持它)READ_COMMITTED