当谈到锁定弹簧jpa时,我真的很不安全 因此,请将此问题视为一个澄清。我真的希望我理解它是正确的,但我的英语对于理解复杂的博客文章并不是那么好 所以这就是我认为我从一些文章中得到的:
锁定有两种基本类型:
第一个问题:到目前为止这是否正确?当我现在想测试这个knollage时,我可以在这个LockModeType之间做出选择:
为什么现在有这么多子锁,他们做了什么?当" OPTIMISTIC"是我试图理解的顶级乐观锁,然后是" OPTIMISTIC_FORCE_INCEMENT"?
版本更新与此有何关系? (或@version
?)
继续:
Spring jpa中有三种锁的基本用法:
在普通列上,例如:
@Entity
public class PersonEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Lock(LockModeType.PESSIMISTIC_WRITE)
private String name;
}
在另一个表的外键上,例如:
@Entity
public class PersonEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Lock(LockModeType.PESSIMISTIC_WRITE)
@OneToOne
private Group group;
}
在存储库内的表上,例如:
interface PersonRepository extends Repository<Person, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Person findOne(Long id);
}
使用
直接锁定实体@Entity
@Lock(LockModeType.PESSIMISTIC_WRITE)
public class PersonEntity { }
是不可能的。因此,您可以使用3(锁定在存储库中)。
第二个问题:这是对的吗?我忘了使用锁定吗?
继续:
锁定背后的想法是,其他方法/进程必须等到锁被释放(除了乐观锁,这里抛出错误)。
只要实例/对象处于活动状态或直到下一次提交,Lock就会存在
解锁对象有两种主要的可能性:
在交易中:在此完整方法中,锁定处于活动状态。但是当返回时,锁将被移除。
@Transactional
public void test(){
System.out.println("start, but not locked yet");
PersonEntity person1 = personRepository.findOne(1L); // locks this person or must wait, when locked
System.out.println("now locked");
// do something
return true; // now the lock will be deleted -> unlocked again
}
直到删除对象:选择对象时数据将被锁定,删除对象时数据将被解锁。
public void test(){
System.out.println("start, but not locked yet");
PersonEntity person1 = personRepository.findOne(1L); // locks this person or must wait, when locked
System.out.println("now locked");
// do something
person1 = null; // now the lock will be deleted -> unlocked again
System.out.println("not locked anymore");
// do something more
return true;
}
第三个问题:到目前为止这是正确的吗?这个功能真的可以等待数据被锁定吗?当对象设置为null
时,是否可以删除锁?
最后的话:
我真的希望我不会惹恼别人。但就像我说的那样:我很难理解英语中这种复杂的结构:(
非常感谢任何形式的帮助:)我真的很感激任何帮助。无论你是否给我链接以便更多地理解或直接回答我的问题:)
答案 0 :(得分:4)
锁定
锁定用于防止脏读(读取未提交的数据)和不可重复的读取(读取在一次读取完成之前被另一个事务删除的数据)。
乐观
乐观锁定将在提交事务时锁定资源。乐观锁定将在第一次访问时保存数据的状态。因此,在乐观锁定中,您可以进行并发访问。如果要执行乐观操作,则在操作之前将初始状态与当前状态进行比较。如果存在差异(资源在此期间已被修改),则不会提交事务。
乐观的力量增量
对于版本化对象,这将增加对象的版本号。在非版本化对象上,将抛出异常。
悲观
悲观阅读
对于可重复读取,用于确保读取之间不更新数据。它是一个共享锁,意味着不同的进程可以执行读操作(不允许写操作)。
悲观写作
强制序列化更新的独占锁。乐观锁定只保存状态,这里它被锁定以防止在并发操作发生这种情况时发生事务失败/死锁。
悲观写入力增量
类似于它的乐观对手,一个更新对象版本的悲观写作。为非版本化对象引发异常。
答案 1 :(得分:0)
关于最后一点-删除一行是否会解除该行的锁定-我认为不会。删除本身只会在事务结束时提交;请注意,如果整个交易回滚,则删除也会回滚。
答案 2 :(得分:0)
我遇到了您遇到的所有这些问题,我正在发布一个示例,如果有帮助,我实际上会尝试过。我有一个设备实体,一个设备状态实体(与设备一对一),一个配置实体(与设备一对多)。我有两条用于更新设备状态的路径(通过mqtt消息处理程序和http请求)。
以下方法在我的DeviceStatus存储库中
@Lock(LockModeType.PESSIMISTIC_WRITE)
DeviceStatus findByDeviceMacAddress(String macAddress); //used by the mqtt handler
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<DeviceStatus> findByDeviceConfigurationId(Long deviceConfigurationId); //used by the http request handler
如果http请求处理程序首先调用findByDeviceConfigurationId
,则将获取PESSIMISTIC_WRITE,直到事务完成为止,mqtt处理程序无法获取对findByDeviceMacAddress
的PESSIMISTIC_WRITE锁(两个处理程序都试图检索相同的DeviceStatus实体)。这意味着对findByDeviceMacAddress
的调用将等待,直到http请求处理程序完成事务为止。同样,如果mqtt处理程序是第一个调用findByDeviceMacAddress
的处理程序,则http请求处理程序将不得不等待,直到mqtt处理程序完成其事务。
我知道这不是一个完整的答案,但认为这可能会对您有所帮助。