Spring的事务管理
事务概念
1.什么是事务
“一荣俱荣,一损俱损”这句话很能体现事务的思想,很多复杂的事务要分布进行,但它们组成了一个整体,要么整体生效,要么整体失效。这种思想反映在数据库上,就是多条sql语句,要么所有执行成功,要么所有执行失败。
2.事务的四个特性(ACID)
- 原子性(Atomic):表示组成的一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。事务中的任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。
- 一致性(Consistency):事务操作成功后,数据库所处的状态和他的业务规则是一致的,即数据不会被破坏。如从A账户转账100元到B帐户,不管操作成功与否,A帐户和B帐户的存款总额是不变的。
- 隔离性(Isolation):在并发数据库操作时,不同的事务拥有各自的数据空间,他们的操作不会对对方产生干扰。准确的说,并非要求做到完全无干扰。数据库规定了多种数据隔离级别,不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越高,但是并发性越低。
- 持久性(Durabiliy):一旦事务提交后,事务中的所有数据操作都必须被持久化到数据库中。即使在提交事务后,数据库马上崩溃,在数据库重启后时,也必须保证能够铜通过某种机制恢复数据。
3.不考虑隔离性产生读问题
- 脏读:A事务读取B事务尚未提交的数据,并在这个数据的基础上进行操作。如果恰巧B事务回滚,那么A事务读取到的数据是不被承认的。Oracle数据库不存在脏读的情况。
- 不可重复读:A事务读取了B事务已经提交的更改数据。假设A在读取数据的过程中B修改的数据,那么A两次读取的数据就不一致。需要对数据库添加行级锁。
- 幻读:A事务读取到B事务提交的新增数据。需要对数据库添加表级锁。
4.解决读问题
- 设置隔离级别
Spring事务管理
1.编程式事务管理(一般不用)
2.声明式事务管理
- 基于xml
- 基于注解
3.Spring事务管理api——PlatformTransactionManger(事务管理器)
基于jdbcTemplate的实战
1.创建一张表并添加两条数据
CREATE TABLE ssm.account
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
username VARCHAR(100) NOT NULL,
salary INT(11) NOT NULL
);
id | header 2 | salary |
---|---|---|
1 | 令狐冲 | 10000 |
2 | 林平之 | 10000 |
2.创建一个service和dao,完成注入关系
需求:林平之给令狐冲转1000
- 林平之少1000
- 令狐冲多1000
dao层
@Service("salaryDao")
public class SalaryDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//减少
public void lessSalary(int id,int count) {
String sql = "update account set salary = salary - ? where id = ?";
jdbcTemplate.update(sql,count,id);
}
//增加
public void addSalary(int id,int count) {
String sql = "update account set salary = salary + ? where id = ?";
jdbcTemplate.update(sql,count,id);
}
}
service层
@Service("salarySercice")
public class SalaryService {
@Autowired
private SalaryDao salaryDao;
public void TransferAccount() {
salaryDao.lessSalary(2,1000);
salaryDao.addSalary(1,1000);
}
}
3.添加事务
- 基于xml
<!--配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ssm"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2.配置事务增强-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<!--事务操作-->
<tx:attributes>
<!--匹配规则-->
<tx:method name="TransferAccount*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3.配置切面-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointCut" expression="execution(* com.service.SalaryService.*(..)"/>
<!--切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointCut"/>
</aop:config>
- 基于注解
<!--1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2.开启事务注解-->
<tx:annotation-driven></tx:annotation-driven>
//3.在类上注解@Transactional
@Service("salarySercice")
@Transactional
public class SalaryService {...}