Hibernate事務管理
阿新 • • 發佈:2019-01-08
User類:
public class User implements Serializable{ public User(){} private Integer id; private String name; private Integer age; private static final long serialVersionUID = 1L; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
User.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="com.po.User" table="TEST_USER"> <id name="id" column="id" type="java.lang.Integer"> <generator class="assigned"/> </id> <property name="name" column="name" type="java.lang.String" not-null="true" unique="true" length="20"/> <property name="age" column="age" type="java.lang.Integer" not-null="true" unique="false" length="0"/> </class> </hibernate-mapping>
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="show_sql">true</property> <property name="hibernate.connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <property name="hibernate.connection.url"> jdbc:oracle:thin:@192.168.58.1:1521:123 </property> <property name="hibernate.connection.username">123</property> <property name="hibernate.connection.password">123</property> <property name="dialect">org.hibernate.dialect.OracleDialect</property> <mapping resource="com/po/User.hbm.xml"/> </session-factory> </hibernate-configuration>
測試類:
public class Test {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("111");
user.setAge(10);
Configuration conf = new Configuration().configure();
SessionFactory sf = conf.buildSessionFactory();
Session sess = sf.openSession();
Transaction t = sess.beginTransaction();//說明一
try{
sess.save(user);
t.commit();//說明二
}catch(Exception e){
t.rollback();
}finally{
if(sess.isOpen()){
sess.close();
}
}
}
}
說明一:Hibernate本身沒有實現自己的事務管理功能,而是對底層JDBC事務或JTA事務的輕量級封裝
org.hibernate.impl.SessionImpl類(該類是會話的實現類):
public Transaction beginTransaction() throws HibernateException {
errorIfClosed();
if ( rootSession != null ) {
log.warn( "Transaction started on non-root session" );
}
Transaction result = getTransaction();
result.begin();
return result;
}
public Transaction getTransaction() throws HibernateException {
errorIfClosed();
return jdbcContext.getTransaction();
}
org.hibernate.jdbc.JDBCContext類:
public Transaction getTransaction() throws HibernateException {
if (hibernateTransaction==null) {
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory().createTransaction( this, owner );
}
return hibernateTransaction;
}
TransactionFactory有很多實現類:
選擇最基本的org.hibernate.transaction.JDBCTransactionFactory觀察一下:
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)throws HibernateException {
return new JDBCTransaction( jdbcContext, transactionContext );
}
org.hibernate.transaction.JDBCTransaction類的說明:
Transaction implementation based on transaction management through a JDBC Connection.
This the Hibernate's default transaction strategy.
事務開始時,會禁用自動提交:
public void begin() throws HibernateException {
if (begun) {
return;
}
if (commitFailed) {
throw new TransactionException("cannot re-start transaction after failed commit");
}
log.debug("begin");
try {
toggleAutoCommit = jdbcContext.connection().getAutoCommit();
if ( log.isDebugEnabled() ) {
log.debug("current autocommit status: " + toggleAutoCommit);
}
if (toggleAutoCommit) {
log.debug("disabling autocommit");
jdbcContext.connection().setAutoCommit(false);//關閉事務自動提交
}
}
catch (SQLException e) {
log.error("JDBC begin failed", e);
throw new TransactionException("JDBC begin failed: ", e);
}
callback = jdbcContext.registerCallbackIfNecessary();
begun = true;
committed = false;
rolledBack = false;
if ( timeout>0 ) {
jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
}
jdbcContext.afterTransactionBegin(this);
}
開啟log日誌也能看出很多端倪:
[2013-08-09 16:37:55] DEBUG -> begin
[2013-08-09 16:37:55] DEBUG -> opening JDBC connection
[2013-08-09 16:37:55] DEBUG -> current autocommit status: false
[2013-08-09 16:37:55] DEBUG -> generated identifier: 1, using strategy: org.hibernate.id.Assigned
[2013-08-09 16:37:55] DEBUG -> commit
說明二:不需要顯式的呼叫flush()方法,事務提交時會根據session的FlushMode自動觸發session的flush
還是通過最基本的JDBCTransaction類看一下:
事務提交完成之後又恢復了事務的自動提交
public void commit() throws HibernateException {
if (!begun) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("commit");
if ( !transactionContext.isFlushModeNever() && callback ) {
transactionContext.managedFlush(); //根據FlushMode(通常為AUTO)重新整理Session
notifySynchronizationsBeforeTransactionCompletion();
if ( callback ) {
jdbcContext.beforeTransactionCompletion( this );
}
try {
commitAndResetAutoCommit();//在該方法中重新開啟了事務自動提交
log.debug("committed JDBC Connection");
committed = true;
if ( callback ) {
jdbcContext.afterTransactionCompletion( true, this );
}
notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );
}
catch (SQLException e) {
log.error("JDBC commit failed", e);
commitFailed = true;
if ( callback ) {
jdbcContext.afterTransactionCompletion( false, this );
}
notifySynchronizationsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException("JDBC commit failed", e);
}
finally {
closeIfRequired();
}
}
private void commitAndResetAutoCommit() throws SQLException {
try {
jdbcContext.connection().commit();
}
finally {
toggleAutoCommit();
}
}
private void toggleAutoCommit() {
try {
if (toggleAutoCommit) {
log.debug("re-enabling autocommit");
jdbcContext.connection().setAutoCommit( true );//重新開啟事務自動提交
}
}
catch (Exception sqle) {
log.error("Could not toggle autocommit", sqle);
//swallow it (the transaction _was_ successful or successfully rolled back)
}
}
JDBC事務預設自動提交,但是如果Hibernate的事務策略使用JDBC,在事務開始之前,Hibernate會關閉事務自動提交,在事務結束之後,重新開啟事務自動提交