hibernate的事务管理

在讲解hibernate的事物管理之前,我们必须首先明白一些基本的概念,以此帮助理解,为什么要事物管理这个东西,有它之后有什么用,它有哪些基本特性或者限制,

那么第一点,我们该知道的就是事物的4个基本特性,也就是我们常说的ACID【原子性,一致性,隔离性,持久性】;

第二点,应该知道的是,事物的隔离级别,即通过某种机制,在并发运行的多个事物之间进行分隔,使其保持执行时的独立性。一般分为Read Uncommitted,   Read Committed ,  Repeatable Read,  Serializable这四个隔离级别,这四种隔离级的严密程度是一次递增的,同事它的性能也是依次下降,在脏读取,不可重读,和虚读,这三个中数据库可能出现漏洞的情况下,这四个级别采取的应对措施是不同的,也就是说,这四个隔离级下,这三种情况发生的可能性是,1.可能脏读,可能重读,可能虚读;2.不可能脏读,可能重读,可能虚读; 3.不可能脏读,不可能重读,可能虚读 4.三种漏洞全都不可能发生。所以日常使用时,需根据实际情况取舍,以保持系统的最佳平衡。

hibernate是jdbc轻量级的封装,本身不具备事务管理的能力,在事物管理层面,一般是委托于底层的jdbc和jta来完成调度的。默认事物处理机制是基于jdbc transaction的,当然,我们也能通过配置jta来实现:

<hibernate-configuration>
    <session-factory>
        ........
            <property name="hibernate.transaction.factory_class">
                     net.sf.hibernate.transaction.JTATransactionFactory  //JTA
                    <!--net.sf.hibernate.transaction.JDBCTransactionFactory-->   //JDBC
            </property>
        ........
     </sesssion-factoty>
</hibernate-configuration>

  将事物委托给jdbc处理,无疑是最简单的方式,hibernate支持它做默认方式,其事物的封装,也非常简单,比如当我们在处理这段代码时:

session = sessionFactory.openSession();
Transaction tx=session.beginTransaction();
......
tx.commit();

  而从jdbc事物层面而言,实际上做的是:

Connection dbconn=getConnection();
dbconn.setAutoCommit(false);
......
dbconn.commit();

  就这么简单,换了个说法,把hibernate的提交方式,在底层用原生的jdbc进行了提交,这里需要注意的是在openSession()的时候,底层的jdbc的AutoCommit属性已被关闭了,除非jdbc连接去commit,否则执行的操作将不会对数据库产生任何效果,这里那就需要我们去显示执行tx.commit()了[非事物性数据库除外,如Mysql ISam]

而JTA与jdbc的事物的最大差异,在于它提供了跨session的事物管理能力。jdbc事物由Connection管理,事物的周期限于Connection的生命周期。而JTA则由JTA容器实现,容器可对当前的众多Connection进行调度,于是它可横跨多个Connection生命周期,于是也提供了跨session的能力。

比如我们下面这段代码,在jdbc的事物下完全正确的,但是在jta下就会产生问题:

class ClassA{
    public void save(User user){
         Session session=sessionFactory.openSession();
         Transaction tx=session.beginTransaction();
         session.save(user);
         tx.commit();
        
        session.close();
    }
}
class ClassB{
    public void save(Order order){
         Session session=sessionFactory.openSession();
         Transaction tx=session.beginTransaction();
         session.save(order);
         tx.commit();
        
        session.close();
    }
}
class ClassC{ public void save(){ ..... UserTransaction tx=(UserTranscation)(new InitialContext().lookup("....")); ClassA.save(user);
         ClassB.save(oreder);
         tx.commit();
        
       ......
    }
}

  这里的问题是,ClassA和B调用了hibernate的Transaction功能。而在hibernate的JTA分装中,Session.beginTransaction同样也执行了InitialContext.lookup去获得UserTransaction的实例,而在tx.commit的时候,ClassA和B都企图声明自己的事物,从而导致错误,因为我们知道,jdbc的事物,是不能够跨connection,跨session的。而假使使用jta,那么我们则可以修改上面代码,实现操作:

class ClassA{
    public void save(User user){
         Session session=sessionFactory.openSession();
         session.save(user);
        session.close();
    }
}

class ClassB{
    public void save(Order order){
         Session session=sessionFactory.openSession();
         session.save(order);
        
        session.close();
    }
}

class ClassC{
    public void save(){
     .....
         Session session=sessionFactory.openSession();
         Transaction tx=session.beginTransaction();
         ClassA.save(user);
         ClassB.save(order);
         tx.commit();
        
        session.close();
    }
}

  在EJB中使用JTA Transaction无疑最为简单,我们只需要将save方法的属性声明为Required,Ejb容器就会自动的维护并执行过程中的事物。

到这里,hibernate的事务管理就jdbc和jta方面已经叙述过一遍了,假使大家最先使用的jdbc即默认方式,那么没关系,一直用下去就好了。假使希望用jta去跨session处理,那么一定要注意上面提出的差异和用法。希望对大家有所帮助。

猜你喜欢

转载自phantomes.iteye.com/blog/1720291