相关文章
前言
什么是事务?根据 维基百科事务 介绍,数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。简单来说,事务就是将一系列操作当成一个不可拆分的执行逻辑单元,这些要么都成功,要么都失败。事务具有4个属性:原子性、一致性、隔离性、持久性。称为ACID特性。
Spring 事务
在使用 Spring 进行开发过程中,一般都会使用 Spring 来进行事务的控制,接下来就来看下 Spring 使用事务的详细过程,包括事务的传播方式等。本文根据官方文档 的介绍,结合例子来进行说明。
Spring 事务支持两种方式,编程式事务和声明式事务,下面的栗子会使用声明式事务来举例,即使用 @Transactional 注解的方式
栗子
首先来看个简单栗子,后面再来对事务的一些属性进行详细的分析和介绍。
1. 首先来看下两个数据库表结构 user 表和 address 表:
user 表:
address 表:
2. Spring 配置文件启动事务:
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/tsmyk"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
3. 定义需要事务执行的方法:
接口
public interface IUserService {
void add(User user) throws RuntimeException;
}
实现类:
public class UserServiceImpl implements IUserService {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Transactional
@Override
public void add(User user) throws RuntimeException {
String sql = "insert into user(name, age, sex, money, job) values (?, ?, ?, ?, ?)";
Object[] args = new Object[]{user.getName(), user.getAge(),user.getSex(),user.getMoney(), user.getJob()};
jdbcTemplate.update(sql, args);
throw new RuntimeException("保存出现异常...");
}
}
这里使用 JdbcTemplate 来操作数据库
4. 在上述的配置文件中配置该 bean:
<bean id="txUserService" class="main.tsmyk.transaction.UserServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
5. 单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/resources/myspring.xml")
public class TestTransaction {
@Autowired
private IUserService userServiceImpl;
@Test
public void test1() throws RuntimeException {
User user = new User("xiaoqi", 20, 1, 1000, "java");
userServiceImpl.add(user);
}
}
6. 运行结果会抛出异常:
7. 此时数据库的数据还是原来的,数据插入失败:
上述的栗子中,在 add() 方法加上了事务注解 @Transactional ,当该方法抛出异常的时候,数据库会进行回滚,数据插入失败。
事务原理
Spring 事务是使用 AOP 来实现的,在 Spring AOP 注解方式源码解析 和 Spring AOP 创建代理的源码解析 文章中,了解到,在执行目标方法之前和之后,我们可以进行一些增强操作,而这恰恰可以符合事务的使用情况,在目标方法执行成功后,提交事务,失败的时候,回滚事务。当然,我们还可以通过 AOP 来自定义事务的行为。从概念上讲,在事务代理上调用方法看起来如下所示:
当客户端调用的时候,调用的是代理对象,在执行目标方法之前,会创建事务,即事务增强,之后会执行我们自