06-Spring03-事务管理
今日知识
1. Spring事务管理
2. 转账案例
Spring事务管理
1. 事务特性(ACID)
1. 原子性:整体 【原子性是指事务包含的所有操作要么全部成功,要么全部失败】
2. 一致性:数据 【一个事务执行之前和执行之后都必须处于一致性状态】
3. 隔离性:并发 【对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。】
4. 持久性:结果 【持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的】
* 隔离问题
1. 脏读:一个事务读到另一个事务未提交的内容
2. 不可重复读:一个事务读到另一个事务已提交的内容(update)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。
3. 虚读:一个事务读到另一个事务已提交的内容(delete,insert),这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。行数发生变化
4. Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
* 隔离级别-解决问题
1. read uncommitted,读未提交,存在三个问题
2. read committed,读已提交,解决:脏读,存在两个问题
3. repeatable read,可重复读,解决:脏读,和不可重复读,存在一个问题
4. serializable,串行化。单事务。没有问题。一般不用,涉及IO操作,占用内存。
2. Spring提供的事务jar包
* spring-tx jar包
* jar 包包含三个顶级接口
* PlatformTransactionManager:
平台事务管理器,spring要管理事务,必须使用事务管理器,进行事务配置时,必须配置事务管理器
* TransactionDefinition:
事务详情(事务定义、事务属性),spring用于确定事务具体详情,
* TransactionStatus:
事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
spring底层根据状态进行相应操作。
3. 手动代理事务
1. AccountServiceImpl写法注入TransactionTemplate
* public class AccountServiceImpl implements AccountService {
//spring底层使用 TransactionTemplate 事务模板进行操作。
//注入已经 配置事务模板
@Autowired
TransactionTemplate transactionTemplate;
//Spring注入AccountDao
@Autowired
AccountDao accountDao;
public void tansfer(final String inner, final String outer, final Integer money) {
//通过事务模板执行业务
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//第一个进账
accountDao.inner(inner,money);
//第二个出账
// int i=10/0;
accountDao.out(outer,money);
}
});
}
}
2. xml中的配置
* !--配置事务模板-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"></property>
</bean>
<!--配置一个事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager
">
<property name="dataSource" ref="dataSource"></property>
</bean>
4. 工厂bean生成代理事务:半自动
1. transactionAttributes:事务详情
prop.key :确定哪些方法使用当前事务配置
prop.text:用于配置事务详情
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
传播行为 隔离级别 是否只读 异常回滚 异常提交
2. AccountServiceImpl2直接普通的写法,不用引入TransactionTemplate事务模板
3. xml中的配置
* <!--配置accountService2,bean-->
<bean id="accountService" class="com.rqy.service.impl.AccountServiceImpl2"/>
<!--配置管理事务的代理工厂,代替上面的方法,到达半自动代理-->
<bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--配置接口-->
<property name="proxyInterfaces" value="com.rqy.service.AccountService"/>
<!--目标对象-->
<property name="target" ref="accountService"/>
<!--事务管理器-->
<property name="transactionManager" ref="txManager"/>
<!--事务详情-->
<!--
transactionAttributes:事务详情
prop.key :确定哪些方法使用当前事务配置
prop.text:用于配置事务详情
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
传播行为 隔离级别 是否只读 异常回滚 异常提交
-->
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
</props>
</property>
</bean>
<!--配置一个事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager
">
<property name="dataSource" ref="dataSource"></property>
</bean>
基本AOP的事务配置(全自动)
1. xml配置(方法一)
1. <!--配置一个事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager
">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务属性,同时引入事务管理器-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--transfer。。。方法可读,-->
<tx:method name="transfer*" propagation="REQUIRED" isolation="REPEATABLE_READ"/>
<!-- 其它方法加可读写事务 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP:告诉spring框架哪些方法需要管理事务 -->
<aop:config>
<!-- 指定切入点 -->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.rqy.service.*.*(..))"/>
</aop:config>
2. 注解事务(方法二)
1. 类里面加注解事务,就不用指明切入点了,默认在该类中加入该事务管理
2. xml需要声明自动开启事务注解驱动:<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
3. 注解直接加在方法上面
* @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
* @Transactional:直接写这个就置默认隔离级别和传播行为
纯javaConfig(全注解配置)
1. 类上面声明
//声明我是配置文件
@Configuration
//声明扫描范围
@ComponentScan(basePackages = "com.rqy")
//声明自动开启事务注解
@EnableTransactionManagement
//开启AspectJ注解
@EnableAspectJAutoProxy
2. 注解类
* //声明我是配置文件
@Configuration
//声明扫描范围
@ComponentScan(basePackages = "com.rqy")
//声明自动开启事务注解
@EnableTransactionManagement
//开启AspectJ注解
@EnableAspectJAutoProxy
public class SpringConfig {
//配置数据源
@Bean
public ComboPooledDataSource comboPooledDataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC");
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("123456");
return comboPooledDataSource;
}
//配置JdbcTemplate
@Bean
public JdbcTemplate jdbcTemplate(ComboPooledDataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//配置事务管理器
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(ComboPooledDataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
3. 实例类
* @Component
public class AccountDaoImpl2 implements AccountDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void out(String outer, Integer money) {
String sql = "update account set money=money-? where username=?";
jdbcTemplate.update(sql, money, outer);
}
public void inner(String inner, Integer money) {
String sql = "update account set money=money+? where username=?";
jdbcTemplate.update(sql, money, inner);
}
}
* @Transactional
@Component("accountService5")
public class AccountServiceImpl5 implements AccountService {
@Autowired
AccountDao accountDao;
public void transfer( String inner, String outer, Integer money) {
//第一个进账
accountDao.inner(inner,money);
//第二个出账
int i=10/0;
accountDao.out(outer,money);
}
}
4. 测试类
* @RunWith(SpringJUnit4ClassRunner.class)
//不加载配置文件的写法,如果有多个配置类,用,隔开。
@ContextConfiguration(classes = {SpringConfig.class})
public class ConfigTest {
//去找代理对象
@Autowired
@Qualifier("accountService5")
AccountService accountService;
@Test
public void test(){
accountService.transfer("rose","jack",2000);
}
}
传播行为
1. PROPAGATION_REQUIRED
required , 必须 【默认值】
* 支持当前事务,A如果有事务,B将使用该事务。
如果A没有事务,B将创建一个新的事务。
2. PROPAGATION_SUPPORTS:supports ·
* 支持当前事务,A如果有事务,B将使用该事务。
如果A没有事务,B将以非事务执行。
3. PROPAGATION_REQUIRES_NEW:如果A有事务,将A的事务挂起,B创 建一个新的事务如果A没有事务,B创建一个新的事务