Spring事务管理基础
什么是数据库事务?
数据库事务有严格定义,必须满足4个特性:原子性、一致性、隔离性、和持久性,简称ACID。简单说明如下:
原子性:表示组成事务的多个数据库操作是一个不可分割的单元,只有所有的操作执行成功,整个事务才提交,有一个失败就回滚到数据库之前的状态。
一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的。
隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它的操作不会对对方产生干扰。
持久性:一旦事务提交成功后,事务中所有的数据库操作必须被持久化到数据库中。
数据并发问题
数据库的数据可能被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。可以归类为以下问题:
脏读:A事务读取B事务尚未提交的更改数据,并在这个数据基础上进行操作,如果B回滚了,A事务读取到的数据是不被承认的。
不可重复读:指A事务读取了B事务已经提交更改的数据。
幻象读:A事务读取B事务提交的新增数据,将出现幻象读的问题。
第一类丢失更新:A事务撤销时,把已经提交的B事务更新数据覆盖了。
第二类丢失更新:A事务覆盖B事务已经提交的数据。
事务的隔离级别
通过一张表来看一下数据库的事务隔离级别:
基于XML配置
Spring在基于Schema的配置中,提供了tx命名空间,配合aop命名空间提供切面,业务方法的事务配置得到了大大的简化,这也是工程开发中最常用的一种方式,下面我们通过一个demo来演示一下:
假设我们的业务类为UserServiceImpl代码如下:
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void addUser(User user) {
userDao.addUser(user);
}
public void updateUser(User user) {
userDao.updateUser(user);
}
}
我们用Spring如何为这两个方法配置事务呢?利用tx事务增强和aop切面配合来完成,这是一组非常方便强大的武器。配置如下:
<?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:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 配置dao和service -->
<bean id="userDao" class="spring.dao.demo2.UserDaoImpl"></bean>
<bean id="userService" class="spring.dao.demo2.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- aop配置切面逻辑 -->
<aop:config>
<aop:pointcut expression="execution(* spring.dao.demo2.UserServiceImpl.*(..))" id="serviceMethod"/>
<aop:advisor advice-ref="txAdvice"/>
</aop:config>
<!-- 事务增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="addUser" read-only="false"/>
<tx:method name="updateUser" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
</beans>
基于注解进行配置
除Xml配置外,Spring还提供了基于注解的事务配置方式,废话不多说,我们还是通过一个demo看一下,这个怎么玩?
如果我们希望对UserServiceImpl业务类的方法进行事务管理,基于注解非常方便,代码如下:
@Transactional
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void addUser(User user) {
userDao.addUser(user);
}
public void updateUser(User user) {
userDao.updateUser(user);
}
}
对,你没有看错,只是在类上加了一行
@Transactional就可以将业务类的方法进行事务管理,不过想让Spring认识它,还需加一行配置:
<?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:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 配置dao和service -->
<bean id="userDao" class="spring.dao.demo2.UserDaoImpl"></bean>
<bean id="userService" class="spring.dao.demo2.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 对标注@Transactional注解的业务bean进行加工,织入事务管理切面 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
这样Spring就可以知道标注了@Transactional的类是需要被事务管理的。
如果@Transactional被标注在类上,类中定义的public方法进行事务管理。
如果在业务实现类方法上标注@Transactional,则会覆盖类的标注。
这个注解有几个属性需要了解:
propagation:事务传播行为
isolation:事务隔离级别
readOnly:事务读写性
timeout:超时时间,int型,以秒为单位
rollbackFor:一组异常类,遇到时进行回滚,类型为:Class<? extends Throwable>[]
rollbackForClassName:一组异常名,遇到进行回滚,类型为String[]
noRollbackFor:一组异常类,遇到不回滚,类型为:Class<? extends Throwable>[]
noRollbackForClassName:一组异常名,遇到不回滚,类型为String[]
至此,Spring的基本知识和基本配置方法讲完了。