目录
①:平台事物管理器PlatformTransactionManager接口
②:事务定义TransactionDefinition接口定义如下:
③:事务状态TransactionStatus接口定义如下:
1.首先使用Maven构建工程,需添加Mysql、Spring等包
2.添加Spring的配置文件Spring-config.xml
2.基于TransactionTemplate的编程式事务管理
一、事务的基本介绍
概念:事务一般特指数据库事务(Database Transaction),是指作为一个程序执行单元执行的一系列操作,要么全执行,要么全不执行。
特性:原子性(Atomicity):一个事物是不可分割的工作单位 (从结构上进行处理,保证sql的执行准确)
一致性(Consistency):事务必须是使数据库从一个以执行状态到另一个一致性状态 (保证业务的一致性)
隔离性(isolation):一个事务的执行不能被其他事务干扰(用于处理并发情况)
持久性(Durability):一个事务一旦提交,它对数据库中数据的改变是永久性的(保存到磁盘上)
Spring的事务管理是基于Mysql和JDBC的,所以接下来首先介绍Mysql和JDBC事务
二、MySQL事务处理
https://blog.youkuaiyun.com/weixin_41963657/article/details/89428840
三、JDBC事务处理
JDBC的事务处理是基于Connection的,JDBC通过Connection对象进行事务管理
JDBC默认事务处理是自动提交
事务的相关方法:setAutoCommit设置是否自动提交
commit提交事务
rollback回滚事务
隔离级别与Mysql处理类似
四、Spring的事务处理内容介绍
1.Spring事务处理的核心API
①:平台事物管理器PlatformTransactionManager接口
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
- getTransaction():开启/获取一个事务,通过传递的TransactionDefinition参数来告诉该方法需要开启一个什么样的事务,返回一个TransactionStatus对象
- commit():用于提交TransactionStatus参数代表的事务
- rollback():用于回滚TransactionStatus参数代表的事务
②:事务定义TransactionDefinition接口定义如下:
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
- getPropagationBehavior():返回定义的事务传播行为;
- getIsolationLevel():返回定义的事务隔离级别;
- getTimeout():返回定义的事务超时时间;
- isReadOnly():返回定义的事务是否是只读的;
- getName():返回定义的事务名字。
③:事务状态TransactionStatus接口定义如下:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
- isNewTransaction():返回当前事务状态是否是新事务;
- hasSavepoint():返回当前事务是否有保存点;
- setRollbackOnly():设置当前事务应该回滚;
- isRollbackOnly(():返回当前事务是否应该回滚;
- flush():用于刷新底层会话中的修改到数据库,一般用于刷新如Hibernate/JPA的会话,可能对如JDBC类型的事务无任何影响;
- isCompleted():当前事务否已经完成。
④:事务管理器的实现类(这里举三个常用的实现类)
- DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
- JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理;
- HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate 3.2+版本;
2.解析Spring事务的传播行为
简单来说有一个A方法,当A方法被其他方法调用了,这时就必须指定A方法如何传播。例如:方法可能继续在现有的事务中运行,也可能开启一个新的事务等。
- PROPAGATION_REQUIRED(常用):支持当前事务,如果当前没有事务,就新建一个事务。
- PROPAGATIONL SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATIONL REQUIRES_ NEW:新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATIONLNEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATIONNESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。
举例比如REQUIRED 传播行为:当A()方法调用了B()方法,不管A是否有事务,也不管B是有事务,都会把调用的B方法开启事务,这样就保证了B方法里的步骤一定在一个事务中
3.事务管理的API的关系
Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态及信息记录到事务状态的对象中。
五、搭建环境(注解方式)
1.首先使用Maven构建工程,需添加Mysql、Spring等包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spring</groupId>
<artifactId>springTransaction</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
</project>
2.添加Spring的配置文件Spring-config.xml
需在配置文件中添加包扫描、配置数据库信息,由于代码中使用了JdbcTemplate所以也要配置Spring的JdbcTemplate方式。
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mytest"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="com.xyz.*"/>
</beans>
3.创建建数据库表
这里仅仅为了说明Spring事务,所以简单的建了一张表,person表中只有id、name两个字段
CREATE TABLE person(
id INT,
NAME VARCHAR(20)
);
4.创建数据库表对应的实体类
@Component
public class Person {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
5.创建持久层接口及实现类
@Repository
public interface personDao {
void insert(Person person);
void delete(int id);
Person query(int id);
}
@Repository
public class personDaoImpl implements personDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void insert(Person person) {
String sql = "insert into person(id,name) values(?,?)";
jdbcTemplate.update(sql,person.getId(),person.getName());
}
@Override
public void delete(int id) {
String sql = "delete from person where id=?";
jdbcTemplate.update(sql,id);
}
@Override
public Person query(int id) {
String sql = "select * from person where id="+id;
return jdbcTemplate.queryForObject(sql, new RowMapper<Person>() {
@Override
public Person mapRow(ResultSet resultSet, int i) throws SQLException {
Person person = new Person();
person.setName(resultSet.getString("name"));
person.setId(resultSet.getInt("id"));
return person;
}
});
}
}
六、Spring编程式事务处理(入门案例)
1.基于底层API的编程式事务管理
由于需使用PlatformTransactionManager、TransactionDefinition、TransactionStatus所以在spring-config.xml文件中配置相关的Bean。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionDefinition" class="org.springframework.transaction.support.DefaultTransactionDefinition">
</bean>
2.测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Spring-config.xml")
public class test {
@Autowired
Person person;
@Autowired
private personDao personDao;
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
@Test
public void demo1(){
person.setId(1);
person.setName("张三");
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
Person query = personDao.query(2);
System.out.println(query);
transactionManager.commit(transaction);
}
@Test
public void demo2(){
person.setId(2);
person.setName("李四");
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
Person query = personDao.query(2);
System.out.println(query);
transactionManager.rollback(transaction);
}
}
运行demo1可以看到数据库person表添加了一条数据,但demo2未添加。
2.基于TransactionTemplate的编程式事务管理
由于基于底层API的编程式事务方式有些代码过于臃肿,Spring为了简化代码创建了一个TransactionTemplate类,通过该类简化底层API式代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Spring-config.xml")
public class test2 {
@Autowired
Person person;
@Autowired
private personDao personDao;
@Autowired
private TransactionTemplate transactionTemplate;
@Test
public void demo1(){
person.setId(3);
person.setName("李四");
transactionTemplate.equals(new TransactionCallback() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
try{
personDao.insert(person);
}catch (Exception e){
transactionStatus.setRollbackOnly();
}
return null;
}
});
}
}
同时也需要修改配置文件添加TransactionTemplate的Bean
TransactionTemplate必须要指定事务管理器,其他的隔离级别等属性可以采取默认
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
七、Spring声明式事务处理(入门案例)
概述:Spring的声明式事务处理是建立在AOP的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。建议在开发中使用声明式事务,是因为这样可以使得业务代码纯粹干净,方便后期的代码维护。
①.基于<tx>命名空间的声明式事务管理
首先来看看配置文件,可以看到多了<tx>、<aop>标签,其中<tx>标签是向指定名称的方法添加事务,<aop>是确定方法的位置
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="dataSource"class="org.springfra
mework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mytest"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="com.xyz*"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="query" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.xyz.dao.daoImpl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试代码如下
可以看出使用了<tx>方式大大减少了代码量
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Spring-config.xml")
public class test3 {
@Autowired
private Person person;
@Autowired
private personDao personDao;
@Test
public void demo1(){
person.setId(5);
person.setName("王五");
personDao.insert(person);
}
}
②.基于@Transactional的声明式事务管理
@Transaction自动进行事务管理,当方法异常时会自动回滚,只需将想要事务处理的方法上添加@Transactional注解即可!
测试:对于下面的代码,运行后控制台仅仅输出了报错信息,而没有输出id=666的person信息,说明事务处理成功,
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Spring-config.xml")
public class test4 {
@Autowired
private Person person;
@Autowired
private personDao personDao;
@Test
@Transactional
public void demo1(){
person.setId(666);
person.setName("666");
personDao.insert(person);
Person p = personDao.query(666);
System.out.println(p);
System.out.println(1/0);
}
}
八、总结
一般开发中,大多使用<tx>命名空间和@Transaction,当需要进行事务处理的方法较少时使用@Transaction,但是当需要进行事务处理的方法太多时选择<tx>命名空间方式更加简便,毕竟可以根据名称前缀批量进行事务处理。
不论何种Spring事务处理方式,都需要配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>