java 弹簧 JPA 锁

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35523428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 00:12:55  来源:igfitidea点击:

Spring JPA Lock

javaspringhibernatejpa

提问by christopher2007

I am really insecure when it comes to locking in spring jpa.
So please consider this question as an clarification. I really hope I understood it correct, but my english is not so good for understanding complex blog posts.
So this is what I think I got from some articles:

在锁定 spring jpa 时,我真的很不安全。
因此,请将此问题视为澄清。我真的希望我理解正确,但我的英语不太适合理解复杂的博客文章。
所以这就是我认为我从一些文章中得到的:

There are two basic types of locking:

有两种基本类型的锁定:

  • optimisticshould be used when less write operation are planned. read operation will not lock an object.
    For example: You have an "money balance" float in an entity with an optimistic lock. Now two processes read this value and use it for calculating and stuff. One of them now changes the value and writes it to the database with an update. No error to this point.
    But now the other process also changes the value and wants to update it. Now there is an error. This only happened because of the second update.
    If the second process would have deleted the instance, nothing would have happend.
  • pessimisticshould be used when much write operation are planned. read operation will lock an object.
    For example: You have an "money balance" float in an entity with an pessimistic lock. One process reads the data/value with "findOne".
    After this, an other process wants to read the data as well, what would be possible with an optimistic lock, but with the pessimistic lock he must now wait (no error, just wait).
    When process 1 is ready (changing the value and updating it), process 2 can go on.
  • 当计划较少的写操作时应该使用乐观。读操作不会锁定对象。
    例如:您在具有乐观锁的实体中有一个“货币余额”浮动。现在有两个进程读取这个值并将其用于计算和填充。其中之一现在更改值并将其写入数据库并进行更新。到此为止没有错误。
    但是现在另一个进程也改变了这个值并想要更新它。现在有一个错误。这只是因为第二次更新而发生的。
    如果第二个进程会删除该实例,则什么也不会发生。
  • 当计划大量写操作时,应该使用悲观。读操作会锁定一个对象。
    例如:您在一个带有悲观锁的实体中有一个“货币余额”浮动。一个进程使用“findOne”读取数据/值。
    在此之后,另一个进程也想读取数据,使用乐观锁是可能的,但是使用悲观锁他现在必须等待(没有错误,只需等待)。
    当进程 1 准备好(更改值并更新它)时,进程 2 可以继续。

First Questions: Is this correct so far? And when I now want to test this knollage, I can choose between this LockModeType's:

第一个问题:到目前为止,这是正确的吗?当我现在想测试这个 knollage 时,我可以在这个 LockModeType 之间进行选择:

  • OPTIMISTIC
  • OPTIMISTIC_FORCE_INCREMENT
  • PESSIMISTIC_READ
  • PESSIMISTIC_WRITE
  • PESSIMISTIC_FORCE_INCREMENT
  • 乐观的
  • OPTIMISTIC_FORCE_INCREMENT
  • 悲观_阅读
  • 悲观_写
  • 悲观_FORCE_INCREMENT

Why are there now so many sub-locks and what do they do? When "OPTIMISTIC" is the optimistic lock from the top I tried to understand, then what is "OPTIMISTIC_FORCE_INCEMENT"?
And what does an version update has to do with this? (or the @version?)

为什么现在有这么多子锁,它们有什么作用?当“OPTIMISTIC”是我试图理解的顶部乐观锁时,那么“OPTIMISTIC_FORCE_INCEMENT”是什么?
版本更新与此有什么关系?(或@version?)

Going on:
There are three basic uses of lock in Spring jpa:

继续:
Spring jpa中lock的三种基本用途:

  1. on a normal column, for example:

    @Entity
    public class PersonEntity {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        private String name;
    }  
    
  2. on a foreign key to an other table, for example:

    @Entity
    public class PersonEntity {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        @OneToOne
        private Group group;
    }  
    
  3. on a table inside a repository, for example:

    interface PersonRepository extends Repository<Person, Long> {
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        Person findOne(Long id);
    }  
    
  1. 在普通列上,例如:

    @Entity
    public class PersonEntity {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        private String name;
    }  
    
  2. 在另一个表的外键上,例如:

    @Entity
    public class PersonEntity {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        @OneToOne
        private Group group;
    }  
    
  3. 在存储库内的表上,例如:

    interface PersonRepository extends Repository<Person, Long> {
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        Person findOne(Long id);
    }  
    

Locking a Entity directly with

直接锁定实体

@Entity
@Lock(LockModeType.PESSIMISTIC_WRITE)
public class PersonEntity { }

