Adj*_*ion 29 java concurrency locking optimistic-locking
我早上花了很多时间阅读谷歌在乐观锁定方面所做的所有热门文章,而对于我的生活,我仍然没有真正理解.
我理解乐观锁定涉及添加用于跟踪记录的"版本"的列,并且该列可以是时间戳,计数器或任何其他版本跟踪构造.但我仍然不明白如何确保WRITE完整性(意味着如果多个进程同时更新同一个实体,那么之后,实体正确地反映了它应该处于的真实状态).
有人可以提供一个具体的,易于理解的例子,说明如何在Java中使用乐观锁定(可能是MySQL数据库).假设我们有一个Person实体:
public class Person {
private String firstName;
private String lastName;
private int age;
private Color favoriteColor;
}
Run Code Online (Sandbox Code Playgroud)
并且这些Person实例会持久化到peopleMySQL表:
CREATE TABLE people (
person_id PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL, # } I realize these column defs are not valid but this is just pseudo-code
age INT NOT NULL,
color_id FOREIGN KEY (colors) NOT NULL # Say we also have a colors table and people has a 1:1 relationship with it
);
Run Code Online (Sandbox Code Playgroud)
现在假设有2个软件系统或1个系统,其上有2个线程,它们试图同时更新同一个Person实体:
people和/或colors表上实现乐观锁定?(寻找特定的DDL示例)people/ colorstable"吗?基本上,我希望看到乐观的锁定动作,并简单地解释它为何起作用.The*_*tor 41
通常,当您研究乐观锁定时,您还可以使用像Hibernate这样的库或其他@Version支持JPA的实现.
示例可以如下所示:
public class Person {
private String firstName;
private String lastName;
private int age;
private Color favoriteColor;
@Version
private Long version;
}
Run Code Online (Sandbox Code Playgroud)
显然,@Version如果您没有使用支持此功能的框架,则无需添加注释.
那么DDL就可以了
CREATE TABLE people (
person_id PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL, # } I realize these column defs are not valid but this is just pseudo-code
age INT NOT NULL,
color_id FOREIGN KEY (colors) NOT NULL, # Say we also have a colors table and people has a 1:1 relationship with it
version BIGINT NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
要完成这两个步骤而不冒其他进程在两个步骤之间更改数据的风险,通常会通过类似的语句来处理
UPDATE Person SET lastName = 'married', version=2 WHERE person_id = 42 AND version = 1;
Run Code Online (Sandbox Code Playgroud)
执行语句后,检查是否更新了一行.如果你这样做了,那么没有其他人在你阅读之后就改变了数据,否则其他人就改变了数据.如果其他人更改了数据,您通常会收到OptimisticLockException您正在使用的库.
此异常应导致撤消所有更改,并且更改要重新启动的值的过程可能不再适用于实体更新的条件.
所以没有碰撞:
碰撞:
如果Color是另一个对象,你应该在同一个方案中放置一个版本.
OptimisticLockExceptions如果许多不同的应用程序访问您的数据,您最好使用数据库自动更新的列.例如,对于MySQL
version TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
Run Code Online (Sandbox Code Playgroud)
这样,实现乐观锁定的应用程序将注意到哑应用程序的变化.
如果更新实体的频率高于其解析TIMESTAMP或Java解释,则该方法可能无法检测到某些更改.此外,如果您让Java生成新的,TIMESTAMP您需要确保运行应用程序的所有计算机都处于完美的时间同步状态.
如果您的所有应用程序都可以更改整数,长,...版本通常是一个很好的解决方案,因为它永远不会受到不同设置时钟的影响;-)
还有其他方案.例如,您可以使用哈希值,甚至可以在String每次更改行时随机生成哈希值.重要的是,当任何进程保存本地处理数据或缓存内部时,您不会重复值,因为该进程将无法通过查看版本列来检测更改.
作为最后的手段,您可以使用所有字段的值作为版本.虽然这在大多数情况下是最昂贵的方法,但它是一种在不改变表结构的情况下获得类似结果的方法.如果您使用Hibernate,则会有@OptimisticLocking-annotation来强制执行此行为.使用@OptimisticLocking(type = OptimisticLockType.ALL)的实体类,如果任何行更改,因为您已经阅读实体或失效@OptimisticLocking(type = OptimisticLockType.DIRTY)时,另一个进程改变了你改变的字段只失败了.