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
    READ_COMMITTED
    ,但在这两种情况下,这都会中断数据源(无法再连接到数据库,我怀疑jdbc驱动程序不支持它)
注意:这不是我的代码,这是一个遗留项目,我被要求做一些事情来解决两个快速连续的请求导致冲突的事实。我发现关于代码的一些问题,但进行重构或重写不是一个现实的选择