概述

  编程式事务控制

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

    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="com.mysql.jdbc.Driver"></property>
 76         <property name="jdbcUrl" value="jdbc:mysql:///mydb"></property>
 77         <property name="user" value="root"></property>
 78         <property name="password" value="950613"></property>
 79         <property name="initialPoolSize" value="4"></property>
 80         <property name="maxPoolSize" value="9"></property>
 81         <property name="maxStatements" value="100"></property>
 82         <property name="acquireIncrement" value="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     @Test
137     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 /**Output
146     
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.xsd
10           http://www.springframework.org/schema/context
11          http://www.springframework.org/schema/context/spring-context.xsd
12          http://www.springframework.org/schema/aop
13          http://www.springframework.org/schema/aop/spring-aop.xsd
14          http://www.springframework.org/schema/tx
15           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="com.mysql.jdbc.Driver"></property>
21         <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
22         <property name="user" value="root"></property>
23         <property name="password" value="root"></property>
24         <property name="initialPoolSize" value="3"></property>
25         <property name="maxPoolSize" value="10"></property>
26         <property name="maxStatements" value="100"></property>
27         <property name="acquireIncrement" value="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.REQUIRED
24     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 @Repository
11 public class LogDao {
12 
13     @Resource
14     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.REQUIRED
43         )
44     public void save(Dept dept) {
45         logDao.insertLog();
46         int i = 1/0;
47         deptDao.save(dept);
48     }
49 }