Spring事务管理

spring是支持事务管理的,这样就不用直接在sql中使用begin transaction这样开始事务的命令了,spring帮你集成了
spring有两种事务,一种是编程式事务,即通过java代码来进行事务管理,一种是声明式事务,使用xml配置或者注解即可。
spring的事务接口是PlatFormTransationManager,实现类DataSourceTransactionManager

编程式事务。

(一)、使用jdbcTemplate进行事务管理
jdbcTemplate是spring中个一个数据库操做类,你可以理解为jdbc那种,只是好一点,稍微封装了一下,类似ibatis的sqlmapclient

1.首先引入事务处理类,可以配置在spring的配置xml,也可以配置在数据库相关的xml中

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
    <property name="dataSource" ref="dataSource"/> 
</bean>

其中datasource就是数据库的一些连接属性,如下:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
  <property name="driverClassName"> 
    <value>com.mysql.jdbc.Driver</value> 
  </property> 
  <property name="username"> 
    <value>root</value> 
  </property> 
  <property name="password"> 
    <value>root</value> 
  </property> 
  <property name="url"> 
    <value>jdbc:mysql://localhost:3306/test</value> 
  </property> 
</bean> 

2.java类中操作,测试事务回滚,这里故意设置teacher表的name不能为空,让其报错,从而测试是否回滚,执行事务了

ApplicationContext ctx=new ClassPathXmlApplicationContext("helloworld.xml");
          DefaultTransactionDefinition dtd=new DefaultTransactionDefinition();
          dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); //设置事务隔离级别
          dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);         
          //获取spring事务处理类
          PlatformTransactionManager tx=(PlatformTransactionManager) ctx.getBean("transactionManager");
          TransactionStatus status=tx.getTransaction(dtd);
          //获取数据源
          DataSource  dataSource = (DataSource) ctx.getBean("dataSource"); 
          JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);                   
          try{
              //执行sql,sql的执行可以换成使用ibatis,mybatis等框架
              jdbcTemplate.execute(sql);
              //如果执行sql,因为name不能为空,会报错,然后就回滚。
              jdbcTemplate.update(sql2,new Object[]{null,'M',1,"abc",151,111});
              tx.commit(status);
              System.out.println("提交数据成功,状态--"+status);
          }catch(Exception e){
              tx.rollback(status);
              System.out.println("数据回滚,状态--"+status);
          }

这里要注意,由于是使用单元测试类执行的,故需要用ClassPathXmlApplicationContext来获取需要的这些bean,其实如果是启动项目了,可以直接使用注入的方式。
其中真正负责回滚和提交的是spring自带的transactionManager类,jdbcTemplate只不过负责执行sql,可以替换为ibatis或者其他的ORM框架。

3.需要测试的sql,以下没有说明,那么sql,sql2也是指这两个

private String sql="insert into student (name,sex,age,address,mobile) "
              + "values ('lisi','F',22,'AAAABCCC',158)";
     private String sql2="insert into teacher (name,sex,age,address,mobile,classid) "
              + "values (?,?,?,?,?,?)";

(二)、tranactionTemplate事务管理
在spring中,还可以使用tranactionTemplate进行事务管理,上面那个太麻烦了,commit,rollback要自己来写,自己控制。tranactionTemplate就简单多了,你只需要负责业务操作,就是执行sql那部分,其他框架帮你
1、配置差不多,都是一个datasource,一个transactionManager,这里不重复了
2、java中调用,同样是在单元测试类中

//获取数据源
TransactionTemplate template=new TransactionTemplate(tx);     
//事务隔离级别       
template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//事务传播行为
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 
//带返回对象方法
template.execute(new TransactionCallback() {
       public Object doInTransaction(TransactionStatus arg0) {
          //此处使用jdbcTemplate来执行sql,可以替换为其他方法,与事务无关
          jdbcTemplate.execute(sql);
          //如果执行sql,因为name不能为空,会报错,然后就回滚。
          jdbcTemplate.update(sql2,new Object[]{null,'M',1,"abc",151,111});
          return null;
       }
 });

其中tx就是上面配置的spring的transactionManager,你只需要负责在doInTransaction中执行你的业务逻辑

3、还有一个不带反回参数的execute方法,如下:

template.execute(new TransactionCallbackWithoutResult() {              
//无返回对象事务方法,出错自动回滚,无需手动使用commit,rollback等
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
          //此处使用jdbcTemplate来执行sql,可以替换为其他方法,与事务无关
          jdbcTemplate.execute(sql);
          //如果执行sql,因为name不能为空,会报错,然后就回滚。
          jdbcTemplate.update(sql2,new Object[]{null,'M',1,"abc",151,111});
       }
  });

