10.Spring 对事务的整合
10.1对事务的复习
什么是事务:
- 事务(TRANSACTION) 是作为单个逻辑工作单元执行的一系列操作。
- 多个操作作为一个整体向系统提交,要么都执行,要么都不执行。
- 事务是一个不可分割的逻辑单元。
事务的特性:
事务具备以下四个特性,简称ACID属性。
l 原子性(Atomicity):
事务是一个完整的操作,事务的各步操作都是不可再分的,要么都执行, 要么都不执行。
l 一致性(Consistency):
当事务完成时,数据必须处于一致的状态。
l 隔离性(Isolation):
并发事务之间相互独立、隔离,它不应以任何方式依赖于或影响其他事 务。
l 持久性(Durability):
事务完成后,它对数据库的修改被永久保持。
10.2Spring中对事务的整合
在Spring中,所有操作事务的类都继承自 PlatformTransactionManager
事务的隔离级别
- ISOLATION_READ_UNCOMMITTED:读未提交
- ISOLATION_READ_COMMITTED:读已提交
- ISOLATION_REPEATABLE_READ:可重复读
- ISOLATION_SERIALIZABLE:串行化
脏读、不可重复读、幻读
脏读:A事务读取B事务尚未提交的更改数据,并在这个数据的基础上进行操作,这时候如果事务B回滚,那么A事务读到的数据是不被承认的。例如常见的取款事务和转账事务:
不可重复读:不可重复读是指A事务读取了B事务已经提交的更改数据。假如A在取款事务的过程中,B往该账户转账100,A两次读取的余额发生不一致。
幻读:A事务读取B事务提交的新增数据,会引发幻读问题。幻读一般发生在计算统计数据的事务中,例如银行系统在同一个事务中两次统计存款账户的总金额,在两次统计中,刚好新增了一个存款账户,存入了100,这时候两次统计的总金额不一致。
事务的七种传播行为
什么是事务的传播行为:事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。
案例一:转账
结构如下:
首先先创建entity与Dao与DaoImpl
public interface IBankDao { //转出 int RolloutMoney(String code_crde,String code_money); //转入 int RollinMoney(String code_crde,String code_money); }
@Repository public class IBankDaoImpl implements IBankDao { @Resource private JdbcTemplate jdbcTemplate; @Override public int RolloutMoney(String code_crde, String code_money) { int outcount = jdbcTemplate.update("update bank set code_money=code_money-? where code_crde=?", code_money, code_crde); return outcount; } @Override public int RollinMoney(String code_crde, String code_money) { int incount = jdbcTemplate.update("update bank set code_money=code_money+? where code_crde=?", code_money, code_crde); return incount; } }
public class Bank { private String code_crde; private String code_name; private String code_money;
创建Service与impl
public interface IBankServce { int transfer(String out_code_crde,String in_code_crde,String money) throws Exception; }
@Service("iBankServce") public class IBankServiceImpl implements IBankServce { @Resource private IBankDao iBankDao; @Override public int transfer(String out_code_crde, String in_code_crde, String money) { int outcount = iBankDao.RolloutMoney(out_code_crde, money); if (true){ throw new RuntimeException("异常"); } int incount = iBankDao.RollinMoney(in_code_crde, money); return outcount+incount; } }
编写text
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-day19jdbcZHUJIE.xml"); IBankServce iBankServce = (IBankServce)ctx.getBean("transactionProxy"); int transfer = 0; try { transfer = iBankServce.transfer("987654321", "1234568479", "100"); } catch (Exception e) { e.printStackTrace(); } if (transfer>0){ System.out.println("cg"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="cn.bank"></context:component-scan> <!--2.识别到配置文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--1.配置数据源--> <!--Spring内置的内置源:创建或者用来提供连接的,不负责管理,使用连接池--> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--3.构建jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="datasource"></property> </bean> <!--事物管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--管理数据--> <property name="dataSource" ref="datasource"></property> </bean> <!--事物代理工厂Bean--> <bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--事物管理器--> <property name="transactionManager" ref="transactionManager"></property> <!--目标对象--> <property name="target" ref="iBankServce"></property> <!--设置方法--> <property name="transactionAttributes"> <props> <!--方法对应的隔离以及传播行为--> <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> </props> </property> </bean> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
如图所示,出现异常则直接回滚,数据库数据不变
Aop实现方式
<context:component-scan base-package="cn.bank"></context:component-scan> <!--2.识别到配置文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--1.配置数据源--> <!--Spring内置的内置源:创建或者用来提供连接的,不负责管理,使用连接池--> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--3.构建jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="datasource"></property> </bean> <!--事物管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--管理数据--> <property name="dataSource" ref="datasource"></property> </bean> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="trans*" isolation="READ_COMMITTED" propagation="REQUIRED"></tx:method> </tx:attributes> </tx:advice> <aop:config> <!--切点--> <aop:pointcut id="poincut" expression="execution(* *..service.Impl.*.*(..))"/> <aop:advisor advice-ref="transactionAdvice" pointcut-ref="poincut"></aop:advisor> </aop:config> </beans>
注解实现方式
前置代码一样后置ServiceImpl如下:
@Service("iBankServce") public class IBankServiceImpl implements IBankServce { @Resource private IBankDao iBankDao; @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED) @Override public int transfer(String out_code_crde, String in_code_crde, String money) { int outcount = iBankDao.RolloutMoney(out_code_crde, money); if (true){ throw new RuntimeException("异常"); } int incount = iBankDao.RollinMoney(in_code_crde, money); return outcount+incount; } }
Xml文件进行注解的读取
<context:component-scan base-package="cn.bankzhu"></context:component-scan> <!--2.识别到配置文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--1.配置数据源--> <!--Spring内置的内置源:创建或者用来提供连接的,不负责管理,使用连接池--> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--3.构建jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="datasource"></property> </bean> <!--事物管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--管理数据--> <property name="dataSource" ref="datasource"></property> </bean> <!--注解支持--> <tx:annotation-driven/> </beans>