专题网站模板,广西人才网,商丘网站建设模板,千牛商家版网站建设目录 1.Spring的事务1.1 什么是事务#xff1f;1.2 事务的特性#xff08;ACID#xff09;1.3 Spring 事务实现方式有哪些#xff1f;1.4 Spring事务管理接口介绍1.4.1 PlatformTransactionManager:事务管理接口1.4.2 TransactionDefinition:事务属性事务管理器接口1.4.3 T… 目录 1.Spring的事务1.1 什么是事务1.2 事务的特性ACID1.3 Spring 事务实现方式有哪些1.4 Spring事务管理接口介绍1.4.1 PlatformTransactionManager:事务管理接口1.4.2 TransactionDefinition:事务属性事务管理器接口1.4.3 TransactionStatus:事务状态 2.事务入门案例3.动态代理控制事务4.Spring AOP控制事务5. 基于注解的AOP控制事务5.1 Transactional 注解使用详解5.2 使用注解控制事务 6.Spring整合MyBatis6.1 创建工程6.2 配置数据源6.3 整合MyBatis6.4 测试 1.Spring的事务
1.1 什么是事务
需要一次执行多条SQL语句时可以使用事务。通俗一点说如果这几条SQL语句全部执行成功则才对数据库进行一次更新如果有一条SQL语句执行失败则这几条SQL语句全部不进行执行即要么都执行要么都不执行。这个时候需要用到事务。
1.2 事务的特性ACID
原子性Atomicity事务是最小的执行单位不允许分割。事务的原子性确保动作要么全部完成要么完全不起作用一致性Consistency执行事务前后数据保持一致例如转账业务中无论事务是否成功转账者和收款人的总额应该是不变的隔离性Isolation并发访问数据库时一个用户的事务不被其他事务所干扰各并发事务之间数据库是独立的持久性Durability一个事务被提交之后。它对数据库中数据的改变是持久的即使数据库发生故障也不应该对其有任何影响。
1.3 Spring 事务实现方式有哪些
Spring事务机制主要包括声明式事务和编程式事务。
编程式事务通过编程的方式管理事务这种方式带来了很大的灵活性但很难维护。声明式事务将事务管理代码从业务方法中分离出来通过aop进行封装。Spring声明式事务使得我们无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。使用 Transactional 注解开启声明式事务。
1.4 Spring事务管理接口介绍
Spring 框架中事务管理相关最重要的 3 个接口如下
PlatformTransactionManager平台事务管理器Spring 事务策略的核心。TransactionDefinition事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。TransactionStatus事务运行状态。
1.4.1 PlatformTransactionManager:事务管理接口
Spring 并不直接管理事务而是提供了多种事务管理器 。
Spring 事务管理器的接口是PlatformTransactionManager 。
通过这个接口Spring 为各个平台如JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager接口中定义了三个方法
public interface PlatformTransactionManager { //开启事务 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; //提交事务void commit(TransactionStatus status) throws TransactionException; //回滚事务void rollback(TransactionStatus status) throws TransactionException;
} 1.4.2 TransactionDefinition:事务属性事务管理器接口
PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务这个方法里面的参数是 TransactionDefinition 类 这个类就定义了一些基本的事务属性。什么是事务属性呢
事务属性可以理解成事务的一些基本配置描述了事务策略如何应用到方法上。事务属性包含了 5 个方面
隔离级别传播行为回滚规则是否只读事务超时
TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。
package org.springframework.transaction;import org.springframework.lang.Nullable;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;// 返回事务的传播行为默认值为 REQUIRED。int getPropagationBehavior();//返回事务的隔离级别默认值是 DEFAULTint getIsolationLevel();// 返回事务的超时时间默认值为-1。如果超过该时间限制但事务还没有完成则自动回滚事务。int getTimeout();// 返回是否为只读事务默认值为 falseboolean isReadOnly();NullableString getName();
}事务隔离级别 事务并发时的安全问题 问题描述隔离级别脏读一个事务读取到另一个事务还未提交的数据read-commited不可重复读一个事务内多次读取一行数据的内容其结果不一致repeatable-read幻读一个事务内多次读取一张表中的内容其结果不一致serialized-read Spring事务隔离级别比数据库事务隔离级别多一个default由低到高为 隔离级别ISOLATION_DEFAULT这是一个platfromtransactionmanager默认的隔离级别使用数据库默认的事务隔离级别。ISOLATION_READ_UNCOMMITTED这是事务最低的隔离级别会产生脏读不可重复读和幻像读。ISOLATION_READ_COMMITTED这种事务隔离级别可以避免脏读出现但是可能会出现不可重复读和幻像读。 Oracle数据库默认的隔离级别。ISOLATION_REPEATABLE_READ这种事务隔离级别可以防止脏读、不可重复读但是可能出现幻像读。MySQL数据库默认的隔离级别。ISOLATION_SERIALIZABLE这是花费最高代价但是最可靠的事务隔离级别事务被处理为顺序执行。除了防止脏读、不可重复读外还避免了幻像读。
事务的传播行为 什么是事务传播行为 事务传播行为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类似的操作。
事务超时
timeout事务超时时间 当前事务所需操作的数据被其他事务占用则等待。 100自定义等待时间100秒。-1由数据库指定等待时间默认值。建议
读写性
readonly 读写性 true只读可提高查询效率适合查询 false可读可写适合增删改
事务回滚规则 这些规则定义了哪些异常会导致事务回滚而哪些不会。 默认情况下事务只有遇到运行期异常RuntimeException 的子类时才会回滚Error 也会导致事务回滚但是在遇到检查型Checked异常时不会回滚。
1.4.3 TransactionStatus:事务状态
TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
PlatformTransactionManager.getTransaction(…)方法返回一个 TransactionStatus 对象。
TransactionStatus 接口内容如下
public interface TransactionStatus{boolean isNewTransaction(); // 是否是新的事务boolean hasSavepoint(); // 是否有恢复点void setRollbackOnly(); // 设置为只回滚boolean isRollbackOnly(); // 是否为只回滚boolean isCompleted; // 是否已完成
}2.事务入门案例
通过实现银行转账功能初步认识事务
applicationContext.xml 创建事物管理器和事物属性bean对象使用默认id !--配置事物管理器--bean classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource//bean!--配置事物属性--bean classorg.springframework.transaction.support.DefaultTransactionDefinitionproperty namepropagationBehaviorName valuePROPAGATION_REQUIRED/property namereadOnly valuefalse/property/beanservice 业务层实现事务手动触发一个异常进行测试
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();}}
}测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 满足执行
我们现在虽然实现了事务控制但是代码非常的臃肿我们可以使用动态代理简化代码
3.动态代理控制事务
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;}});}
}applicationContext.xml
!--配置service代理对象--
bean idproxyService factory-beanbeanFactory factory-methodgetUserService/beanservice
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);}
}测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)
public class ServiceTest {AutowiredQualifier(proxyService)//注入代理对象private UserService userService;Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 动态代理需要手动编写被代理类来指定增强代码AOP可自动创建代理类从而进一步简化代码
4.Spring AOP控制事务
导入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/beans 配置增强 !-- 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:advice配置切点 aop:config!--2、切点--aop:pointcut expressionexecution(* com.by.service.*.*(..)) idpointcut//aop:config配置切面 aop:config!--3、切面--aop:advisor advice-reftxAdvice pointcut-refpointcut/aop:advisor/aop:config测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚
5. 基于注解的AOP控制事务
5.1 Transactional 注解使用详解
Transactional 的作用范围
方法推荐将注解使用于方法上不过需要注意的是该注解只能应用到 public 方法上否则不生效。
类如果这个注解使用在类上的话表明该注解对该类中所有的 public 方法都生效。
接口不推荐在接口上使用。
Transactional 的常用配置参数
Transactional注解源码如下里面包含了基本事务属性的配置
Target({ElementType.TYPE, ElementType.METHOD})
Retention(RetentionPolicy.RUNTIME)
Inherited
Documented
public interface Transactional {AliasFor(transactionManager)String value() default ;AliasFor(value)String transactionManager() default ;Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class? extends Throwable[] rollbackFor() default {};String[] rollbackForClassName() default {};Class? extends Throwable[] noRollbackFor() default {};String[] noRollbackForClassName() default {};}Transactional 的常用配置参数总结只列出了 5 比较常用的
属性名说明propagation事务的传播行为默认值为 REQUIRED可选的值在上面介绍过isolation事务的隔离级别默认值采用 DEFAULT可选的值在上面介绍过timeout事务的超时时间默认值为-1不会超时。如果超过该时间限制但事务还没有完成则自动回滚事务。readOnly指定事务是否为只读事务默认值为 false。rollbackFor用于指定能够触发事务回滚的异常类型并且可以指定多个异常类型。
Transactional 事务注解原理
Transactional 的工作机制是基于 AOP 实现的AOP 又是使用动态代理实现的。如果目标对象实现了接口默认情况下会采用 JDK 的动态代理如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
5.2 使用注解控制事务
applicationContext.xml
!-- 开启spring对注解事务的支持 --
tx:annotation-driven transaction-managertransactionManager/ service
Service
Transactional(readOnlytrue,propagation Propagation.SUPPORTS)
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;/*** 转账* param source* param target* param money*/OverrideTransactional(readOnlyfalse,propagationPropagation.REQUIRED)public void updateUser(String source, String target, Float money) {userMapper.updateUserOfSub(source, money);int a 6/0;userMapper.updateUserOfAdd(target, money);}
}测试
RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;/*** 转账业务*/Testpublic void testUpdate(){userService.updateUser(张三丰,宋远桥,1F);}
}事务回滚 6.Spring整合MyBatis
6.1 创建工程 pom.xml添加工程依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.by/groupIdartifactIdSpring_MyBatis/artifactIdversion1.0-SNAPSHOT/versionproperties!-- 项目源码及编译输出的编码 --project.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncoding!-- 项目编译JDK版本 --maven.compiler.source1.8/maven.compiler.sourcemaven.compiler.target1.8/maven.compiler.target/propertiesdependencies!-- Spring常用依赖 --dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.1.8.RELEASE/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion5.1.8.RELEASE/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion5.1.8.RELEASE/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.1.8.RELEASE/version/dependency!-- MySql --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.47/version/dependency!--连接池--dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.0/version/dependency!--mybatis--dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.3/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion2.0.3/version/dependency!--日志--dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactIdversion1.7.26/version/dependency!--junit--dependencygroupIdorg.springframework/groupIdartifactIdspring-test/artifactIdversion5.1.8.RELEASE/version/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.32/version/dependency/dependenciesbuildresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.xml/include/includes/resourceresourcedirectorysrc/main/resources/directory/resource/resources/build
/projectlog4j.properties配置日志输出文件
log4j.rootLoggerDEBUG,A1log4j.appender.A1org.apache.log4j.ConsoleAppender
log4j.appender.A1.layoutorg.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern[%t] [%c]-[%p] %m%napplicationContext.xml
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/contextxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi: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.xsdcontext:component-scan base-packagecom.by/context:component-scan
/beans6.2 配置数据源
db.properties配置数据库连接信息
jdbc.driverClasscom.mysql.jdbc.Driver
jdbc.urljdbc:mysql://localhost:3306/spring?useUnicodetruecharacterEncodingUTF-8
jdbc.usernameroot
jdbc.password1111applicationContext.xml配置数据源
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:contexthttp://www.springframework.org/schema/contextxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi: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.xsd!--加载配置文件--context:property-placeholder locationclasspath:db.properties /!-- 配置数据源 --bean iddataSource classcom.alibaba.druid.pool.DruidDataSourcedestroy-methodcloseproperty namedriverClassName value${jdbc.driverClass}/property nameurl value${jdbc.url}/property nameusername value${jdbc.username}/property namepassword value${jdbc.password}//bean
/beans6.3 整合MyBatis
applicationContext.xml
!--会话工厂--
bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource/propertyproperty nametypeAliasesPackage valuecom.by.pojo/property
/bean!--扫描basePackage所指定的包下的所有接口生成代理类并交给spring管理--
bean classorg.mybatis.spring.mapper.MapperScannerConfigurer!--mapper所在的包--property namebasePackage valuecom.by.mapper/propertyproperty namesqlSessionFactoryBeanName valuesqlSessionFactory/property
/bean6.4 测试
创建表
CREATE TABLE t_user (id int(11) NOT NULL AUTO_INCREMENT,name varchar(255) DEFAULT NULL,money float DEFAULT NULL,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT14 DEFAULT CHARSETutf8;pojo
package com.by.pojo;Data
NoArgsConstructor
AllArgsConstructor
Accessors(chain true)
public class User {private Integer id;private String name;private Float money;}mapper
public interface UserMapper {public void addUser(User user);
}?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.UserMapperinsert idaddUser parameterTypeUserinsert into t_user(name,money) values(#{name},#{money})/insert
/mapperservice
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserMapper userMapper;Overridepublic void addUser(User user) {userMapper.addUser(user);}
}junit
package com.by.test;import com.by.pojo.User;
import com.by.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classpath:applicationContext.xml)//加载配置文件
public class ServiceTest {Autowiredprivate UserService userService;Testpublic void testAdd(){userService.addUser(new User(张三丰,4000F));userService.addUser(new User(宋远桥,2000F));}
}