我研究如何解决这个问题已经有一段时间了,但似乎找不到合适的解决方案。
问题是:
我有一个Java EE应用程序,许多用户可以登录,他们会看到一个项目列表,他们可以选择和编辑其中的任何一个。
所有用户都看到相同的项目列表。如前所述,他们可以编辑项目,但我想将编辑功能限制为一个用户。也就是说,许多用户可以同时编辑不同的项目,但只有一个用户可以编辑特定的项目。
当一个用户正在编辑一个项目时,任何其他试图编辑该项目的用户都应该看到一条消息。
我通过将项inUse上的标志设置为true,然后进行检查来实现这一点。当用户通过单击"保存"或"取消"完成项目编辑后,该标志将设置为false。这种方法的问题是要考虑用户打开浏览器或关闭浏览器的情况。
我尝试设置会话超时,但似乎无法实现,因为当会话超时时,我无法访问该项。我只能访问httprequest会话id。
也许这是一种错误的方法,因为这似乎是许多应用程序都会遇到的问题,而且应该存在一个不那么黑客的解决方案。
我研究过使用线程和同步方法,但不知道这将如何工作,因为一旦用户进入编辑项屏幕,该方法就会退出并释放锁。
我发现了这个解决方案,一次只允许一个用户编辑内容,但不确定这是否是Java中的做法。
有没有更优雅的/java解决方案?如果是的话,你能告诉我正确的方向吗?你将如何实现这一点?
谢谢!
解决方案:尽管最初我认为乐观的锁定是可行的,但我很快意识到这对我的环境并不适用。我决定采用悲观锁定的组合(http://www.agiledata.org/essays/concurrencyControl.html#PessimisticLocking)和超时。
当访问一个项目时,我将inUse字段设置为true,并将对象上次访问的字段设置为当前时间。
每次有人试图编辑对象时,我都会检查inUse字段和lastAccessed字段+5分钟。所以基本上,我给5分钟的时间来编辑用户。
就像在数据库中一样,在数据库中使用时间戳。时间戳与记录一起保存,当一个人提交他的编辑时,除非时间戳相同,否则编辑不会进行(这意味着"自我阅读此记录以来,没有发生任何编辑")。然后,当编辑完成时,将创建一个新的时间戳。
首先,在持久层中,您确实应该使用版本/时间戳字段执行乐观锁定。
在UI级别,为了处理您的用例,我会进行资源租赁:
-
在表中添加两个字段:
LAST_LEASE_TIME
:上次租赁时间LAST_LEASE_USER
:上次租用记录的用户
-
当用户尝试编辑您的记录时,首先检查该记录是否未出租,或者租约是否已过期(即租约没有超过指定的租约时间),或者该用户是否是被授予租约的用户。
-
通过您的网络浏览器,定期续订租约,例如使用AJAX调用。
-
当用户结束编辑记录时,明确地使租约过期。
通过租赁,你解决了"关闭浏览器"的问题:在租赁期到期而没有进行任何租赁翻新后,算法会自动"释放"资源。
听起来你可以使用:会话Bean报价:
一般来说,如果以下情况成立,您应该使用会话bean:
在任何给定的时间,只有一个客户端可以访问bean实例。bean的状态不是持久的,只存在很短的一段时间(可能只有几个小时)。
MartinFowler描述了这样一个问题的4种模式:
- 在线乐观锁定
- 在线悲观锁定
- 离线乐观锁定
- 离线悲观锁定
你应该根据你的问题决定使用哪一个。JPA、JDO和Hibernate提供了开箱即用的1和2。Hibernate也可以处理3(我不确定JPA和JDO)。没有人能处理开箱即用的4个问题,你应该自己执行。