今天在csdn上看到一個特別有趣的話題,hibernate3爲什麼必須使用事務才能保存對象,我相信這個問題對很多人來說都非常困惑包括我自己,於是掛上hibernate源碼,一直跟蹤最底層,也沒發現什麼,然而正是因爲沒用發現什麼才點醒了我,回憶多年前使用經典jdbc的場景,那時候使用事務必須自己手工控制conn.setAutoCommit(false); 纔行。而現在如果我們要正常使用hibernate3保存對象的話要使用事務處理纔行:
public static void main(String[] args) throws Exception {
SessionFactory sf = HibernateSessionFactory.getSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
User u = new User();
u.setName("aaa");
session.save(u);
session.getTransaction().commit();
}
使用spring聲明式事務本質上和上面是一樣的,spring只不過是利用了動態代理而已。 從上面代碼可以看到beginTransaction非常像很久以前我們寫的conn.setAutoCommit(false); 而session.getTransaction().commit();則是對應conn.commit();那會不會是因爲conn已經默認是false了呢System.out.println(session.connection().getAutoCommit());//經測試果然如此。經測試下面代碼可以成功保存對象。
SessionFactory sf = HibernateSessionFactory.getSessionFactory();
Session session = sf.openSession();
System.out.println(session.connection().getAutoCommit());
session.connection().setAutoCommit(true);
User u = new User();
u.setName("aaa");
session.save(u);
只要修改conn默認的提交方式就可以了,爲了進一步驗證這個問題其實和hibernate是無關的,寫了如下測試代碼,同樣可以正常的保存對象。
public static void main(String[] args) throws Exception {
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
Connection conn = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs",
"sa", "11111111");
SessionFactory sf = HibernateSessionFactory.getSessionFactory();
Session session = sf.openSession(conn);
System.out.println(session.connection().getAutoCommit());
// session.connection().setAutoCommit(true);
User u = new User();
u.setName("aaa");
session.save(u);
}
其實我覺得必須使用事務才能保存對象是大家對hibernate的誤解,目前流行的數據庫連接池默認的情況下都是conn自動提交爲false的。很多連接池還可以靈活的配置,我們還是要還hibernate清白的。這是取決於數據庫連接池的配置。