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,換個視角總有好處。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM