Hibernate与Spring的事务管理

网友投稿 273 2022-09-12

Hibernate与Spring的事务管理

什么是事务

这个问题比较大,按照我的理解就是,一个事务内的n个操作,要么全部完成,一旦有一个操作有问题,那么所有的操作都全部回滚。

Jdbc的事务

首先,大家已经知道了,事务说白了就是一个词----统一,要么全部OK,要么都不做。

在jdbc中,默认情况下,一个sql就是一个事务,一个事务也仅仅只有一个sql。AutoCommit=true

那么我们正常使用的时候,肯定是想把若干个sql绑到一起,看做一个事务。

那么我们第一步就是先告诉connection,你别一个sql一个sql提交了,整体来。即AutoCommit=false

我们看下面的例子

public int delete(int sID) {  dbc = new DataBaseConnection();  Connection con = dbc.getConnection();  try {   con.setAutoCommit(false); // 更改JDBC事务的默认提交方式   dbc.executeUpdate("delete from xiao where ID=" + sID);   dbc.executeUpdate("delete from xiao_content where ID=" + sID);   dbc.executeUpdate("delete from xiao_affix where bylawid=" + sID);   con.commit();//提交JDBC事务   con.setAutoCommit(true); // 恢复JDBC事务的默认提交方式   dbc.close();   return 1;  }  catch (Exception exc) {   con.rollBack();//回滚JDBC事务   exc.printStackTrace();   dbc.close();   return -1;  }}

jta事务

不懂,我目前没用到这个东西。

hibernate中的事务

Hibernate 是JDBC 的轻量级封装,本身并不具备事务管理能力。在事务管理层,

Hibernate将其委托给底层的JDBC或者JTA,以实现事务管理和调度功能。

Hibernate的默认事务处理机制基于JDBC Transaction。我们也可以通过配置文件设定采用JTA作为事务管理实现:

          ……            net.sf.hibernate.transaction.JTATransactionFactory                  ……      

单纯的使用hibernate,对于事务的处理是很简单的,例如

Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Teacher s = new Teacher(); s.setName("zhangsan"); s.setAge(232); s.setDate(sdf.format(date)); SessionFactory sessionFactory = new AnnotationConfiguration() .configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); session.save(s); session.getTransaction().commit(); session.close(); sessionFactory.close();

抽象的来说,

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

在jdbc层面上就相当于:

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

另一方面,在我们获得session的时候,hibernate会初始化数据库连接,把AutoCommit设置为false,后面在beginTransaction会再次检查AutoCommit的值是否未false(防止用户更改)。

所以

session = sessionFactory.openSession(); session.save(user); session.close();

上面的代码不会对数据库产生任何影响。你没提交嘛!

使用spring替hibernate管理事务

首先,我们为什么要让spring去替hibernate管理事务?

一 如果单纯的用hibernate,每次对数据库做一次操作,我都得beginTransaction然后getTransaction.commit。你不烦呀。

二 粒度的问题,事务其实在更高的层次上看是一个逻辑概念,它是几个操作的集合。而默认情况下,hibernate只管理对数据库最低层次的操作。(这个,具体的咱们在后面再说)

OK,我们已经知道了用spring管理事务的必要性,再看看用spring管理事务的方式。

有两种。

一种是使用xml,一种是使用Annotation

/以下为9月30日的补充内容

我写个简单的例子:

public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionDefinition txDefinition; private PlatformTransactionManager txManager; public boolean transfer(Long fromId, Long toId, double amount) { TransactionStatus txStatus = txManager.getTransaction(txDefinition); boolean result = false; try { result = bankDao.transfer(fromId, toId, amount); txManager.commit(txStatus); } catch (Exception e) { result = false; txManager.rollback(txStatus); System.out.println("Transfer Error!"); } return result; }}

TransactionDefinition,PlatformTransactionManager都是spring注入的#

上面的bankDao.transfer(fromId, toId, amount)就是把tromid的amount块钱转移到toid上去#

感觉是和jdbc的每什么区别,还都得提交#,我们应该关注于业务本身,对于事务的提交与回滚应该交给系统#

既然说到了jdbc,那么大家就肯定会想到jdbctemplate#那么既然有jdbctebmplage,那为什么就不能有transactionTemplate呢?

我们看下面的例子

public class BankServiceImpl implements BankService { private BankDao bankDao; private TransactionTemplate transactionTemplate; public boolean transfer(final Long fromId, final Long toId, final double amount) { return (Boolean) transactionTemplate.execute(new TransactionCallback(){ public Object doInTransaction(TransactionStatus status) { Object result; try { result = bankDao.transfer(fromId, toId, amount); } catch (Exception e) { status.setRollbackOnly(); result = false; System.out.println("Transfer Error!"); } return result; } }); }}

这样一来,我们就能关注单纯的业务逻辑了

。(只不过一旦出错了,我们还得status.setRollbackOnly())

关于硬编码这块,大家参见

只不过,大家请记着,除非我们是接手了一个遗留系统,否则还是不要用编程式事务管理了。

