Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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 为线程间的并发性锁定数据库记录_Java_Mysql_Database_Hibernate_Concurrency - Fatal编程技术网

Java 为线程间的并发性锁定数据库记录

Java 为线程间的并发性锁定数据库记录,java,mysql,database,hibernate,concurrency,Java,Mysql,Database,Hibernate,Concurrency,我敢肯定,这种事情已经做了一百万次了,但是我的search foo今天看起来很弱,我想听听大家对实现这一目标的最佳方式的看法 我的应用程序跟踪系统中在线用户的会话。每个会话对应于数据库中的一条记录。会话可以通过以下两种方式之一结束。接收到“停止”消息,或者会话可能超时。前一种情况很简单,在消息处理线程中处理,一切正常。后一种情况才是问题的根源 为了处理超时,每个记录都有一个结束时间列,该列在每次收到该会话的消息时更新。为了使超时工作,我有一个线程,它返回数据库中endtime

我敢肯定,这种事情已经做了一百万次了,但是我的search foo今天看起来很弱,我想听听大家对实现这一目标的最佳方式的看法

我的应用程序跟踪系统中在线用户的会话。每个会话对应于数据库中的一条记录。会话可以通过以下两种方式之一结束。接收到“停止”消息,或者会话可能超时。前一种情况很简单,在消息处理线程中处理,一切正常。后一种情况才是问题的根源

为了处理超时,每个记录都有一个结束时间列,该列在每次收到该会话的消息时更新。为了使超时工作,我有一个线程,它返回数据库中endtime 我可以使用信号灯或类似的东西,在超时发生时阻止消息线程处理,因为它只需要每30秒或每分钟运行一次。但是,随着用户表变大,这将遇到一些严重的性能问题。我想我想要的是一种在消息线程中知道超时线程当前正在处理该记录的方法。如果我能做到这一点,我可以放弃消息或等待超时线程结束,但只有在冲突的情况下,而不是总是现在


目前我的应用程序直接使用JDBC。如果我使用Hibernate这样的框架,是否会有一种更简单/标准的方法来解决这个问题?

这是一个发生各种疯狂错误的好机会,一些解决方法可能会导致性能问题

经典的解决方案是使用事务(http://dev.mysql.com/doc/refman/5.0/en/commit.html). 这使您能够保证数据的一致性,但数据库上长时间运行的事务会将其变成一个巨大的瓶颈;如果“查找超时会话”代码运行一分钟,事务可能会在整个时间段内运行,从而有效地锁定对受影响表的写访问。大多数系统都不能很好地处理这个问题

对于这种情况,我最喜欢的解决方案是为状态设置一个“状态机”;我喜欢将其实现为历史记录表,但这确实会导致数据库的快速增长

您将会话的状态定义为“已启动”、“正在运行”、“超时-关闭”、“超时-关闭”和“已由用户停止”(例如)

您实现的代码在任何数据访问逻辑中都遵循状态转换逻辑。“清理”脚本的伪代码可能是:

  • 更新endtime
  • 对于状态为“超时-关闭”的每条记录
    • 做任何你需要做的事情
    • 更新该记录以设置状态“超时-关闭”,其中status=“超时-关闭”
  • 下一张唱片
所有其他修改会话记录当前状态的尝试都必须检查当前状态是否对尝试的更改有效

例如,“手动”停止代码应如下所示:

update sessions
set status = "stopped by user"
where session_id = xxxxx
and status = 'running'
如果自动关闭例程在显示用户界面和数据库代码之间启动,where子句将不匹配任何记录,因此代码的其余部分根本不会运行

要使其工作,所有修改会话状态的代码都必须检查其前置条件;最可维护的方法是将状态和允许的转换编码到单独的数据库表中

您也可以编写触发器来强制执行此逻辑,尽管我通常不喜欢触发器-只有在必要时才这样做


我不认为这会增加显著的性能问题,但需要测试和优化“更新声明的条款;假设您有一个状态索引,它不太可能产生可测量的影响。

您可以通过会话ID而不是在线程级别包装信号量,因此在消息处理程序和超时线程的关闭部分中有同步(sessionID)块。我不认为它像您希望的那样干净,但是它对性能的影响比在单个信号量上锁定整个线程要小,因为只有该会话的消息会被阻塞。这到底是如何工作的?我的理解是,这将锁定对象sessionID,而不是sessionID的值。由于在DB读取之后的两个线程中创建的对象不是同一个对象,因此它似乎永远不会阻塞。如果您有一个锁对象的字段,并且在同步块之前从两个线程更新了它,那么您在并发性方面也会遇到与之前相同的问题,只是焦点切换到锁对象。除非有办法在我不知道的值上同步块,否则答案会根据您的结构而变化。如果您有mysession.handleMessage(x)和mysession.closeAndCleanup(),您应该能够锁定mysession。然后,竞争条件是,如果在会话被标记为关闭后但在到达同步块之前收到消息,则将处理该消息,会话关闭或会话关闭,并且该消息将返回有关超时的错误。如果结构是handlemessage(ID,msg)和close(ID),其中ID只是一个int,那么您需要一个映射或一些东西来同步