Here are some experiments on this. I am using Hibernate 4.3.6 as the JPA provider and MySQL 5.6 as the database.
Several test objects - TestPerson, TestUser, TestOrder
TestUser extends TestPerson (with JOINED inheritance), and TestUser has a bidirectional list of 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**
Data Creation Code:
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 | +------+----+
Now look at the side of MnayToOne, i.e. 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);
Note the “for update” in the pessimistic lock request. This query also contains a connection table.
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=?
Also, when I query for the user, this time only the tables associated with the user hierarchy are locked using "to 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();
Resulting 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=?