当然,虽然不鼓励大家主动去用这个东西,但是我们至少得会用,看到这个这些代码得知道是什么意思,更进一步的,如果我们还能知道里面的实现过程,那对我们的编程技术,或者说架构能力都是有帮助的。

总结一下:

基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务管理是 Spring 提供的最原始的方式,通常我们不会这么写,但是了解这种方式对理解 Spring 事务管理的本质有很大作用。

基于 TransactionTemplate 的编程式事务管理是对上一种方式的封装,使得编码更简单、清晰。

/以上为9月30日的补充内容

Annotation

我们先说使用Annotation。

第一步

在spring的xml里面加上

一般情况下,JDBC(iBATIS) 使用 DataSourceTransactionManager,hibernate使用HibernateTransactionManager

当然,如果xml里面没有tx的命名空间,还得加上

xmlns:tx=" @Transaction

我给大家一个实例,向数据库里添加一个user,然后再添加一条日志记录。

说到这,先看代码。

package com.bjsxt.service;import javax.annotation.Resource;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import com.bjsxt.dao.LogDAO;import com.bjsxt.dao.UserDAO;import com.bjsxt.model.Log;import com.bjsxt.model.User;@Component("userService")public class UserService { @Resource private UserDAO userDAO; @Resource private LogDAO logDAO; public User getUser(int id) { return null; } public void add(User user) { userDAO.save(user); Log log = new Log(); log.setMsg("a user saved!"); logDAO.save(log); } //省略getset}package com.bjsxt.dao.impl;import javax.annotation.Resource;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.springframework.stereotype.Component;import com.bjsxt.dao.UserDAO;import com.bjsxt.model.User;@Component("userDAO") public class UserDAOImpl implements UserDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void save(User user) { Session s = sessionFactory.getCurrentSession(); s.save(user); }}

省略LogDAO的接口及实现。

现在的问题是我把 @Transaction加到UserDAOImpl的sava方法上(当然还有LogDAOImpl的save方法)还是加到UserService的add方法上。

我的代码都已经写出来了,大家就是用大腿想,应该也能想出来,加到整体的业务逻辑上。

这个观点提升一下就是,

我们应该在service层做事务管理。

OK,我们仔细看看这 @Transaction

下图是 @Transaction的doc文档

我们其实只有看两个:

readOnly,我们应该能猜出来,如果某个方法的 @transaction加了readonly,那么方法内部就不能对数据库有增删改的行为。

为什么会有这个属性呢,spring为对readOnly的transaction的方法做优化。

因此,如果你肯定某个方法是不会修改数据库,那就给他加上readOnly=true吧,另一方面,从设计上来讲,readOnly也可以看做一种检查,看某个不应该出现更改数据库的地方出现了更改操作。

第二个属性是propagation,我们能看出他的选值是Propagation,而Propagation是一个枚举类。

Propagation的说明如下:

我们最经常使用的,而且也是spring默认的就是REQUIRED

REQUIRED就是,如果当前方法没有事务,那就新产生一个事务,并且如果此方法有了事务,那么方法内部的方法调用也会使用这个事务。

至于别的几个参数,大家就都忘了吧。

如果把 @Transaction加到某个类上,就等于给这个类的所有方法都加上了 @Transaction @Transaction标签不可继承。

前面我们已经说了,让spring管理事务有两种方式,第一是annotation,上面我们已经说了,下面我们说说使用xml。

在spring的xml中加入如下内容

当然,要去掉使用annotation的

我解释一下上面的定义。

在com.bjsxt.service包及其子包下的所有类的所有public的方法都加上事务管理

具体的事务设置是,如果方法名是getUser那么设置read-only为true,如果方法是以add开头的,那么设置propagation为REQUIRED(这个其实不用设,因为是默认的)

现在有个问题,到底是用annotation那,还是xml呢?

回答是看情况。

你觉得哪个方便用哪个。

另外,上面的代码使用的是spring3 hibernate3

如果使用spring4 hibernate4

xml如下:

classpath:jdbc.properties com.bjsxt.model.User com.bjsxt.model.Log org.hibernate.dialect.MySQLDialect true update

到底用哪个呢?

答案是采用HibernateTransactionManager

它既可以管hibernate,也可以管jdbc

参见: ​​ spring 同时配置hibernate and jdbc 事务​​

/以下为9月30日的补充内容

怎么说呢,虽然之前的事务管理方式都已经很out了,而且我们也没太大的必要对之前的实现方法做多么深的理解,但是不是有那么已经老话嘛:温故而知新,可以为师矣。

我们只有知道了之前是怎么样的,才能真正的体会,为什么事务管理会是今天这个样子。之前是现在的基础。

总结一下:

/以上为9月30日的补充内容

参考资料

北京尚学堂 马士兵 spring3讲解

​​同时配置hibernate and jdbc 事务​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【系统部署知识汇总】第18章——pipeline示例 + maven安装
下一篇:table中 点击某一行变色
相关文章

 发表评论

暂时没有评论,来抢沙发吧~