一、声明式事务
步骤
1.配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.启用事务注解
<tx:annotation-driven transaction-manager="transactionManager"/>
3.在使用事务的方法上添加注解@Transactional
@Transactional
public void purchase(String username, String isbn) {
//1.获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2.更新书的库存
bookShopDao.updateBookStock(isbn);
//3.更新用户余额
bookShopDao.updateUserAccount(username, price);
}
二、事务的传播行为
- 使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时,如何使用事务
- 默认取值为REQUIRED,及使用调用方法的事务
- REQUIRES_NEW,使用自己的事务,调用的事务方法的事务被挂起
例如一共有130元,要买两本书(定义一个事物),其中一本书100元(定义一个事物),一本书70元(定义一个事物),使用REQUIRED,因为不够买两本,所有可以买0本书;使用REQUIRES_NEW,可以买1本书,剩余30元。
@Service
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bookShopDao;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void purchase(String username, String isbn) {
//1.获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2.更新书的库存
bookShopDao.updateBookStock(isbn);
//3.更新用户余额
bookShopDao.updateUserAccount(username, price);
}
}
@Service("cashier")
public class CashierImpl implements Cashier {
@Autowired
private BookShopService bookShopSrvice;
@Transactional
public void checkout(String username, List<String> isbns) {
for(String isbn:isbns) {
bookShopSrvice.purchase(username, isbn);
}
}
}
三、事务的其他属性
- 使用isolation 指定事务的隔离级别,最常用的取值为READ_COMMITTED
- 默认情况下Spring 的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置,通常情况下取默认值即可
- 只读属性:使用readOnly 指定事务是否为只读,表示这个事物只读取数据但不更新数据,这样可以帮助数据库引擎优化事务。若真的是一个只读数据库值的方法,应设置readOnly=true
- 使用 timeout 指定强制回滚之前事务可以占用的时间
@Transactional(propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
noRollbackFor= {UserAccountException.class},
readOnly=false,
timeout=3)
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
四、使用xml配置事务
步骤
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="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
3.配置事务切入点,以及把事务切入点和事务属性关联起来
<aop:config>
<aop:pointcut expression="execution(* com.atguigu.spring.tx.xml.*.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>