事务的四个关键属性:
原子性(atomicity):事务是一个原子操作,由一系列动作组成,事务原子性确保动作要么全部完成要么完全不起作用。
一致性(consistency):一旦所有事务动作完成,事务就被提交,数据和资源就处于满足业务规则的一致性状态中。
隔离性(isolation):可能有许多事务会同时处理相同的数据因此每个事务都应该与其他事务隔离起来,防止数据损坏
持久性(durability):一旦事务完成,无论发生什么系统错误,他的结果都不应该收到影响,事务的结果被写到持久化存储器中。
声明式事务管理:
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理,事务管理作为一种横切关注点,可以通过AOP方法模块化,Spring通过SpringAOP来实现声明式事务管理。
Spring从不同的事务管理API中抽象了一整套的事务机制,开发人员不必了解底层的事务API,就可以利用这些事务机制。
Spring的核心事务管理抽象类是PlatformTransctionMananger,其下有针对不同技术的实现类用于特定技术的支持。管理封装了一组独立于技术的方法,无论使用Spring的哪种事务管理策略,事务管理器都是必须的。
使用:
在配置文件中声明事务管理器:
//spring注解扫描范围
<context:component-scan base-package="com.cmzy.spring.transction" resource-pattern="**/*.class"></context:component-scan>
//引用外部properties文件。存放数据库连接信息
<context:property-placeholder location="classpath:db.properties"/>
//配置数据库连接池
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
//配置JdbcTemplate数据操作模板,需要引用数据源
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
//配置事务管理器,需要引用数据源
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
//启用spring 事务注解
<tx:annotation-driven transaction-manager="transactionManager"/>
导入tx事务命名空间,并启用Spring事务注解
<tx:annotation-driven transaction-manager="transactionManager"/>
在需要使用事务的事务的方法上添加@Transactional注解
@Service
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bookShopDaoImpl;
@Transactional
public void buyBook(int bookId, String username) {
// TODO Auto-generated method stub
Book book = bookShopDaoImpl.findBookPriceById(1);
bookShopDaoImpl.updateBookStock(1);
bookShopDaoImpl.updateAccount(username, book.getPrice());
}
}
事物的传播性:
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如:方法可能继续在现有的事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以有传播属性指定,spring定义了七种事务传播行为。
REQURED:如果有事务在运行,当前的方法就在这个事务内运行,否则就启用一个新的事务,并在自己的事务内运行。
REQUIRES_NEW:当前的方法必须启用新事务,并在它自己的事务内运行,如果有事务正在运行,应该将其挂起。
SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以运行在事务中。
NOT_SUPPORTE:当前的方法不应该在事务中,如果有运行的事务,将它挂起
MANDATORY:当前的方法必须运行在食物内部,如果没有正在运行的事务,就抛出异常。
NEVER:当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启用一个新的事务,并在它自己的事务内运行
事务默认的传播行为是REQURED,在事务注解中配置,使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用的时候,如何使用事务。这里要注意,是当前的事务方法被另一个事务方法调用时,定义传播行为的时候是在被调用的方法上定义。
@Transactional(propagation = Propagation.REQUIRED)
public void buyBook(int bookId, String username) {
// TODO Auto-generated method stub
Book book = bookShopDaoImpl.findBookPriceById(1);
bookShopDaoImpl.updateBookStock(1);
bookShopDaoImpl.updateAccount(username, book.getPrice());
}
事务的隔离级别,使用isolation指定事务的隔离级别,最常用的取值为READ_COMMITTED
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
默认情况下,Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置。通常情况下取默认值即可。noRollbackFor对哪些异常不回滚,rollbackFor对哪些异常回滚
由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响,如果一个是无只读取数据而不做修改,数据库引擎可以对这个事务进行优化。
超时事务属性:事务在执行回滚之前可以保持多久,这样可以防止长期运行的事务占用资源。
只读事务属性:表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务。默认false ,
基于XML配置声明式事务
1、配置事务管理器,跟注解配置相同
2、配置事务属性,tx:advice标签配置
3、配置事务切入点,把事务切入点和事务属性关联起来,使用aop:config标签,其实事务就是AOP的实现,就是在XML中配置AOP,只不过标签使用有所不同。