Hibernate 基于JDBC的事务
Hibernate 是JDBC 的轻量级封装 本身并不具备事务管理能力 在事务管理层 Hibernate将其委托给底层的JDBC或者JTA 以实现事务管理和调度功能
Hibernate的默认事务处理机制基于JDBC Transaction 我们也可以通过配置文件设定采用JTA作为事务管理实现
Java代码
- <hibernate configuration> <session factory> …… <property name= hibernate transaction factory_class > net sf hibernate transaction JTATransactionFactory <! net sf hibernate transaction JDBCTransactionFactory > </property> …… </session factory> </hibernate configuration>
<hibernate configuration> <session factory> …… <property name= hibernate transaction factory_class > net sf hibernate transaction JTATransactionFactory <! net sf hibernate transaction JDBCTransactionFactory > </property> …… </session factory> </hibernate configuration>
基于JDBC的事务管理 将事务管理委托给JDBC 进行处理无疑是最简单的实现方式 Hibernate 对于JDBC事务的封装也极为简单 我们来看下面这段代码 Java代码- session = sessionFactory openSession(); Transaction tx = session beginTransaction(); …… mit();
session = sessionFactory openSession(); Transaction tx = session beginTransaction(); …… mit();
从JDBC层面而言 上面的代码实际上对应着 Java代码
- Connection dbconn = getConnection(); dbconn setAutoCommit(false); …… mit();
Connection dbconn = getConnection(); dbconn setAutoCommit(false); …… mit();
就是这么简单 Hibernate并没有做更多的事情(实际上也没法做更多的事情) 只是将这样的JDBC代码进行了封装而已 这里要注意的是 在sessionFactory openSession()中 hibernate会初始化数据库连接 与此同时 将其AutoCommit 设为关闭状态(false) 而其后 在Session beginTransaction 方法中 Hibernate 会再次确认Connection 的AutoCommit 属性被设为关闭状态( 为了防止用户代码对session 的Connection AutoCommit属性进行修改) 这也就是说 我们一开始从SessionFactory获得的session 其自动提交属性就已经被关闭(AutoCommit=false) 下面的代码将不会对数据库产生任何效果 Java代码- session = sessionFactory openSession(); session save(user); session close();
session = sessionFactory openSession(); session save(user); session close();
这实际上相当于 JDBC Connection的AutoCommit属性被设为false 执行了若干JDBC操作之后 没有调用mit操作即将Connection关闭 如果要使代码真正作用到数据库 我们必须显式的调用Transaction指令 Java代码- session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close();
session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close();
基于JTA的事务管理 JTA 提供了跨Session 的事务管理能力 这一点是与JDBC Transaction 最大的差异 JDBC事务由Connnection管理 也就是说 事务管理实际上是在JDBC Connection中实现 事务周期限于Connection的生命周期之类 同样 对于基于JDBC Transaction的Hibernate 事务管理机制而言 事务管理在Session 所依托的JDBC Connection中实现 事务周期限于Session的生命周期 JTA 事务管理则由 JTA 容器实现 JTA 容器对当前加入事务的众多Connection 进 行调度 实现其事务性要求 JTA的事务周期可横跨多个JDBC Connection生命周期 同样对于基于JTA事务的Hibernate而言 JTA事务横跨可横跨多个Session JTA 事务是由JTA Container 维护 而参与事务的Connection无需对事务管理进行干涉 这也就是说 如果采用JTA Transaction 我们不应该再调用HibernateTransaction功能 上面基于JDBC Transaction的正确代码 这里就会产生问题 Java代码- public class ClassA{ public void saveUser(User user){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close(); } } public class ClassB{ public void saveOrder(Order order){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(order); mit(); session close(); } } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); ClassA save(user); ClassB save(order); mit(); …… } }
public class ClassA{ public void saveUser(User user){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close(); } } public class ClassB{ public void saveOrder(Order order){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(order); mit(); session close(); } } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); ClassA save(user); ClassB save(order); mit(); …… } }
这里有两个类ClassA和ClassB 分别提供了两个方法 saveUsersaveOrder 用于保存用户信息和订单信息 在ClassC中 我们接连调用了ClassA saveUser方法和ClassB saveOrder 方法 同时引入了JTA 中的UserTransaction 以实现ClassC save方法中的事务性 问题出现了 ClassA 和ClassB 中分别都调用了Hibernate 的Transaction 功能 在Hibernate 的JTA 封装中 Session beginTransaction 同样也执行了InitialContext lookup方法获取UserTransaction实例 mit方法同样也调用了mit方法 实际上 这就形成了两个嵌套式的JTA Transaction ClassC 申明了一个事务 而在ClassC 事务周期内 ClassA 和ClassB也企图申明自己的事务 这将导致运行期错误 因此 如果决定采用JTA Transaction 应避免再重复调用Hibernate 的 Transaction功能 上面的代码修改如下 Java代码- public class ClassA{ public void save(TUser user){ session = sessionFactory openSession(); session save(user); session close(); } …… } public class ClassB{ public void save (Order order){ session = sessionFactory openSession(); session save(order); session close(); } …… } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); classA save(user); classB save(order); mit(); …… } }
public class ClassA{ public void save(TUser user){ session = sessionFactory openSession(); session save(user); session close(); } …… } public class ClassB{ public void save (Order order){ session = sessionFactory openSession(); session save(order); session close(); } …… } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); classA save(user); classB save(order); mit(); …… } }
上面代码中的ClassC save方法 也可以改成这样 Java代码- public class ClassC{ public void save(){ …… session = sessionFactory openSession(); Transaction tx = session beginTransaction(); classA save(user); classB save(order); mit(); …… } }
- /** * @ejb interface method * view type= remote * * @ejb transaction type = Required **/ public void save(){ //EJB环境中 通过部署配置即可实现事务申明 而无需显式调用事务 classA save(user); classB save(log); }//方法结束时 如果没有异常发生 则事务由EJB容器自动提交