Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何避免两个不同的线程从DB(Hibernate和Oracle 10g)读取相同的行_Java_Oracle_Hibernate_Transactions_Locking - Fatal编程技术网

Java 如何避免两个不同的线程从DB(Hibernate和Oracle 10g)读取相同的行

Java 如何避免两个不同的线程从DB(Hibernate和Oracle 10g)读取相同的行,java,oracle,hibernate,transactions,locking,Java,Oracle,Hibernate,Transactions,Locking,假设我有两个不同的线程,T1和T2,同时访问同一个数据库并从同一个表中获取数据 现在,在线程启动时,我需要从表中获取数据并将行存储到集合中,然后使用该集合在其他地方执行一些工作。我不希望两个线程能够处理相同的数据,因为这将导致重复(和长时间)的工作。更具体地说,这是一个企业应用程序,需要在启动时加载一些记录,并将其存储在集合中以执行一些额外的工作。问题在于,在集群环境中,这可能会导致两个不同的实例加载相同的数据,因此工作可能会重复。因此,我希望单个实例只加载一次行 我如何避免这种情况 我目前正在

假设我有两个不同的线程,T1和T2,同时访问同一个数据库并从同一个表中获取数据

现在,在线程启动时,我需要从表中获取数据并将行存储到集合中,然后使用该集合在其他地方执行一些工作。我不希望两个线程能够处理相同的数据,因为这将导致重复(和长时间)的工作。更具体地说,这是一个企业应用程序,需要在启动时加载一些记录,并将其存储在集合中以执行一些额外的工作。问题在于,在集群环境中,这可能会导致两个不同的实例加载相同的数据,因此工作可能会重复。因此,我希望单个实例只加载一次行

我如何避免这种情况

我目前正在使用Hibernate和Oracle 10g。以下是我迄今为止的解决方案:

  • 以编程方式锁定行。第一个读取它的线程将某个“locked”列设置为true,但如果第一个线程在没有将行设置为“processed”的情况下死亡,则很可能发生死锁

  • 使用悲观锁定。我尝试了LockMode.UPGRADE,但似乎没有帮助,因为我仍然能够同时从两个线程读取数据

公共列表getAllNtfFromDb(){ Session Session=HibernateUtil.getOraclesessionfactory().openSession(); Query q=session.createQuery( “来自MyObject n,其中n.state='NEW'”; List=(List)q.List();
对于(int i=0;i,您需要在查询时使用
悲观\u WRITE

Query q = session
    .createQuery("from MyObject n where n.state = 'NEW'")
    .setLockOptions(new LockOptions(LockMode.PESSIMISTIC_WRITE));
List<MyObject> list = (List<MyObject>) q.list();
Query q=session
.createQuery(“来自MyObject n,其中n.state='NEW')
.setLockOptions(新的LockOptions(LockMode.悲观写入));
List=(List)q.List();
锁定父对象就足够了。死锁不一定会发生。如果持有锁的线程没有在另一个线程超时等待之前释放锁,则可能会导致锁获取失败

由于您使用的是Oracle,因此工作原理如下:

选择…作为更新锁定行和任何关联索引 条目,与为这些行发出UPDATE语句相同。 其他事务被阻止更新这些行,无法执行 选择…在共享模式下锁定,或从特定模式下读取数据 事务隔离级别。一致读取忽略在上设置的任何锁 存在于读取视图中的记录。(记录的旧版本) 无法锁定;它们是通过在 内存中记录的副本。)

因此,如果T1获得了某些行的独占锁,T2将无法读取这些记录,直到T1提交或回滚。如果T2使用隔离级别,则T2将永远不会阻塞锁记录,因为它只是使用撤消日志来重建数据,就像查询开始时一样。与SQL标准相反,Oracle read_UNCOMMITTED将:

为了提供一致或正确的答案,Oracle数据库将 创建包含此行的块的副本,该行在 查询开始了…实际上,Oracle数据库绕道了 修改了它周围读取的数据,并从撤消中重建数据 (也称为回滚)段。一致且正确的答案 在不等待事务提交的情况下返回


也许可以使用select for update语句?能否提供此行使用的Hibernate导入:
Session Session=HibernateUtil.getOraclesessionfactory().openSession()
好的,谢谢,这确实有效,但只有当两个线程试图在时间上非常接近的情况下读取相同的数据时才有效。如果T1读取数据,并且在1分钟后T2读取相同的数据(T1很可能仍在处理),则T2能够看到行。我想锁定行,直到它们被更新(例如,状态列设置为“Ok”,或者“已处理”)。此外,更新一个实体是否会自动释放行?如果会话关闭或线程崩溃,是否会在超时后释放行?非常感谢。这可能取决于基础数据库独占锁支持。
Query q = session
    .createQuery("from MyObject n where n.state = 'NEW'")
    .setLockOptions(new LockOptions(LockMode.PESSIMISTIC_WRITE));
List<MyObject> list = (List<MyObject>) q.list();