Hibernate:有了 save,为什么还需要 persist?


背景

万物皆自然,每个 API 的设计,无论是否正确,都有其意图。因此,在学习某些框架的时候,我们需要经常思考:这个 API 的设计意图是啥?

本文来探讨一下 Session 中 persist 的设计意图。

官方注释

save

1     /**
 2      * Persist the given transient instance, first assigning a generated identifier. (Or
 3      * using the current value of the identifier property if the <tt>assigned</tt>
 4      * generator is used.) This operation cascades to associated instances if the
 5      * association is mapped with {@code cascade="save-update"}
 6      *
 7      * @param object a transient instance of a persistent class
 8      *
 9      * @return the generated identifier
10      */
11     public Serializable save(Object object);

persist

1     /**
2      * Make a transient instance persistent. This operation cascades to associated
3      * instances if the association is mapped with {@code cascade="persist"}
4      * <p/>
5      * The semantics of this method are defined by JSR-220.
6      *
7      * @param object a transient instance to be made persistent
8      */
9     public void persist(Object object);

解释

save 因为需要返回一个主键值,因此会立即执行 insert 语句,而 persist 在事务外部调用时则不会立即执行 insert 语句,在事务内调用还是会立即执行 insert 语句的。

看 persist 的注释会觉得其不会立即执行 insert 语句,为何 在事务内调用会立即执行 insert 语句,后面再分析。

测试

SessionHelper

1 package demo;
 2 
 3 import org.hibernate.*;
 4 import org.hibernate.cfg.*;
 5 
 6 public final class SessionHelper {
 7     private static SessionFactory factory;
 8 
 9     public static void execute(SessionAction action) {
10         execute(action, false);
11     }
12 
13     public static void execute(SessionAction action, boolean beforeTransaction) {
14         Session session = openSession();
15         try {
16             if (beforeTransaction) {
17                 System.out.println("action");
18                 action.action(session);
19             }
20 
21             System.out.println("begin transaction");
22             session.beginTransaction();
23             if (!beforeTransaction) {
24                 System.out.println("action");
25                 action.action(session);
26             }
27 
28             System.out.println("flush and commit");
29             session.flush();
30             session.getTransaction().commit();
31         } catch (Exception ex) {
32             session.getTransaction().rollback();
33         } finally {
34             session.close();
35         }
36     }
37 
38     @SuppressWarnings("deprecation")
39     public static Session openSession() {
40         if (factory == null) {
41             factory = new Configuration().configure().buildSessionFactory();
42         }
43 
44         return factory.openSession();
45     }
46 }

save

1 package demo;
 2 
 3 import model.*;
 4 
 5 import org.hibernate.*;
 6 /*
 7  * save 会导致 insert 语句的立即执行。
 8  */
 9 public class SaveDemo implements Demo {
10 
11     @Override
12     public void run() {
13         SessionHelper.execute(new SessionAction() {
14 
15             @Override
16             public void action(Session session) {
17                 User user = new User();
18                 user.setUsername("woshishui");
19                 user.setPassword("123456");
20 
21                 session.save(user);
22             }
23 
24         });
25     }
26 
27 }

输出结果

1 begin transaction
 2 action
 3 Hibernate: 
 4     /* insert model.User
 5         */ insert 
 6         into
 7             USERS
 8             (USERNAME, PASSWORD) 
 9         values
10             (?, ?)
11 flush and commit

persis in transactiont

1 package demo;
 2 
 3 import model.*;
 4 
 5 import org.hibernate.*;
 6 
 7 /*
 8  * persist 在事务中执行,会导致 insert 语句的立即执行。
 9  */
10 public class PersisInTransactiontDemo implements Demo {
11 
12     @Override
13     public void run() {
14         SessionHelper.execute(new SessionAction() {
15 
16             @Override
17             public void action(Session session) {
18                 User user = new User();
19                 user.setUsername("woshishui");
20                 user.setPassword("123456");
21 
22                 session.persist(user);
23             }
24 
25         });
26     }
27 
28 }

输出结果

1 begin transaction
 2 action
 3 Hibernate: 
 4     /* insert model.User
 5         */ insert 
 6         into
 7             USERS
 8             (USERNAME, PASSWORD) 
 9         values
10             (?, ?)
11 flush and commit

persis before transactiont

1 package demo;
 2 
 3 import model.*;
 4 
 5 import org.hibernate.*;
 6 
 7 /*
 8  * persist 不在事务中执行,不会导致 insert 语句的立即执行,而是在 flush 时执行 insert 语句。
 9  */
10 public class PersisBeforeTransactiontDemo implements Demo {
11 
12     @Override
13     public void run() {
14         SessionHelper.execute(new SessionAction() {
15 
16             @Override
17             public void action(Session session) {
18                 User user = new User();
19                 user.setUsername("woshishui");
20                 user.setPassword("123456");
21 
22                 session.persist(user);
23             }
24 
25         }, true);
26     }
27 
28 }

输出结果

1 action
 2 begin transaction
 3 flush and commit
 4 Hibernate: 
 5     /* insert model.User
 6         */ insert 
 7         into
 8             USERS
 9             (USERNAME, PASSWORD) 
10         values
11             (?, ?)

分析

为何 persist 在事务内和事务外表现的行为不同呢?为何这样设计?目前还没有查到官方的第一手资料(刚学习 Java 和 Hibernate),我的猜测是: 事务外的 persist 是为了应对长事务,事务内的 persist 是为了和 save 保持一个语义

备注

学习 Hibernate 的过程也相当于从新学习了一遍 EntityFramework,换个视角总有好处。


原文链接:https://www.cnblogs.com/happyframework/p/3352158.html