首页 > 代码库 > spring来了-06-事务控制

spring来了-06-事务控制

概述

  编程式事务控制

    自己手动控制事务,就叫做编程式事务控制。

    Jdbc代码:

      Conn.setAutoCommite(false);  // 设置手动控制事务

    Hibernate代码:

      Session.beginTransaction();    // 开启一个事务

    【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】

    (比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)

 

spring提供的事务控制

  声明式事务控制

    Spring提供了对事务的管理, 这个就叫声明式事务管理。

    Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务  控制的最大程度的解耦。

    Spring声明式事务管理,核心实现就是基于Aop。

    【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】

    (因为aop拦截的是方法。)

 

    Spring声明式事务管理器类:

      Jdbc技术:DataSourceTransactionManager

      Hibernate技术:HibernateTransactionManager

技术分享
  1 package cn.fuyi.a_tx;  2   3 public class Dept {  4   5     private Integer deptId;  6     private String dname;  7     public Integer getDeptId() {  8         return deptId;  9     } 10     public void setDeptId(Integer deptId) { 11         this.deptId = deptId; 12     } 13     public String getDname() { 14         return dname; 15     } 16     public void setDname(String dname) { 17         this.dname = dname; 18     } 19      20 } 21  22 package cn.fuyi.a_tx; 23  24 import org.springframework.jdbc.core.JdbcTemplate; 25  26 public class DeptDao { 27  28     private JdbcTemplate jdbcTemplate; 29     public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { 30         this.jdbcTemplate = jdbcTemplate; 31     } 32      33     public void save(Dept dept) { 34         String sql = "insert into dept(dname) values(?)"; 35         jdbcTemplate.update(sql, dept.getDname()); 36     } 37 } 38  39 package cn.fuyi.a_tx; 40  41 public class DeptService { 42  43     private DeptDao deptDao; 44     public void setDeptDao(DeptDao deptDao) { 45         this.deptDao = deptDao; 46     } 47      48     public void save(Dept dept) { 49         deptDao.save(dept); 50         int i = 1/0; 51         deptDao.save(dept); 52          53     } 54 } 55  56 <?xml version="1.0" encoding="UTF-8"?> 57 <beans xmlns="http://www.springframework.org/schema/beans" 58     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 59     xmlns:p="http://www.springframework.org/schema/p" 60     xmlns:context="http://www.springframework.org/schema/context" 61     xmlns:aop="http://www.springframework.org/schema/aop" 62     xmlns:tx="http://www.springframework.org/schema/tx" 63     xsi:schemaLocation=" 64         http://www.springframework.org/schema/beans 65         http://www.springframework.org/schema/beans/spring-beans.xsd 66         http://www.springframework.org/schema/context 67         http://www.springframework.org/schema/context/spring-context.xsd 68         http://www.springframework.org/schema/aop 69         http://www.springframework.org/schema/aop/spring-aop.xsd 70         http://www.springframework.org/schema/tx 71          http://www.springframework.org/schema/tx/spring-tx.xsd"> 72  73     <!-- dataSource配置 --> 74     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 75         <property name="driverClass" value="http://www.mamicode.com/com.mysql.jdbc.Driver"></property> 76         <property name="jdbcUrl" value="http://www.mamicode.com/jdbc:mysql:///mydb"></property> 77         <property name="user" value="http://www.mamicode.com/root"></property> 78         <property name="password" value="http://www.mamicode.com/950613"></property> 79         <property name="initialPoolSize" value="http://www.mamicode.com/4"></property> 80         <property name="maxPoolSize" value="http://www.mamicode.com/9"></property> 81         <property name="maxStatements" value="http://www.mamicode.com/100"></property> 82         <property name="acquireIncrement" value="http://www.mamicode.com/2"></property> 83     </bean> 84      85     <!-- JdbcTemplate工具类实例 --> 86     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 87         <property name="dataSource" ref="dataSource"></property> 88     </bean> 89      90     <!-- dao实例 --> 91     <bean id="deptDao" class="cn.fuyi.a_tx.DeptDao"> 92         <property name="jdbcTemplate" ref="jdbcTemplate"></property> 93     </bean> 94      95     <!-- service实例 --> 96     <bean id="deptService" class="cn.fuyi.a_tx.DeptService"> 97         <property name="deptDao" ref="deptDao"></property> 98     </bean> 99     100     101     <!-- spring的声明式事务配置 -->102     <!-- 1.配置事务管理器类 -->103     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">104         <property name="dataSource" ref="dataSource"></property>105     </bean>106     107     <!-- 2.配置事务增强(如何管理事务?) -->108     <tx:advice id="txAdvice" transaction-manager="transactionManager">109         <tx:attributes>110             <tx:method name="*save*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>111             <tx:method name="*find*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"/>112             <tx:method name="*get*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"/>113         </tx:attributes>114     </tx:advice>115 116     <!-- 3.AOP配置:拦截哪些方法(切入点表达式 + 应用上面的事务增强配置) -->117     <aop:config>118         <aop:pointcut expression="execution(* cn.fuyi.a_tx.DeptService.*(..))" id="pt"/>119         <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>120     </aop:config>121         122 </beans>123 124 package cn.fuyi.a_tx;125 126 import static org.junit.Assert.*;127 128 import org.junit.Test;129 import org.springframework.context.ApplicationContext;130 import org.springframework.context.support.ClassPathXmlApplicationContext;131 132 public class App {133 134     private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/fuyi/a_tx/beans.xml");135     136     @Test137     public void testTx1() throws Exception {138         DeptService ds = (DeptService) ac.getBean("deptService");139         Dept dept = new Dept();140         dept.setDname("哈2哈");141         ds.save(dept);142     }143 }144 145 /**Output146     147      数据库回滚148  149 */
View Code

 

  注解方式实现

    使用注解实现Spring的声明式事务管理,更加简单!

    步骤:

  1) 必须引入Aop相关的jar文件

  2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类

  3)在需要添加事务控制的地方,写上: @Transactional

 

   @Transactional注解:

  1)应用事务的注解

  2)定义到方法上: 当前方法应用spring的声明式事务

  3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理;

  4)定义到父类上: 当执行父类的方法时候应用事务。

