1.什么是事务?
逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
2.事务的特性?
- 原子性:事务不可分割
- 一致性:事务执行前后数据完整性保持一致
- 隔离性:一个事务的执行不应该受到其他事务的干扰
- 持久性:一旦事务结束,数据就持久化到数据库
3.如果不考虑隔离性会引发安全性问题?
- 读问题:
- 脏读 :一个事务读到另一个事务未提交的数据
- 不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
- 虚读、幻读 :一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致
- 写问题:
- 丢失更新
4.如何解决读问题?
- 设置事务的隔离级别
- Read uncommitted :未提交读,任何读问题解决不了。
- Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
- Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
- Serializable :解决所有读问题。
5.Spring的事务管理的API
- PlatformTransactionManager
PlatformTransactionManage:平台事务管理器 是一个接口,下面有两个实现类:
- DataSourceTransactionManager
底层使用JDBC管理事务- HibernateTransactionManager
底层使用Hibernate管理事务
- TransactionDefinition
事务定义信息:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
- TransactionStatus
事务状态:用于记录在事务管理过程中,事务的状态的对象
- 事务管理的API的关系
- 在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
- Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,
6.Spring的事务的七种传播行为
- 什么是传播行为?
一个业务方法当中,调用另一个业务的方法
- 保证多个操作在同一个事务中:
- PROPAGATION_REQUIRED
默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
- PROPAGATION_SUPPORTS
支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
- PROPAGATION_MANDATORY
如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。
- 保证多个操作不在同一个事务中
- PROPAGATION_REQUIRES_NEW
如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
- PROPAGATION_NOT_SUPPORTED
如果A中有事务,将A的事务挂起。不使用事务管理。
- PROPAGATION_NEVER
如果A中有事务,报异常。
- 嵌套式事务
PROPAGATION_NESTED
嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点;
执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点
7.Spring事务编程(注解形式)
- 定义Dao接口和Dao实现类:
//接口
public interface AccountDao {
/*加钱*/
public void addMoney(String name, Double money);
/*减钱*/
public void minusMoney(String name, Double money);
}
//实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void addMoney(String name, Double money) {
this.getJdbcTemplate().update("update account set money= money+? where name=?",money,name);
}
@Override
public void minusMoney(String name, Double money) {
this.getJdbcTemplate().update("update account set money=money-? where name =?",money,name);
}
}
- 定义业务接口和业务实现类
//接口
public interface AccountService {
public void transferMoney(String from, String to, Double money);
}
//实现类
@Transactional /*事务注解*/
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transferMoney(String from, String to, Double money) {
accountDao.minusMoney(from, money);
//int i=1/0;
accountDao.addMoney(to, money);
}
}
- jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123
applicationContext.xml
<?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 ">
<!--加载属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--druid-->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
<!--key值 不能和name 一样-->
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--AccoutDao-->
<bean id="accoutDao" class="com.itlike.demo4.AccountDaoImpl">
<property name="dataSource" ref="druid"></property>
</bean>
<!--AccoutService-->
<bean id="accoutService" class="com.itlike.demo4.AccountServiceImpl">
<property name="accountDao" ref="accoutDao"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druid"/>
</bean>
<!--开启注解 增强-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
- 定义测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {
@Resource(name="accoutService")
private AccountService accountService;
@Test
public void Test(){
accountService.transferMoney("zs","ls",100d);
}
}
运行测试类,当程序运行异常时,就会执行事务回滚!