is not possible. Therefore you can use 3 (locking inside a repository).

不可能。因此,您可以使用 3(锁定在存储库内)。

Second Question: Is this correct? Did I forgot about a use of a locking?

第二个问题:这是正确的吗?我忘记使用锁了吗?

Going on:
The idea behind locking is, that other methods/processes have to wait until a lock is released (except by the optimistic lock, here a error is thrown).
The Lock is there as long as the instance/object is active or until the next commit.
There are two main possibilities to unlock an object:

继续:
锁定背后的想法是,其他方法/进程必须等到锁被释放(除了乐观锁,这里会抛出错误)。
只要实例/对象处于活动状态或直到下一次提交,锁就会存在。
解锁对象有两种主要可能性:

  1. Within an transaction: In this full method the lock is active. But when the return comes, the lock will be removed.

    @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
    }  
    
  2. until the object is deleted: The data will be locked when the object is selected, and the data will be unlocked when the object is deleted.

    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;
    }  
    
  1. 在事务中:在这种完整方法中,锁处于活动状态。但是当返回来时,锁就会被解除。

    @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
    }  
    
  2. 直到对象被删除:选择对象时数据将被锁定,删除对象时数据将解锁。

    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;
    }  
    

Third Questions: is this correct so far? Does this function really can wait then the data is locked? Can an lock really be deleted when the object is set to null?

第三个问题:到目前为止,这是正确的吗?这个功能真的可以等待然后数据被锁定吗?当对象设置为 时,真的可以删除锁null吗?

Last words:
I really hope I will not annoy somebody. But like I said: it is really difficult for me to understand such complex structures in the english language :(
So thanks a lot for help in any form :) I really appreciate any little help. regardless of whether you give me links for more understanding or answering my questions directly :)

遗言:
我真的希望我不会惹恼任何人。但就像我说的:我真的很难理解英语中如此复杂的结构:(
所以非常感谢任何形式的帮助:)我真的很感激任何一点帮助。无论您是给我链接以加深理解还是直接回答我的问题:)

回答by William Burnham

Locking

锁定

Locking is used to prevent dirty reads (reading data that hasn't been committed) and non-repeatable reads (reading data that gets deleted by another transaction before the one reading is finished).

锁定用于防止脏读(读取尚未提交的数据)和不可重复读取(读取在一次读取完成之前被另一个事务删除的数据)。

Optimistic

乐观的

Optimistic locking will lock a resource when committing the transaction. Optimistic locking will save the state of the data at the first access. As such, in optimistic locking you have the possibility of concurrent access. If an optimistic operation is to be performed, before the operation the initial state is compared to the current state. If there is a discrepancy (the resource has been modified in the meantime), the transaction is not committed.

乐观锁定将在提交事务时锁定资源。乐观锁会在第一次访问时保存数据的状态。因此,在乐观锁定中,您有可能进行并发访问。如果要执行乐观操作,则在操作之前将初始状态与当前状态进行比较。如果存在差异(资源在此期间已被修改),则不会提交事务。

Optimistic force increment

乐观力增量

For versioned objects, this will increment the object's version number. On non-versioned objects an exception will be thrown.

对于版本化对象,这将增加对象的版本号。在非版本化对象上,将抛出异常。

Pessimistic

悲观

Pessimistic read

悲观阅读

For repeatable reads, used to ensure that data isn't updated between reads. It is a shared lock meaning different processes can perform read operations (no write operations are permitted).

对于可重复读取,用于确保在读取之间不会更新数据。它是一个共享锁,意味着不同的进程可以执行读操作(不允许写操作)。

Pessimistic write

悲观写

An exclusive lock which forces serialization of updates. Where optimistic locking only saved state, here it is locked to prevent transaction failure/deadlock in cases where this would happen with concurrent operations.

强制更新序列化的排他锁。乐观锁定只保存状态,这里它被锁定以防止在并发操作发生这种情况的情况下事务失败/死锁。

Pessimistic write force increment

悲观写入力增量

Analogous to its optimistic counterpart, a pessimistic write that updates the object's version. Throws an exception for non-versioned objects.

类似于它的乐观对应物,更新对象版本的悲观写入。对非版本化对象抛出异常。

回答by nabeel

Regarding the last point - whether deleting a row will take off the lock on the row - i think, it will not. The delete itself will get committed only at the end of the transaction; note that if the whole transaction rolls back, the delete also rolls back.

关于最后一点——删除一行是否会解除对行的锁定——我认为不会。删除本身只会在事务结束时提交;请注意,如果整个事务回滚,则删除也会回滚。