Hibernate JDBC traction

来源:互联网 发布:linux yum安装apache 编辑:程序博客网 时间:2024/05/24 04:11
Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装。

Hibernate可以配置为JDBCTransaction或者是JTATransaction,这取决于你在hibernate.properties中的配置:

#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory


如果你什么都不配置,默认情况下使用JDBCTransaction。建议是什么都不配,将让它保持默认状态。


一、Transaction

HIbernate对于JDBC事物的封装是极为简单的,看看使用JDBC Transaction的时候我们的代码例子:


Session session = sessionFactory.openSession();
Transaction tx = session.beginTransactioin();
...
session.flush();
tx.commit();
session.close();


详细的信息我们查看一下Hibernate2.0.3源代码中的类

net.sf.hibernate.transaction.JDBCTransaction:
public void begin() throws HibernateException {


...
if (toggleAutoCommit) session.connection().setAutoCommit(false);
...
}

这是启动Transaction的方法,看到 connection().setAutoCommit(false) 了吗?是不是很熟悉?


再来看
public void commit() throws HibernateException { 
...
try {
if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
try {
session.connection().commit();
committed = true;
}
...
toggleAutoCommit();
}

这是提交方法,看到connection().commit() 了吗?下面就不用我多说了,这个类代码非常简单易懂,通过阅读使我们明白Hibernate的Transaction都在干了些什么?我现在把用Hibernate写的例子翻译成JDBC,大家就一目了然了:


Connection conn = ...; <--- session = sf.openSession();
conn.setAutoCommit(false); <--- tx = session.beginTransactioin();
... <--- ...
conn.commit(); <--- tx.commit(); (对应左边的两句)
conn.setAutoCommit(true);

conn.close(); <--- session.close();


就是这么简单,Hibernate只是将这样的JDBC代码进行了封装而已。


这里要注意的是,在Hibernate中,Session打开的时候,即sessionFactory.openSession()中,hibernate会初始化数据库连接,于此同时设置conn.setAutoCommit(false)。而后,在session.beginTracsaction方法中,Hibernate会再次确认Connection的AutoCommit属性被设置为关闭状态(false),防止用户代码对session的Connection.AutoCommit()属性进行修改。不像一般的JDBC,默认都是true,所以用Hibernate的时候,你在程序中不写Transaction的话,数据库根本就没有反应。

二、setAutoCommit


void setAutoCommit(boolean autoCommit)throws SQLException
参数: autoCommit - 为 true 表示启用自动提交模式;为 false 表示关闭提交模式。如果connection.setAutoCommit(false);的话,则在语句正常执行完毕后需要用connection.commit()手动提交,如果在执行语句时出错的可以调用connection.rollback()来回滚!


将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则将执行其所有 SQL 语句,并将这些语句作为单独的事务提交。否则,其 SQL 语句将成组地进入通过调用 commit 方法或 rollback 方法终止的事务中。默认情况下,新的连接处于自动提交模式下。


注:误用Connection.setAutoCommit导致的数据库死锁问题。
Connection con = null;
try{
con = getConnection();
con.setAutoCommit(false);
        /*
         * update USER set name=’winson’ where id=’000001’;
         */
        con.commit();
}finally{
if(con!=null){
try {
        con.close();
             } catch (SQLException e) {
                 e.printStackTrace();
             }
}
}
分析:问题就出现在第4行,写代码的人把数据库连接con 设置成非自动提交,但没有在执行出现异常的时候进行回滚。如果在执行第5行的时候出现异常,con既没有提交也没有回滚,表USER就会被锁住(如果oracle数据库就是行锁),而这个锁却没有机会释放。有人会质疑,在执行con.close()的时候不会释放锁吗?因为如果应用服务器使用了数据库连接池,连接不会被断开。


参考正确的写法应该是:
        Connection con = null;
       try{
           con = getConnection();
           con.setAutoCommit(false);
           /*
            * do what you want here.
            */
           con.commit();
        }catch(Throwable e){
           if(con!=null){
               try {
                   con.rollback();
               } catch (SQLException e1) {
                   e1.printStackTrace();
               }
           }
throw new RuntimeException(e);
        }finally{
           if(con!=null){
               try {
                   con.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }


参考:
http://www.360doc.com/content/10/0226/11/888785_16865620.shtml
http://jianrc.iteye.com/blog/52044
http://blog.csdn.net/he_hchx/article/details/1586409
原创粉丝点击