一般如果使用编程式事务,都是使用tranactionTemplate

声明式(配置式)事务

编程式事务还是对代码要修改,有侵入性,spring有更高级的,就是声明式事务,无需代码,只要配置
1.xml中配置如下,使用事务标签

<tx:advice id="txAdvice" transaction-manager="transactionManager"> 
    <tx:attributes> 
    <!-- 这个name是指要切入的方法,以insert开头的都切入事务 -->
        <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED"/> 
    </tx:attributes> 
</tx:advice>

2.aop配置,因为这个就是用到了面向切面编程,故需要aop

<aop:config> 
    <aop:pointcut id="serviceMethod" expression="execution(* com.xxxx.dao.TransactionDao.insert(..))"/> 
    <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/> 
</aop:config>

pointcut表示切入点,这里表示TransactionDao类,以insert开头的方法都会加入事务,而不是insert的sql语句,不要混淆。
3.这个是被切入的那个类,负责数据库操作(业务操作)

<bean id="transaction" class="com.luohw.dao.TransactionDao">
  <property name="dataSource" ref="dataSource"></property>
</bean>

4.业务逻辑:

public void insert(){
          //在没有声明式事务前,sql执行正常,数据库有数据,sql2失败,没有插入
          jdbcTemplate = new JdbcTemplate(dataSource);
          jdbcTemplate.execute(sql);
          jdbcTemplate.update(sql2,new Object[]{null,'M',1,"abc",151,111});
     }

其中,由于用到tx事务标签,aop标签,配置文件开头需要引入以下东西:

<?xml version="1.0" encoding="UTF-8"?> 
<beans   
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                    http://www.springframework.org/schema/tx
                    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 

注意,这是指多的部分,之前还有spring必须的一个dtd和shema要引入。
这样对于业务代码,没有一点的侵入,完全只要配置就可以了,使用aop编程,spirng会自动动态代理,类似组合成一个新的方法,先开启事务,再执行你的sql。

使用注解注入事务,也是声明式的一种,更简洁好用。因为用aop,有可能返回太大,某个类,或者某个包所有的方法都加入了事务,有好处,一次操作多个,也有坏处,有些不需要事务的被你误杀。

注解的比较好控制范围,可以在方法,或者类上注解,那么就表示对应范围的都加了事务控制了。
1.在配置文件中,加入这个标签,表示支持事务注解

<tx:annotation-driven transaction-manager="transactionManager"/>

2.在需要加入事务控制的代码处,加入这个,此处以方法为例

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
     public void insert2(){
          jdbcTemplate = new JdbcTemplate(dataSource);
          jdbcTemplate.execute(sql);
          jdbcTemplate.update(sql2,new Object[]{null,'M',1,"abc",151,111});
     }

看,是否非常简单。。。。

xml声明式事务,有传播行为(propagation),有以下值:
1.required——表示方法必须运行在事务中,如果没有,会创建一个新的事务,如果有,加入到这个事务中
2.mandatory——表示方法必须在事务中,如果没有,抛出异常
3.nested——如果存在事务,那么方法会在嵌套事务中运行?其他与required一样
4.never——表示方法不在事务中运行,如果有事务,那么抛出异常
5.not_supported——表示方法不在事务中运行,如果有事务,那么将被挂起(暂停),直到方法完成
6.required_new——表示方法必须在新的事务中运行, 如果当前存在事务,把当前事务挂起
7.supports——表示支持事务,如果有,也可以在事务中运行,也可以没有

传播行为用于确定方法嵌套方法时的事务调用情况。比如方法A调用方法B,两个方法都使用了注解事务。如果为required(一般都是这个),那么会把A,B合并到一起作为一个事务。如果是其他,看上面配置。

事务隔离级别(isolation)
1.read_uncommited——不提交读,未提交的数据,其他事务可以读,会出现脏读。比如B改了未提交,恰好A在事务中读,那么这个就是脏数据(A读了B修改前的数据)
2.read_commited——提交读,提交后的数据,其他事务才能读。会发生幻读和不可重复读
不可重复读, 一 个事务对同一行数据重复读取两次但是却得到了不同结果(有其他事务数据修改了)
幻读,事务在操作过程中进行两次查询,第二次查询结果包含了第一次查询中未出现的数据(有其他事务数据插入了)
3.repeatable_read——可重复读,对于同一字段多次读取结果是一致的,除非数据被本身事务修改,会发生幻读。
4.serializable——序列化,最高级别(性能最差),什么问题读都不会发生

隔离级别 更新丢失 脏读取 不可重复读取 幻读
未提交读取 N Y Y Y
提交读取 N N Y Y
可重复读取 N N N Y
串行 N N N N

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值