专做商品折扣的网站,网站建设费用预算表、,关键词优化seo优化,装饰工程施工方案7.1.事务介绍
7.1.1.什么是事务#xff1f;
当你需要一次执行多条SQL语句时#xff0c;可以使用事务。通俗一点说#xff0c;如果这几条SQL语句全部执行成功#xff0c;则才对数据库进行一次更新#xff0c;如果有一条SQL语句执行失败#xff0c;则这几条SQL语句全部不…7.1.事务介绍
7.1.1.什么是事务
当你需要一次执行多条SQL语句时可以使用事务。通俗一点说如果这几条SQL语句全部执行成功则才对数据库进行一次更新如果有一条SQL语句执行失败则这几条SQL语句全部不进行执行这个时候需要用到事务。
刘德华《无间道》去不了终点回到原点
回顾一下数据库事务的四大特性ACID
原子性Atomicity事务是最小的执行单位不可再分割一致性Consistency事务前后的数据都是正确的隔离性Isolation事物之间相互隔离互不干扰并发执行的事务彼此无法看到对方的中间状态持久性Durability事务一旦提交不可再回滚 7.1.2.数据库本身控制事物
start transaction#记录log(老数据)//1.本地数据库操作张三减少金额//2.本地数据库操作李四增加金额
rollback; #根据log恢复老数据
或
commit; #删除log7.2.3.jdbc中使用事物
1.获取对数据库的连接
2.设置事务不自动提交默认情况是自动提交的
conn.setAutoCommit(false); //其中conn是第一步获取的随数据库的连接对象。3.把想要一次性提交的几个sql语句用事务进行提交
try{Statement stmt null; stmt conn.createStatement(); stmt.executeUpdate(sql1); int a6/0;stmt.executeUpdate(Sql2); . . . conn.commit(); //使用commit提交事务
}4.捕获异常进行数据的回滚回滚一般写在catch块中
catchException e { ... conn.rollback();
}7.2.转账案例
7.2.1.拷贝上一章代码 7.2.2.添加转账业务
7.2.2.1.mapper
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.by.mapper.UserMapper... ...!--转账--update idupdateUserOfSubupdate t_user set moneymoney-#{money} where name#{source}/updateupdate idupdateUserOfAddupdate t_user set moneymoney#{money} where name#{target}/update
/mapperpublic interface UserMapper {... .../**扣钱*/void updateUserOfSub(Param(source) String source, Param(money) Float money);/*加钱*/void updateUserOfAdd(Param(target) String target, Param(money) Float money);
}7.2.2.2.service
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;/*** 转账* param source* param target* param money*/Overridepublic void updateUser(String source, String target, Float money) {userMapper.updateUserOfSub(source, money);int a 6/0;userMapper.updateUserOfAdd(target, money);}
}7.2.2.3.测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}此时我们观察数据表里面的变化情况 转账是成功的但是涉及到业务的问题如果业务层实现类有其中一个环节出问题都会导致灾难。 我们先把数据恢复到转账前。 现在我们故意模拟转账业务出现问题 再来测试
业务执行出错但是 这是因为不满足事务的一致性减钱的事务提交了加钱的事务没有提交甚至都没有执行到。
7.2.Spring中事务控制的API介绍
说明 JavaEE体系进行分层开发事务处理位于业务层Spring提供了分层设计业务层的事务处理解决方案。 Spring框架为我们提供了一组事务控制的接口。具体在后面的小节介绍。这组接口是在spring-tx.RELEASE.jar中。 spring的事务控制都是基于AOP的它既可以使用编程的方式实现也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
7.2.1.PlatformTransactionManager 此接口是spring的事务管理器它里面提供了我们常用的操作事务的方法源代码如下 public interface PlatformTransactionManager { //开启事务 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; //提交事务void commit(TransactionStatus status) throws TransactionException; //回滚事务void rollback(TransactionStatus status) throws TransactionException;
} 真正管理事务的对象 Spring为不同的orm框架提供了不同的PlatformTransactionManager接口实现类 DataSourceTransactionManager使用Spring JDBC或iBatis 进行持久化数据时使用HibernateTransactionManager使用Hibernate版本进行持久化数据时使用
7.2.2.TransactionDefinition TransactionDefinition接口包含与事务属性相关的方法源代码如下 public interface TransactionDefinition {int PROPAGATION_REQUIRED 0;int PROPAGATION_SUPPORTS 1;int PROPAGATION_MANDATORY 2;int PROPAGATION_REQUIRES_NEW 3;int PROPAGATION_NOT_SUPPORTED 4;int PROPAGATION_NEVER 5;int PROPAGATION_NESTED 6;int ISOLATION_DEFAULT -1;int ISOLATION_READ_UNCOMMITTED 1;int ISOLATION_READ_COMMITTED 2;int ISOLATION_REPEATABLE_READ 4;int ISOLATION_SERIALIZABLE 8;int TIMEOUT_DEFAULT -1;//传播行为int getPropagationBehavior();//隔离级别int getIsolationLevel();int getTimeout();boolean isReadOnly();
} TransactionDefinition 接口定义的事务规则包括事务隔离级别、事务传播行为、事务超时、事务的只读、回滚规则属性同时Spring 还为我们提供了一个默认的实现类DefaultTransactionDefinition该类适用于大多数情况。如果该类不能满足需求可以通过实现 TransactionDefinition 接口来实现自己的事务定义。
7.2.2.1.事务隔离级别 事务并发时的安全问题 问题描述隔离级别脏读一个事务读取到另一个事务还未提交的数据read-commited不可重复读一个事务内多次读取一行数据的内容其结果不一致repeatable-read幻读一个事务内多次读取一张表中的内容其结果不一致serialized-read Spring事务隔离级别比数据库事务隔离级别多一个default由低到高为 隔离级别ISOLATION_DEFAULT这是一个platfromtransactionmanager默认的隔离级别使用数据库默认的事务隔离级别。ISOLATION_READ_UNCOMMITTED这是事务最低的隔离级别会产生脏读不可重复读和幻像读。ISOLATION_READ_COMMITTED这种事务隔离级别可以避免脏读出现但是可能会出现不可重复读和幻像读。 Oracle数据库默认的隔离级别。ISOLATION_REPEATABLE_READ这种事务隔离级别可以防止脏读、不可重复读但是可能出现幻像读。MySQL数据库默认的隔离级别。ISOLATION_SERIALIZABLE这是花费最高代价但是最可靠的事务隔离级别事务被处理为顺序执行。除了防止脏读、不可重复读外还避免了幻像读。
7.2.2.2.事务的传播行为 什么是事务传播行为 事务传播行为propagation behavior指的就是当一个事务方法被另一个事务方法调用时这个事务方法应该如何进行。 例如methodA事务方法调用methodB事务方法时methodB是继续在调用者methodA的事务中运行呢还是为自己开启一个新事务运行这就是由methodB的事务传播行为决定的。 Spring定义了七种传播行为 事务传播行为类型说明PROPAGATION_REQUIRED如果当前没有事务就新建一个事务如果已经存在一个事务中加入到这个事务中。这是最常见的选择。PROPAGATION_SUPPORTS支持当前事务如果当前没有事务就以非事务方式执行。PROPAGATION_MANDATORY使用当前的事务如果当前没有事务就抛出异常。PROPAGATION_REQUIRES_NEW新建事务如果当前存在事务把当前事务挂起。PROPAGATION_NOT_SUPPORTED以非事务方式执行操作如果当前存在事务就把当前事务挂起。PROPAGATION_NEVER以非事务方式执行如果当前存在事务则抛出异常。PROPAGATION_NESTED如果当前存在事务则在嵌套事务内执行。如果当前没有事务则执行与REQUIRED类似的操作。
7.2.2.3.事务超时
timeout事务超时时间 当前事务所需操作的数据被其他事务占用则等待。 100自定义等待时间100秒。-1由数据库指定等待时间默认值。建议
7.2.2.4.读写性
readonly 读写性 true只读可提高查询效率适合查询 false可读可写适合增删改
7.2.2.5.回滚规则 TransactionAttribute TransactionAttribute 的默认实现类是DefaultTransactionAttribute 它同时继承了DefaultTransactionDefinition。在DefaultTransactionDefinition 的基础上增加了rollbackOn的实现DefaultTransactionAttribute的实现指定了当异常类型为unchecked exception 的情况下将回滚事务。 rollbackOn 回滚规则可省略或设置 rollbackOn“Exception” 如果事务中抛出 RuntimeException,则自动回滚 如果事务中抛出 CheckException不会自动回滚
7.3.3.TransactionStatus PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象该对象代表一个新的或已经存在的事务源代码如下 public interface TransactionStatus{boolean isNewTransaction();void setRollbackOnly();boolean isRollbackOnly();
}7.4.改造转账案例
7.4.1.applicationContext.xml !--配置事物管理器--bean classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource//bean!--配置事物属性--bean classorg.springframework.transaction.support.DefaultTransactionDefinitionproperty namepropagationBehaviorName valuePROPAGATION_REQUIRED/property namereadOnly valuefalse/property/bean7.4.2.service
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate TransactionDefinition txDefinition;Autowiredprivate PlatformTransactionManager txManager;/*** 转账* param source* param target* param money*/Overridepublic void updateUser(String source, String target, Float money) {// 获取一个事务TransactionStatus txStatus txManager.getTransaction(txDefinition);try {userMapper.updateUserOfSub(source, money);int a 6/0;userMapper.updateUserOfAdd(target, money);//提交事务txManager.commit(txStatus);}catch (Exception e){//回滚事务txManager.rollback(txStatus);e.printStackTrace();}}
}7.4.3.测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 满足执行 我们现在虽然实现了事务控制但是代码非常的臃肿我们可以使用动态代理简化代码
7.3.动态代理控制事务
7.3.1.factory
我们创建一个工厂专门用来给 Service 创建代理对象如下
package com.by.factory;import com.by.service.UserService;
import com.by.service.UserServiceImpl;
import org.hamcrest.Factory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** bean工厂*/
Component
public class BeanFactory {Autowiredprivate UserService userService;Autowiredprivate TransactionDefinition txDefinition;Autowiredprivate PlatformTransactionManager txManager;/*** 获得UserServiceImpl对象** return*/public UserService getUserService() {return (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//开启事务TransactionStatus txStatus txManager.getTransaction(txDefinition);try {method.invoke(userService, args);//提交事务txManager.commit(txStatus);} catch (Exception e) {//回滚事务txManager.rollback(txStatus);e.printStackTrace();}return null;}});}
}7.3.2.applicationContext.xml
!--配置service代理对象--
bean idproxyService factory-beanbeanFactory factory-methodgetUserService/bean7.2.3.service
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;/*** 转账* param source* param target* param money*/Overridepublic void updateUser(String source, String target, Float money) {userMapper.updateUserOfSub(source, money);int a 6/0;userMapper.updateUserOfAdd(target, money);}
}7.2.4.测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)
public class ServiceTest {AutowiredQualifier(proxyService)//注入代理对象private UserService userService;Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 7.4.Spring AOP控制事务
7.4.1.导入schema约束
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/contextxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:txhttp://www.springframework.org/schema/tx xmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd!--配置事物属性bean classorg.springframework.transaction.support.DefaultTransactionDefinitionproperty namepropagationBehaviorName valuePROPAGATION_REQUIRED/property namereadOnly valuefalse/property/bean配置service代理对象bean idproxyService factory-beanbeanFactory factory-methodgetUserService /bean--
/beans 7.4.2.配置增强 !-- 1、增强 --tx:advice idtxAdvice transaction-managertransactionManager!--事务属性--tx:attributes!-- 指定方法名称是业务核心方法read-only是否是只读事务。默认false不只读。isolation指定事务的隔离级别。默认值是使用数据库的默认隔离级别。propagation指定事务的传播行为。timeout指定超时时间。默认值为-1。永不超时。rollback-for用于指定一个异常当执行产生该异常时事务回滚。产生其他异常事务不回滚。省略时任何异常都回滚。--tx:method name* read-onlyfalse propagationREQUIRED/tx:method nameselect* read-onlytrue propagationSUPPORTS/tx:method nameget* read-onlytrue propagationSUPPORTS//tx:attributes/tx:advice7.4.3.配置切点 aop:config!--2、切点--aop:pointcut expressionexecution(* com.by.service.*.*(..)) idpointcut//aop:config7.4.4.配置切面 aop:config!--3、切面--aop:advisor advice-reftxAdvice pointcut-refpointcut/aop:advisor/aop:config7.4.5.factory
删除bean工程
7.4.6.测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 问题一如果我们把方法名称改了那么事务还会回滚吗 修改applicationContext.xml 修改service 问题二如果我们把异常捕捉了那么事务还会回滚吗