首页 > 代码库 > 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 */
注解方式实现
使用注解实现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>
事务属性
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-事务控制