技术分享
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  4     xmlns:p="http://www.springframework.org/schema/p" 5     xmlns:context="http://www.springframework.org/schema/context" 6     xmlns:aop="http://www.springframework.org/schema/aop" 7     xmlns:tx="http://www.springframework.org/schema/tx" 8     xsi:schemaLocation="http://www.springframework.org/schema/beans 9          http://www.springframework.org/schema/beans/spring-beans.xsd10           http://www.springframework.org/schema/context11          http://www.springframework.org/schema/context/spring-context.xsd12          http://www.springframework.org/schema/aop13          http://www.springframework.org/schema/aop/spring-aop.xsd14          http://www.springframework.org/schema/tx15           http://www.springframework.org/schema/tx/spring-tx.xsd">16 17     18     <!-- 1. 数据源对象: C3P0连接池 -->19     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">20         <property name="driverClass" value="http://www.mamicode.com/com.mysql.jdbc.Driver"></property>21         <property name="jdbcUrl" value="http://www.mamicode.com/jdbc:mysql:///hib_demo"></property>22         <property name="user" value="http://www.mamicode.com/root"></property>23         <property name="password" value="http://www.mamicode.com/root"></property>24         <property name="initialPoolSize" value="http://www.mamicode.com/3"></property>25         <property name="maxPoolSize" value="http://www.mamicode.com/10"></property>26         <property name="maxStatements" value="http://www.mamicode.com/100"></property>27         <property name="acquireIncrement" value="http://www.mamicode.com/2"></property>28     </bean>29     30     <!-- 2. JdbcTemplate工具类实例 -->31     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">32         <property name="dataSource" ref="dataSource"></property>33     </bean>34     35     <!-- 事务管理器类 -->36     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">37         <property name="dataSource" ref="dataSource"></property>38     </bean>39     40     <!-- 开启注解扫描 -->41     <context:component-scan base-package="cn.itcast.b_anno"></context:component-scan>42     43     <!-- 注解方式实现事务: 指定注解方式实现事务 -->44     <tx:annotation-driven transaction-manager="txManager"/>45 </beans>     
View Code

 

事务属性

 

 1 @Transactional( 2             readOnly = false,  // 读写事务 3             timeout = -1,       // 事务的超时时间不限制 4             noRollbackFor = ArithmeticException.class,  // 遇到数学异常不回滚 5             isolation = Isolation.DEFAULT,              // 事务的隔离级别,数据库的默认 6             propagation = Propagation.REQUIRED            // 事务的传播行为 7     ) 8     public void save(Dept dept){ 9         deptDao.save(dept);10         int i = 1/0;11         deptDao.save(dept);12     }

事务传播行为:

  Propagation.REQUIRED

    指定当前的方法必须在事务的环境下执行;

    如果当前运行的方法,已经存在事务, 就会加入当前的事务;

  Propagation.REQUIRED_NEW

    指定当前的方法必须在事务的环境下执行;

    如果当前运行的方法,已经存在事务:  事务会挂起; 会始终开启一个新的事务,执行完后;  刚才挂起的事务才继续运行。

  举例:

 1 1.Propagation.REQUIRED   2 Class Log{ 3     @Propagation.REQUIRED   4     insertLog();   5 } 6  7 Class DeptDao{ 8     @Propagation.REQUIRED 9     Void  saveDept(){10         insertLog();    // 加入当前事务11         .. 出现异常, 会回滚12         saveDept();13     }14 }15 16 2.Propagation.REQUIRED_NEW  17 Class Log{18     @Propagation.REQUIRED_NEW  19     insertLog();  20 }21 22 Class DeptDao{23     @Propagation.REQUIRED24     Void  saveDept(){25         insertLog();    // 始终开启事务26         .. 异常, 日志不会回滚27         saveDept();28     }29 }

  测试:

 1 package cn.fuyi.a_tx; 2  3 import javax.annotation.Resource; 4  5 import org.springframework.jdbc.core.JdbcTemplate; 6 import org.springframework.stereotype.Repository; 7 import org.springframework.transaction.annotation.Propagation; 8 import org.springframework.transaction.annotation.Transactional; 9 10 @Repository11 public class LogDao {12 13     @Resource14     private JdbcTemplate jdbcTemplate;15     16     @Transactional(propagation=Propagation.REQUIRES_NEW)17     public void insertLog() {18         String sql = "insert into log_ values(‘在保存dept。。。‘)";19         jdbcTemplate.update(sql);20     }21 }22 23 package cn.fuyi.a_tx;24 25 import javax.annotation.Resource;26 27 import org.springframework.stereotype.Service;28 import org.springframework.transaction.annotation.Propagation;29 import org.springframework.transaction.annotation.Transactional;30 31 @Service("deptService")32 public class DeptService {33 34     @Resource(name="deptDao")35     private DeptDao deptDao;36     37     @Resource(name="logDao")38     private LogDao logDao;39     40     41     @Transactional(42             propagation=Propagation.REQUIRED43         )44     public void save(Dept dept) {45         logDao.insertLog();46         int i = 1/0;47         deptDao.save(dept);48     }49 }

 

 

 

 

 

 

spring来了-06-事务控制