在JDBC中,可以用Connection來管理交易,可以將Connection的AutoCommit設定為false,在下達一連串的SQL語句 後,自行呼叫Connection的commit()來送出變更,如果中間發生錯誤,則撤消所有的執行,例如:
try
{
.....
connection.setAutoCommit(false);
.....
// 一連串SQL操作
connection.commit();
} catch(Exception) {
// 發生錯誤,撤消所有變更
if(connection != null) {
try {
connection.rollback();
catch(SQLException ex) {
ex.printStackTrace();
}
}
}
finally {
if(connection != null) {
try {
connection.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
.....
connection.setAutoCommit(false);
.....
// 一連串SQL操作
connection.commit();
} catch(Exception) {
// 發生錯誤,撤消所有變更
if(connection != null) {
try {
connection.rollback();
catch(SQLException ex) {
ex.printStackTrace();
}
}
}
finally {
if(connection != null) {
try {
connection.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
Hibernate本身沒有交易管理功能,它依賴於JDBC或JTA的交易管理功能,預設是使用JDBC交易管理,可以在配置文件中加上 hibernate.transaction.factory_class屬性來指定Transaction的工廠類別,例如:
- hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
....
<!-- 設定交易管理的工廠類 -->
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<!-- 物件與資料庫表格映射文件 -->
<mapping resource="onlyfun/caterpillar/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
基於JDBC的交易管理是最簡單的方式,事實上,Hibernate基於JDBC的交易管理只是對JDBC作了個簡單的封裝,使用Hibernate進行編程式的(Programmatic transaction)交易管理,其基本流程為:
try
{
session = sessionFactory.openSession();
tx = session.beginTransaction();
....
tx.commit(); // 必須commit才會更新資料庫
} catch(HibernateException e) {
if(tx != null) {
try {
tx.rollback();
}
catch(HibernateException ex) {
ex.printStackTrace();
}
}
}
finally {
if(session != null) {
try {
session.close();
}
catch(HibernateException e) {
e.printStackTrace();
}
}
}
session = sessionFactory.openSession();
tx = session.beginTransaction();
....
tx.commit(); // 必須commit才會更新資料庫
} catch(HibernateException e) {
if(tx != null) {
try {
tx.rollback();
}
catch(HibernateException ex) {
ex.printStackTrace();
}
}
}
finally {
if(session != null) {
try {
session.close();
}
catch(HibernateException e) {
e.printStackTrace();
}
}
}
Session是lazy的,也就是在一開始的openSession()取得Session時,並不會馬上取得Connection,在beginTransaction()時,才會真正取得JDBC的Connection實例,並設定AutoCommit為false,在 操作過程中,最後要commit (),否則的話對資料庫的操作不會有作用,在commit()之後,Connection與Session脫勾,如果使用Session再度 beginTransaction()的話,會重新取得Connection,如果操作過程中因發生例外,則最後commit()不會被執行,之前的操作 取消,執行rollback()可撤 消之前的操作,一個實際的程式如下所示:
- FirstHibernate.java
package onlyfun.caterpillar;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class FirstHibernate {
public static void main(String[] args) {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
User user = new User();
user.setName("momor");
user.setAge(new Integer(26));
Session session = null;
Transaction tx= null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
session.save(user);
tx.commit();
}
catch(Exception e) {
e.printStackTrace();
if(tx != null) {
try {
tx.rollback();
}
catch(HibernateException ee) {
ee.printStackTrace();
}
}
}
finally {
if(session != null) {
try {
session.close();
}
catch(HibernateException e) {
e.printStackTrace();
}
}
}
sessionFactory.close();
}
}
當因為發生Exception而rollback一個交易時,您要作的是關閉目前的Session,不建議繼續使用發生例外的Session或持久物件。
PS. 要使用MySQL中的交易處理,必須建立交易表類型的表格,例如InnoDB的表格:
CREATE TABLE user (
.....
....
) TYPE = InnoDB;
.....
....
) TYPE = InnoDB;