【问题标题】:JPA PessimisticLockScope.NORMAL and locking "relationships"JPA PessimisticLockScope.NORMAL 和锁定“关系”
【发布时间】:2014-07-17 14:54:15
【问题描述】:

我正在研究JPA Documentation,遇到以下几行:

锁定实体包含外来实体的实体关系 键也将被锁定,但不是被引用实体的状态 (除非这些实体被明确锁定)。元素集合和 实体不包含外键的关系 (例如映射到联接表的关系或 目标实体的单向一对多关系 包含外键)默认不会被锁定。

来自here (PessimisticLockScope.NORMAL)

我想知道如何解释这些行。如果PessimisticLockScope 设置为EXTENDED,那么连接表中的行也会被锁定(但不是相关实体本身),那么在使用NORMAL 值时会锁定什么?确定实体行(或行,如果继承策略是JOINEDTABLE_PER_CLASS 或如果有SecondaryTable),但什么是“实体关系”:

锁定实体包含外来实体的实体关系 钥匙也将被锁定

PessimisticLockScope.NORMAL的上下文中?

【问题讨论】:

    标签: java hibernate jpa transactions locking


    【解决方案1】:

    实体关系映射到数据库 FK 关联。

    PessimisticLockScope.NORMAL 将发出一个相当激进的数据库独占锁定:

    • 实体分离表行
    • 在连接表继承结构中,基表和子类表都将被锁定
    • 所有具有实际 FK 关系的 @ManyToOne@OneToOne 关联表行(例如带有 @JoinColumn 的一侧)。但这意味着您不能更改 FK 信息,这意味着您不能将其设置为 null 或任何其他不同的值。因此,只有 FK 列值被锁定,而不是其他表关联的 FK 行。

    @OneToMany@ManyToMany 和非拥有的@OneToOne@ManyToOne 关联不会被锁定,因为这些关联只有面向对象的等效项,并且锁定仅在数据库级别发生。

    PessimisticLockScope.EXTENDED 也将扩展为 @OneToMany@ManyToMany 关联。但同样,这仅适用于 FK 列值,而不适用于整行。所以这个锁定将阻止向/从@OneToMany/@ManyToMany 关联添加/删除元素。它不会阻止包含的元素被更新。为此,您必须锁定每个包含的实体。

    【讨论】:

    • 谢谢!它比 JPA 文档中的要清楚得多。
    • 很好的解释@Vlad。您能否就“这仅适用于 FK 列值而不适用于整行”进行更多解释。你的意思是只有一列被锁定而不是行。这个锁是如何转换到数据库的。 AFAIK,锁的粒度是行而不是列,或者这种关系锁定仅在内存中。
    • 我指的是包含 FK 的行(实际上锁定是针对整行,而不仅仅是单个列),而不是 FK 列引用的行。
    • 什么时候可以放注解?对于内置方法,您将在哪里放置注释?
    • 如有疑问,请查看 JavaDoc。 PessimisticLockScope 文档可以回答您的问题。
    【解决方案2】:

    这里有几个关于这个问题的实验。我使用 Hibernate 4.3.6 作为 JPA 提供程序,使用 MySQL 5.6 作为数据库。

    少数测试实体 - TestPerson、TestUser、TestOrder

    TestUser 扩展了 TestPerson(具有 JOINED 继承),并且 TestUser 具有 TestOrders 的双向 OneToMany 列表

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public class TestPerson {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)   
        private long id;
    
        private String name;
        private String address;
    
        //getters and setters
    
    
    
    @Entity
    public class TestUser extends TestPerson {
    
        @OneToMany(fetch=FetchType.LAZY,mappedBy="user")   
        private List<TestOrder> orders ;
    
        //getters and setters
    
    
    @Entity
    public class TestOrder {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)   
        private long id;
    
        @ManyToOne
        @JoinTable(name="test_user_orders")
        private TestUser user;
    
        private String orderNumber ;
    
        //getters and setters**
    

    数据创建代码:

             em.getTransaction().begin();            
             TestUser user = new TestUser();
             user.setName("TestUser"+System.currentTimeMillis());
             user.setAddress("TestUserAddress1");
             em.persist(user);
             List<TestOrder> orders = new ArrayList();
             for (int i=1;i<6;i++){
             TestOrder order = new TestOrder();
             order.setOrderNumber("ON"+System.currentTimeMillis());
             order.setUser(user);
             em.persist(order);
             orders.add(order);
             }
             user.setOrders(orders);
    
             em.getTransaction().commit();
             em.close();
    
    
    
    
    mysql> select * from test_person;
    +----+------------------+-----------------------+
    | id | address          | name                  |
    +----+------------------+-----------------------+
    |  1 | TestUserAddress1 | TestUser1406031063539 |
    +----+------------------+-----------------------+
    1 row in set (0.00 sec)
    
    
    mysql> select * from test_user;
    +----+
    | id |
    +----+
    |  1 |
    +----+
    
    
    mysql> select * from test_order;
    +----+-----------------+
    | id | order_number    |
    +----+-----------------+
    |  1 | ON1406031063627 |
    |  2 | ON1406031063673 |
    |  3 | ON1406031063678 |
    |  4 | ON1406031063683 |
    |  5 | ON1406031063686 |
    +----+-----------------+
    
    
    
    mysql> select * from test_user_orders;
    +------+----+
    | user | id |
    +------+----+
    |    1 |  1 |
    |    1 |  2 |
    |    1 |  3 |
    |    1 |  4 |
    |    1 |  5 |
    +------+----+
    

    现在正在查找 MnayToOne 端,即 TestOrder

    Map<String, Object> map = new HashMap<String, Object>();
     map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
     TestOrder order  = em2.find(TestOrder.class, new Long(1), LockModeType.PESSIMISTIC_WRITE, map);
    

    注意悲观锁定查询中的“for update”。 此查询也包含连接表。

     select
            testorder0_.id as id1_8_0_,
            testorder0_.order_number as order_nu2_8_0_,
            testorder0_1_.user as user1_11_0_ 
        from
            test_order testorder0_ 
        left outer join
            test_user_orders testorder0_1_ 
                on testorder0_.id=testorder0_1_.id 
        where
            testorder0_.id=? for update
    
    Hibernate: 
        select
            testuser0_.id as id1_9_0_,
            testuser0_1_.address as address2_9_0_,
            testuser0_1_.name as name3_9_0_ 
        from
            test_user testuser0_ 
        inner join
            test_person testuser0_1_ 
                on testuser0_.id=testuser0_1_.id 
        where
            testuser0_.id=?
    

    另外,当我查询用户时,这次只有用户层次结构中涉及的表被“for update”锁定

     Map<String, Object> map = new HashMap<String, Object>();
            map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
            TestUser user  = em2.find(TestUser.class, new Long(2), LockModeType.PESSIMISTIC_WRITE,map);
            user.getOrders().size(); // to force initialization of orders
    

    生成的 SQL 是:

            select
            testuser0_.id as id1_9_0_,
            testuser0_1_.address as address2_9_0_,
            testuser0_1_.name as name3_9_0_ 
        from
            test_user testuser0_ 
        inner join
            test_person testuser0_1_ 
                on testuser0_.id=testuser0_1_.id 
        where
            testuser0_.id=? for update
    
    Hibernate: 
        select
            orders0_.user as user1_9_0_,
            orders0_.id as id2_11_0_,
            testorder1_.id as id1_8_1_,
            testorder1_.order_number as order_nu2_8_1_,
            testorder1_1_.user as user1_11_1_ 
        from
            test_user_orders orders0_ 
        inner join
            test_order testorder1_ 
                on orders0_.id=testorder1_.id 
        left outer join
            test_user_orders testorder1_1_ 
                on testorder1_.id=testorder1_1_.id 
        where
            orders0_.user=?
    

    【讨论】:

    • 这很好地解释了EXTENDED 的作用,但我的问题是关于文档中的PessimisticLockScope.NORMALEntity relationships for which the locked entity contains the foreign key will also be locked 声明(位于NORMAL 值下)。
    猜你喜欢
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 2021-02-06
    • 2012-11-14
    • 2012-11-14
    • 2012-06-23
    • 2010-10-27
    • 1970-01-01
    相关资源
    最近更新 更多