概述
Spring事务
事务介绍
事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.
事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用
事务的四大特性(ACID)
- 原子性(Atomicity) :是不可分割的最小操作单位,要么同时成功,要么同时失败。
- 一致性(Consistency) :事务操作前后,保证数据的一致性
- 隔离性(Isolation) :多个事务之间,相互独立,互不干扰
- 持久性(Durability) :当事务提交或回滚后,数据库会持久化的保存数据。
Spring事务
作为企业级应用程序框架, Spring 在不同的事务管理 API 之上定义了一个抽象层. 而应用程序开发人员不必了解底层的事务管理 API, 就可以使用 Spring 的事务管理机制.Spring 既支持
【编程式事务】
管理, 也支持【声明式事务】
管理.
编程式事务
就是将业务代码和事务代码放在一起书写,它的耦合性太高,开发中不使用
声明式事务
其实就是将事务代码(spring内置)和业务代码隔离开发, 然后通过一段配置让他们组装运行, 最后达到事务控制的目的.声明式事务就是通过AOP原理实现的.
Spring事务管理器
PlatformTransactionManager
spring事务管理器的顶级接口,它为事务管理封装了一组独立于技术的方法. 无论使用 Spring 的哪种事务管理策略(编程式或声明式), 事务管理器都是必须的.
JpaTransactionManager
使用sun公司提供的jpa规范(SpringData-jpa)框架事务管理器
DataSourceTransactionManager
使用 mybatis、jdbc原生、DbUtils、JdbcTemplate框架事务管理
HibernateTransactionManager
使用hibernate框架事务管理器
相关方法
TransactionStatus getTransaction(TransactionDefinition definition)
获取事务的状态信息
void commit(TransactionStatus status)
提交事务
void rollback(TransactionStatus status)
回滚事务
相关实现类
spring事务管理器先定义好规范,真正的执行者需要实现类完成,导入一个坐标 spring-orm
<!--spring的orm-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
TransactionDefinition
spring事务定义参数的接口,比如定义:事务隔离级别、事务传播行为等等
事务的隔离级别
级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认隔离级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
2 | 读已提交 | read committed | 否 | 是 | 是 | Oracle和SQL Server |
3 | 可重复读 | repeatable read | 否 | 否 | 是 | MySQL |
4 | 串行化 | serializable | 否 | 否 | 否 |
事务的传播行为
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制
REQUIRED(默认传播行为)
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
如果单独调用方法B时,没有事务,spring就给当前方法创建一个新事物
如果方法A中已经存在了事务,调用方法B时,方法B加方法A的事务中…
SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行
如果单独调用方法B时没有事务,咱们就以非事务方法运行
如果方法A中已经存在了事务,调用方法B时,方法B加方法A的事务中…
MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW
新建事务,如果当前在事务中,把当前事务挂起
NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER
以非事务方式运行,如果当前存在事务,抛出异常
NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
read-only
是否只读: 只读事务(增 删 改不能使用,只能查询使用)
timeout
超时时间: 默认值是-1,没有超时限制。如果有,以秒为单位进行设置
TransactionStatus
获取spring当前事务运行的状态。,由返回的状态决定是否执行提交或回滚操作!
Spring事务小结
Spring中的事务控制主要就是通过这三个API实现的
PlatformTransactionManager
负责事务的管理,它是个接口,其子类负责具体工作
TransactionDefinition
定义了事务的一些相关参数
TransactionStatus
代表事务运行的一个实时状态
可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。
Spring 事务搭建
在这里我们使用JdbcTemplate操作数据库,完成转账,并演示事务的操作
- 创建maven工程
- 导入坐标
- 编写Dao和实现类
- 编写Service和实现类
- jdbc配置文件
- applicationContext.xml
- 创建数据库
- 测试
1. 创建maven工程
2. 导入坐标
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--spring的核心坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 设置编译版本为1.8 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
3. 编写Dao和实现类
@Repository
public class AccountDaoImpl implements AccountDao {
// 依赖jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void outUser(String outUser, Double money) {
// 1.编写sql
String sql = "update account set money = money - ? where name = ?";
// 2.执行sql
jdbcTemplate.update(sql, money,outUser);
}
@Override
public void inUser(String inUser, Double money) {
// 1.编写sql
String sql = "update account set money = money + ? where name = ?";
// 2.执行sql
jdbcTemplate.update(sql, money,inUser);
}
}
public interface AccountDao {
/**
* 转出操作
* @param user 转出的账号
* @param money 转出金额
*/
void outUser(String user,Double money);
/**
* 转入操作
* @param user 转入的账号
* @param money 转入金额
*/
void inUser(String user,Double money);
}
4. 编写Service和实现类
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String outUser, String inUser, Double money) {
// 核心业务
accountDao.outUser(outUser, money);
accountDao.inUser(inUser, money);
}
}
public interface AccountService {
/**
* 转账
* @param outUser 转出用户
* @param inUser 转入用户
* @param money 金额
*/
public void transfer(String outUser, String inUser, Double money);
}
5. jdbc配置文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_test1?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=1234
6. applicationContext.xml
<!--开启注解-->
<context:component-scan base-package="com.lifly"/>
<!--开启事务注解-->
<tx:annotation-driven/>
<!--通过context:property-placeholder 记载jdbc.properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置Druid数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置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>
7.创建数据库
-- 创建数据表
CREATE TABLE account ( -- 账户表
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(32),
money DOUBLE
);
-- 添加数据
INSERT INTO account (`name`, money) VALUES ('蝴蝶姐', 1000), ('罗志祥', 1000);
8.测试
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTransferTest {
@Autowired
private AccountService accountService;
@Test
public void test(){
accountService.transfer("罗志祥","蝴蝶姐",500);
}
}
Spring编程式事务
结合着转账案例演示Spring编程事务
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
事务的模板
@Service
public class xxxServiceImpl implements xxxService{
@Autowired
private PlatformTransactionManager transactionManager;
public void method() {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置是否只读,为false才支持事务
def.setReadOnly(false);
// 设置隔离级别
def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 设置事务的传播行为
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 对事务管理器进行配置
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务操作
// ......................
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback(status);
}
}
}
修改UserServiceImpl
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Autowired
private PlatformTransactionManager transactionManager;
@Override
public void transfer(String outUser, String inUser, Double money) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置是否只读,为false才支持事务
def.setReadOnly(false);
// 设置隔离级别
def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 设置事务的传播行为
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 对事务管理器进行配置
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务操作
// 核心业务
accountDao.outUser(outUser, money);
// 制造异常
System.out.println(2/0);
accountDao.inUser(inUser, money);
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback(status);
}
}
}
Spring声明式事务
在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的
Spirng声明式事务思想
目标对象:AccountServiceImpl
通知对象:DataSourceTransactionManager
配置切面:xml,切面
环境搭建
其他配置与转账案例环境是一致的,只不过是在本项目中,我们需要导入以下两个坐标
<!--spring的orm-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--aspectj-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
Spring声明式事务xml版
引入事务的约束
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
配置通知类
在这里我们需要将事务管理器,升级为事务通知类
<!--
将事务管理器,升级为事务通知类
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--定义事务管理器信息-->
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--
配置aop
-->
<aop:config>
<!--
此标签仅支持Spring事务管理器使用
通知+切点=切面
-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itfxp.service..*.*(..))"></aop:advisor>
</aop:config>
测试
public class SpringTransferTest {
@Autowired
private AccountService accountService;
@Test
public void test01() {
accountService.transfer("罗志祥","蝴蝶姐",500.0);
}
}
声明式事务细节
在配置文件中,配置事务时,以下这个配置,这个配置的意思是:我要对所有的方法进行事务管理。
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
如果我们想要对某一类的方法或某一个方法进行事务管理 ,就不能再写
*
了
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--
定义事务管理器信息 DefaultTransactionDefinition
我们可以控制指定的方法,设置事务隔离级别、传播行为、是否只读、是否超时...
name="transfer" 需要控制事务的方法名
isolation="DEFAULT" 设置当前方法的事务隔离界别,mysql默认级别:repeatable_read
propagation="REQUIRED" 设置当前方法的事务传播行为 ,REQUIRED:当前方法必须有一个事务(单独 使用开启,别人调用加入对方事务)
read-only="false" 当前方式为非只读(增删改用的)
timeout="-1" 事务超时时间,-1:永不超时
-->
<tx:attributes>
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
</tx:attributes>
</tx:advice>
Spring声明式事务注解版
开启事务注解
<!--开启事务注解支持-->
<tx:annotation-driven />
在目标方法上加事务
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
// 那个方法需要被控制,我们就需要在那个方法上加 @Transactional注解即可
@Transactional
public void transfer(String outUser, String inUser, Double money) {
accountDao.outUser(outUser, money);
accountDao.inUser(inUser, money);
}
}
注解事务细节
配置事务的隔离别和传播行为
我们使用注解的形式,也可以配置像xml的一些事务的隔离级别和事务的传播行为以及是否只读等内容
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
// <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = true,timeout = -1)
public void transfer(String outUser, String inUser, Double money) {
accountDao.outUser(outUser, money);
System.out.println(2/0);
accountDao.inUser(inUser, money);
}
}
当前类中的方法全部被事务管理
只需要在该类上加上@Transactional注解即可
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
}
最后
以上就是壮观野狼为你收集整理的详解(Spring事务介绍,快速入门,环境搭建,编程式事务,注解式事务以及注意的细节)Spring事务的全部内容,希望文章能够帮你解决详解(Spring事务介绍,快速入门,环境搭建,编程式事务,注解式事务以及注意的细节)Spring事务所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复