事务回顾
什么是事务?
- 事务指数据库中多个操作合并在一起形成的操作序列(要么同时成功,要么同时失败).
事务的作用
- 当数据库操作序列中个别操作失败时,提供一种方式使数据库状态恢复到正常状态(A),保障数据库即使在异常状态下仍能保持数据一致性(C)(要么操作前状态,要么操作后状态)。
- 当出现并发访问数据库时,在多个访问间进行相互隔离,防止并发访问操作结果互相干扰(I)。
- 事务特征(ACID)
- 原子性(Atomicity)指事务是一个不可分割的整体,其中的操作要么全执行或全不执行
- 一致性(Consistency)事务前后数据的完整性必须保持一致
- 隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离
- 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
事务隔离级
-
脏读:允许读取未提交的信息
- 原因:Read uncommitted
- 解决方案: Read committed(表级读锁)
-
不可重复读::读取过程中单个数据发生了变化
- 解决方案: Repeatable read (行级写锁)
- 解决方案: Repeatable read (行级写锁)
-
幻读:读取过程中数据条目发生了变化
- 解决方案: Serializable(表级写锁)
- 解决方案: Serializable(表级写锁)
事务管理
Spring事务核心对象
- J2EE开发使用分层设计的思想进行,对于简单的业务层转调数据层的单一操作,事务开启在业务层或者数据层并无太大差别,当业务中包含多个数据层的调用时,需要在业务层开启事务,对数据层中多个操作进行组合并归属于同一个事务进行处理
- Spring为业务层提供了整套的事务解决方案
- PlatformTransactionManager
- TransactionDefinition
- TransactionStatus
PlatformTransactionManager
- 此接口定义了事务的基本操作
- 获取事务 :
TransactionStatus getTransaction(TransactionDefinition definition)
- 提交事务 :
void commit(TransactionStatus status)
- 回滚事务 :
void rollback(TransactionStatus status)
TransactionDefinition
TransactionStatus
事务控制方式
- 编程式
- 声明式(XML)
- 声明式(注解)
编程式事务
public void transfer(String outName,String inName,Double money){
//创建事务管理器
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
//为事务管理器设置与数据层相同的数据源
dstm.setDataSource(dataSource);
//创建事务定义对象
TransactionDefinition td = new DefaultTransactionDefinition();
//创建事务状态对象,用于控制事务执行
TransactionStatus ts = dstm.getTransaction(td);
accountDao.inMoney(outName,money);
int i = 1/0; //模拟业务层事务过程中出现错误
accountDao.outMoney(inName,money);
//提交事务
dstm.commit(ts);
}
使用AOP控制事务
- 将业务层的事务处理功能抽取出来制作成AOP通知,利用环绕通知运行期动态织入
public Object tx(ProceedingJoinPoint pjp) throws Throwable {
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
dstm.setDataSource(dataSource);
TransactionDefinition td = new DefaultTransactionDefinition();
TransactionStatus ts = dstm.getTransaction(td);
Object ret = pjp.proceed(pjp.getArgs());
dstm.commit(ts);
return ret;
}
- 配置AOP通知类,并注入dataSource
<bean id="txAdvice" class="com.itheima.aop.TxAdvice">
<property name="dataSource" ref="dataSource"/>
</bean>
- 使用环绕通知将通知类织入到原始业务对象执行过程中
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
<aop:aspect ref="txAdvice">
<aop:around method="tx" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
声明式事务(XML)
AOP配置事务是否具有特例性?
public Object tx(ProceedingJoinPoint pjp) throws Throwable {
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
dstm.setDataSource(dataSource);
TransactionDefinition td = new DefaultTransactionDefinition();
TransactionStatus ts = dstm.getTransaction(td);
Object ret = pjp.proceed(pjp.getArgs());
dstm.commit(ts);
return ret;
}
<bean id="txAdvice" class="com.itheima.aop.TxAdvice">
<property name="dataSource" ref="dataSource"/>
</bean>
- 使用tx命名空间配置事务专属通知类
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" read-only="false" />
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>
- 使用aop:advisor在AOP配置中引用事务专属通知类
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config
aop:advice与aop:advisor区别
- aop:advice配置的通知类可以是普通java对象,不实现接口,也不使用继承关系
- aop:advisor配置的通知类必须实现通知接口
- MethodBeforeAdvice
- AfterReturningAdvice
- ThrowsAdvice
tx配置
- 名称:tx:advice
- 类型:标签
- 归属:beans标签
- 作用:专用于声明事务通知
- 格式:
<beans>
<tx:advice id="txAdvice" transaction-manager="txManager">
</tx:advice>
</beans>
- 基本属性:
- id :用于配置aop时指定通知器的id
- transaction-manager :指定事务管理器bean
tx配置二
- 名称:tx:attributes
- 类型:标签
- 归属:tx:advice标签
- 作用:定义通知属性
- 格式:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
</tx:attributes>
</tx:advice>
tx配置三
- 名称:tx:method
- 类型:标签
- 归属:tx:attribute标签
- 作用:设置具体的事务属性
- 格式:
<tx:attributes>
<tx:method name="*" read-only="false" />
<tx:method name="get*" read-only="true" />
</tx:attributes>
- 说明:
- 通常事务属性会配置多个,包含1个读写的全事务属性,1个只读的查询类事务属性
tx:method属性
事务传播行为
- 事务管理员
- 事务协调员
- 事务传播行为描述的是事务协调员对事务管理员所携带事务的处理态度
事务传播应用
声明式事务(注解)
- 名称:@Transactional
- 类型:方法注解,类注解,接口注解
- 位置:方法定义上方,类定义上方,接口定义上方
- 作用:设置当前类/接口中所有方法或具体方法开启事务,并指定相关事务属性
- 范例:
@Transactional(
readOnly = false,
timeout = -1,
isolation = Isolation.DEFAULT,
rollbackFor = {ArithmeticException.class, IOException.class},
noRollbackFor = {},
propagation = Propagation.REQUIRES_NEW
)
声明式事务(注解)二
- 名称:tx:annotation-driven
- 类型:标签
- 归属:beans标签
- 作用:开启事务注解驱动,并指定对应的事务管理器
- 范例:
<tx:annotation-driven transaction-manager="txManager"/>
声明式事务(注解)三
- 名称:tx:annotation-driven
- 类型:标签
- 归属:beans标签
- 作用:开启事务注解驱动,并指定对应的事务管理器
- 范例:
<tx:annotation-driven transaction-manager="txManager"/>
声明式事务(纯注解驱动)
- 名称:@EnableTransactionManagement
- 类型:类注解
- 位置:Spring注解配置类上方
- 作用:开启注解驱动,等同XML格式中的注解驱动
- 范例:
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
事务底层原理解析
策略模式应用
- 策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。
装饰模式应用
- JdbcTemplate
public void save(Account account) {
String sql = "insert into account(name,money)values(?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
}
- NamedParameterJdbcTemplate
public void save(Account account) {
String sql = "insert into account(name,money)values(:name,:money)";
Map pm = new HashMap();
pm.put("name",account.getName());
pm.put("money",account.getMoney());
jdbcTemplate.update(sql,pm);
}