数据库事务的概述
事务是反映现实世界中所需要完整提交的一项工作,在数据库系统中是用户定义的一个数据库操作序列,是数据库应用中一个不可分割的工作单元。一个事务中的这些序列的操作要么全部完整地执行,要么全部不执行。
在SQL中,有关事务定义的语句有三个:BEGIN TRANSACTION、COMMIT和 ROOLBACK。通常情况下,事务以BEGIN TRANSACTION开始,以COMMIT或ROOLBACK结束。其中COMMIT表示事务正常结束,要向数据库系统提交事务的所有操作,即将事务中所有对数据库的更新操作写回到磁盘;而ROOLBACK是回滚的意思,即在事务运行的过程中发生故障,不能继续执行,系统将把事务对数据库的所有已经完成的操作全部撤销,以使数据库回滚到该事务开始之前的状态。
事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称ACID。
- 原子性:事务作为数据库独立的逻辑工作单位,事务中所包含的操作要么全做,要么全部做。
- 一致性:事务的执行结果必须保证数据库能够从一个一致性状态转变到另一个一致性状态。
- 隔离性:一个事务在执行期间所使用的数据,不能够被其他事务再使用,以免其执行时受其他事务的干扰。
- 持久性:事务一旦提交,它对数据库数据的改变就是永久的,数据库的其他操作或者一些故障都不能够影响到它的执行结果。
Spring对事务管理的支持
Spring为事务管理提供了一致的编程模板,在高层次建立了统一的事务抽象。也就是说,不管选择SpringJDBC、Hibernate、JPA还是iBatis,Spring都让我们可以用统一的编程模型进行事务管理。
像Spring DAO为不同的持久化实现提供了模板类一样,Spring事务管理继承了这一风格,也提供了事务模板类TransactionTemplate。通过TransactionTemplate并配合使用事务回调TransactionCallback指定具体的持久化操作就可以通过编程方式实现事务管理,而无须关注资源获取、复用、释放、事务同步和异常处理的操作。
Spring的事务管理器实现类
- org.springframework.orm.jpa.JpaTransactionManager:使用JPA进行持久化,使用该事务管理器。
- org.springframework.orm.hibernate3.HibernateTransactionManager:使用Hibernate3.0版本进行持久化,使用该事务管理器。
- org.springframework.jdbc.datasource.DataSourceTransactionManager:使用Spring JDBC或iBatis等基于DataSource数据源的持久化技术时,使用该事务管理器。
- org.springframework.orm.jdo.JdoTransactionManager:使用JDO进行持久化,使用该事务管理器。
- org.springframework.transaction.jta.JtaTransactionManager:具有多个数据源的全局事务使用该事务管理器(不管采用何种持久化技术)。
这些事务管理器都是对特定事务实现框架的代理,这样,我们就可以通过Spring所提交的高级抽象对不同种类的事务实现使用相同的方式进行管理,而不关心具体的实现。
基于数据源的数据管理器:
<!-- 定义一个使用DBCP实现的数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/xxdb?characterEncoding=utf8&useSSL=false"
p:username="root"
p:password="123"/>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
在幕后,DataSourceTransactionManager使用了DataSource的Connection的commit()、rollback()等方法管理事务。
Hibernate
.....
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource"
p:mappingResources="classpath:xxxx.xml">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.shiw_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory">
</bean>
大部分的ORM框架都拥有自己事务管理的API,它们对DataSource和Connection进行了封装。Hibernate使用org.hibernate.Session封装Connection,所以需要一个能够创建Session的SessionFactory。
编程式的事务管理
Spring为编程式事务管理提供了模板类org.springframework.transaction.support.TransactionTemplate,以满足一些特殊场合的需要。
TransactionTemplate和那些持久化模板类一样,都是线程安全的,因此,我们可以在多个业务类中共享TransactionTemplate实例进行事务管理。TransactionTemplate拥有多个设置事务属性的方法,如setReadOnly(boolean readOnly),setIsolationLevel(int isolationLevel)等。
TransactionTemplate有两个主要的方法:
- void setTransactionManager(PlatformTransactionManager transactionManager):设置事务管理器。
- Object execute(TransactionCallback action):在TransactionCallback回调接口中定义需要以事务方式组织的数据访问逻辑。
使用XML配置声明式事务
大多数Spring用户选择声明式事务管理的功能,这种方式对代码的侵入性最小,可以让事务管理代码完全从业务代码中移除,非常符合非侵入式轻量级容器的理念。
Spring的声明式事务管理是通过Spring AOP实现的,通过事务的声明式信息,Spirng负责将事务管理增强逻辑动态织入到业务方法相应连接点中。这些逻辑包括获取线程绑定资源、开始事务、提交/回滚事务、进行异常转换和处理等工作。
package service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import dao.LoginLogDao;
import dao.UserDao;
import domain.LoginLog;
import domain.User;
@Service //将UserServer标注为一个服务层的Bean
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private LoginLogDao loginLogDao;
public boolean hasMatchUser(String userName,String password){
int matchCount = userDao.getMatchCount(userName, password);
return matchCount>0;
}
public User findUserByUserName(String userName){
return userDao.findUserByUesrName(userName);
}
public void loginSuccess(User user){
user.setCredits(5+user.getCredits());
LoginLog loginLog = new LoginLog();
loginLog.setUserId(user.getUserId());
loginLog.setIp(user.getLastIp());
loginLog.setLoginDate(user.getLastVisit());
userDao.updateLoginInfo(user);
loginLogDao.insertLoginLog(loginLog);
}
}
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 通过AOP配置提供事务增强,让service包下所有bean的所有方法拥有事务 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod" expression="execution(* service..*(..))"/>
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
在基于数据源的DataSourceTransactionManager事务管理器,该事务管理器负责声明式事物的管理,该管理器需要引用dataSource Bean。通过aop及tx命名空间的语法,以aop的方式为service包下所有类的所有方法都添加了事物增强,即它们都工作于事务环境中。
Spirng声明式事务管理是Spring中的亮点,也是被使用最多的功能之一。Spring使声明式事务平民化,现在我们可以在Spring轻量级容器中享受这项曾经只能在臃肿、厚重的EJB应用服务器才拥有的功能。
Spring事务管理是Spring AOP技术的应用案例,事务管理作为一个切面织入到目标业务方法的周围,业务方法完全从事务代码中解脱出来,代码的复杂度大大降低。被织入的事务代码基于Spring事务同步管理器进行工作,事务同步管理器维护着业务类对象线程相关的资源。