Hibernate事务管理

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);//right here
		}
	}
	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刷新Session

	notifySynchronizationsBeforeTransactionCompletion();
	if ( callback ) {
		jdbcContext.beforeTransactionCompletion( this );
	}

	try {
		commitAndResetAutoCommit();//look here
		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编程式事务管理当然要关闭自动提交,最后手动提交

 

posted @ 2013-08-08 17:17  心意合一  阅读(199)  评论(0编辑  收藏  举报