- 浏览: 63698 次
文章分类
最新评论
spring 编程式事务、声明式事务
spring 编程式事务、声明式事务
事务管理是应用系统中必不可少的一部分,它保证了用户的每一次操作都是可靠的,即便是出现了异常情况,也不至于破坏后台数据的完整性。 Spring 提供了丰富的事务管理功能,Spring 的事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理指通过编码的方式实现事务管理,声明式事务基于 AOP,将业务逻辑与事务处理解耦。声明式事务对代码侵入较少,在实际使用中使用比较广泛。
一、包依赖
项目中使用的 Spring 和 MyBatis 包依赖如下:
...
<properties>
<spring-version>4.2.2.RELEASE</spring-version>
</properties>
<dependencies>
<!-- **************** -->
<!-- spring -->
<!-- **************** -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- **************** -->
<!-- mybatis -->
<!-- **************** -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
...
</dependencies>
...
二、编程式事务
Spring 编程式事务管理通过编码的方式实现事务管理,需要在代码中显示的 getTransaction(), commit(), roolback() 等事务管理方法,通过这些 Spring 提供的 API 可以灵活控制事务的执行,在底层,Spring将这些事务的操作委托给持久化框架执行。
Spring 配置文件 config.xml 如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 引入属性文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${driver}</value>
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="username">
<value>${username}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
</bean>
<!-- 自动扫描了所有的mapper配置文件对应的mapper接口文件 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiaofan.test" />
</bean>
<!-- 配置Mybatis的文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:user_mapper.xml"/>
<property name="configLocation" value="classpath:mybatis_config.xml" />
</bean>
<!-- 配置JDBC事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="userService" class="com.xiaofan.test.UserService">
</bean>
</beans>
根据 PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三个接口,可以通过编程的方式来进行事务管理, TransactionDefinition 实例用于定义一个事务,PlatformTransactionManager 实例用语执行事务管理操作,TransactionStatus 实例用于跟踪事务的状态。UserService 服务中配置如下:
public class UserService {
@Resource
UserDAO userDAO;
@Resource
DataSource dataSource;
@Resource
PlatformTransactionManager transactionManager;
public void addUser(User user) throws Exception {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// [1](https://hacpai.com/tag/) 插入纪录
userDAO.insert(user);
// [2] 范例抛出异常
Integer i = null;
if (i.equals(0)) {
}
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
return;
}
}
Spring 测试代码如下
@ContextConfiguration(locations = {"classpath:config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class Test extends AbstractJUnit4SpringContextTests{
@Resource
UserService userService;
@org.junit.Test
public void testAdd() {
try {
userService.addUser(new User(null, "LiLei", 25));
} catch (Exception e) {
}
}
}
如果[2]处抛出异常,则事务执行回滚,如果[2]没有抛出异常,则提交执行纪录插入操作。
另一种编程式事务管理
以上这种事务管理方式容易理解,但事务管理代码散落在业务代码中,破坏了原有代码的条理性,且每个事务方法中都包含了启动事务、提交 / 回滚事务的功能,基于此,Spring 提供了简化的模版回调模式(TransactionTemplate)。 在 config.xml 配置文件中加入 TransactionTemplate bean 配置:
...
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
# 新增
<property name="isolationLevelName" value="ISOLATION_DEFAULT" />
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" />
</bean>
...
TransactionTemplate 的 execute()方法有一个 TransactionCallback 类型的参数,该接口中定义了一个 doInTransaction() 方法,可通过匿名内部累的方式实现 TransactionCallBack 接口,将业务代码写在 doInTransaction()方法中,业务代码中不需要显示调用任何事物管理 API,除了异常回滚外,也可以在业务代码的任意位置通过 transactionStatus.setRollbackOnly(); 执行回滚操作。UserService 服务代码变更为:
注:如果抛异常的话,也会自动rollback
public class UserService {
@Resource
UserDAO userDAO;
@Resource
TransactionTemplate transactionTemplate;
public void addUser(final User user) {
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus transactionStatus) {
userDAO.insert(user);
// transactionStatus.setRollbackOnly();
Integer i = null;
if (i.equals(0)) {
// 自动rollback
throw new Exception("xxx");
}
return null;
}
});
}
}
三、声明式事务
Spring 的声明式事务管理建立在 AOP 基础上,其本质是在目标方法执行前进行拦截,在方法开始前创建一个事务,在执行完方法后根据执行情况提交或回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不用侵入业务代码,只需要在配置文件中做相关的事物声明就可将业务规则应用到业务逻辑中。和编程式事务相比,声明式事务唯一的不足是智能作用到方法级别,无法做到像编程式事务那样到代码块级别
声明式事务有四种方式,a. 基于 TransactionInterceptor 的声明式事务;b. 基于 TransactionProxyFactoryBean 的声明式事务;c. 基于 \ 命名空间的声明式事务;d. 基于标注(@Transactional)的声明式事务。
注:一般d用得比较多,使用和学习成本都比较低。
a. 基于 TransactionInterceptor 的声明式事务
TransactionInterceptor 主要有两个属性,一个是 transactionManager,用于指定一个事务管理器;另一个是 transactionAttributes,通过键值对的方式指定相应方法的事物属性,其中键值可以使用通配符。在 config.xml 配置文件中加入 TransactionInterceptor 配置:
...
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="userService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="com.xiaofan.test.UserService" />
</property>
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
...
其中事务的传播行为边界为:
PROPAGATION_REQUIRED | 支持当前事务,如果当前没有事务,则新建一个事务 |
PROPAGATION_SUPPORT | 支持当前事务,如果当前没有事务,则以非事务执行 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,则抛出异常 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,则把当前事务挂起 |
PROPAGATION_NOT_SUPPORT | 以非事务方式操作,如果当前有事务,则把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式操作,如果当前有事务,则抛出异常 |
UserService 服务代码变更为:
public class UserService {
@Resource
UserDAO userDAO;
public void addUser3(User user) {
userDAO.insert(user);
Integer i = 1;
if (i.equals(0)) {
}
}
}
b. 基于 TransactionProxyFactoryBean 的声明式事务
以上基于 TransactionInterceptor 的方式每个服务 bean 都需要配置一个 ProxyFactoryBean,这会导致配置文件冗长,为了缓解这个问题,Spring 提供了基于 TransactionProxyFactoryBean 的声明式事务配置方式。在 config.xml 配置文件中加入 TransactionProxyFactoryBean 配置:
...
<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target">
<bean class="com.xiaofan.test.UserService" />
</property>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
...
UserService 服务代码如上,不用变更。
c. 基于 \ 命名空间的声明式事务
Spring 2.x 引入了 \ 命名空间,加上 \ 命名空间的切点表达式支持,声明式事务变的更加强大,借助于切点表达式,可以不需要为每个业务类创建一个代理。为了使用动态代理,首先需要添加 pom 依赖:
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
...
config.xml 文件添加如下配置:
...
<bean id="userService" class="com.xiaofan.test.UserService">
</bean>
<tx:advice id="userAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userPointcut" expression="execution (* com.xiaofan.test.*.*(..))"/>
<aop:advisor advice-ref="userAdvice" pointcut-ref="userPointcut"/>
</aop:config>
...
UserService 服务代码如上,不用变更。
d. 基于标注(@Transactional)的声明式事务
除了基于命名空间的事务配置方式外,Spring2.x 还引入了基于注解的方式,主要涉及 @Transactional 注解,它可以作用于接口、接口方法、类和类的方法上,当做用于类上时,该类的所有 public 方法都有该类型的事务属性,可被方法级事务覆盖。在 config.xml 配置文件中加入注解识别配置:
...
<tx:annotation-driven transaction-manager="transactionManager"/>
...
@Transactional 注解应该被应用到 public 方法上,这是由 AOP 的本质决定的,如果应用在 protected、private 的方法上,事务将被忽略。UserService 服务代码如下:
public class UserService {
@Resource
UserDAO userDAO;
@Transactional(propagation = Propagation.REQUIRED)
public void addUser4(User user) {
userDAO.insert(user);
Integer i = 1;
if (i.equals(0)) {
}
}
}
@Transactional 注解的完整属性信息如下表 [1]:
name | 指定选择多个事务管理器中的某个事务管理器 |
propagation | 事务传播行为,默认为 REQUIRED |
isolation | 事务个力度,默认为 DEFAULT |
timeout | 事务超时时间,默认为-1 |
read-only | 指定事务为只读,默认为 false |
rollback-for | 指定触发事务回滚的异常类型,多个异常通过逗号分隔 |
no-rollback-for | 抛出指定的异常类型,不回滚 |
基于 \ 命名空间和基于注解的事务声明各有优缺点:基于 \ 的方式一个配置可以匹配多个方法,但配置较注解方式复杂;基于注解的方式需要在每个需要使用事务的方法或类上标注,但基于标注的方法学习成本更低。
转载于:https://my.oschina.net/haitaoxiedekongjian/blog/1584969
相关推荐
Spring 编程式事务与声明式事务详解 本文将详细解释 Spring 的编程式事务管理及声明式事务管理,帮助读者理清思路。 事务管理的重要性 事务管理对于企业应用至关重要。它保证了用户的每一次操作都是可靠的,即便...
1. **Spring编程式事务管理**: 编程式事务管理允许开发者在代码中直接控制事务的开始、提交、回滚等操作。这种方式提供了更大的灵活性,但可能导致事务管理代码分散在整个应用中,增加维护难度。通常,这种方式...
Spring 声明式事务和Spring 编程式事务
本文将全面分析Spring中的编程式事务管理和声明式事务管理,旨在帮助开发者深入理解这两种事务管理方式,并在实际项目中合理选择。 **编程式事务管理** 编程式事务管理是通过代码直接控制事务的开始、提交、回滚等...
本篇文章将深入探讨Spring中的两种主要事务管理方式:编程式事务管理和声明式事务管理。 1. 编程式事务管理: 编程式事务管理允许开发者直接在代码中控制事务的开始、提交、回滚等操作。这种方式具有较高的灵活性,...
本主题将深入探讨Hibernate的编程式事务管理和Spring AOP的声明式事务管理,以及两者如何在实际项目中集成使用。 **Hibernate编程式事务管理** Hibernate作为流行的ORM(对象关系映射)框架,提供了对JDBC事务的...
Spring提供了多种事务管理方式,其中编程式事务管理和声明式事务管理是两种主要的模式。编程式事务管理允许开发者通过代码来精确控制事务的边界,而`TransactionTemplate`就是Spring为编程式事务管理提供的一种便捷...
在本篇“Spring学习笔记(十五)——编程式事务例子”中,我们将深入探讨Spring框架中的编程式事务管理。在实际开发中,我们通常使用声明式事务管理,它基于AOP(面向切面编程)来简化事务处理。然而,有时为了更细...
Spring 中的事务处理可以分为两种方式:声明式事务处理和编程式事务处理。声明式事务处理通过 AOP 的实现,把事务管理代码作为方面封装到业务代码中,使得事务管理代码和业务代码解藕。这使得事务管理变得更加灵活...
在Spring中,事务管理分为编程式和声明式两种方式,而声明式事务处理则是通过配置来控制事务的行为,使得代码与事务逻辑解耦,提高了代码的可读性和可维护性。 首先,我们要理解什么是事务。事务是数据库操作的一组...
它分为两种主要类型:编程式事务管理和声明式事务管理。这两种方式各有特点,适用于不同的场景。 首先,编程式事务管理是通过编写代码来控制事务的开始、提交、回滚以及异常处理。在Spring中,我们通常使用`...
首先,我们要理解Spring事务管理的两种主要方式:编程式事务管理和声明式事务管理。编程式事务管理通常通过AOP(面向切面编程)的TransactionTemplate或PlatformTransactionManager接口直接在代码中控制事务,而声明...
Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 **编程式事务管理**是通过编写代码来显式地管理事务的开始、提交、回滚等操作。在Spring中,可以使用PlatformTransactionManager接口的实现...
本教程将深入探讨 Spring 的编程式事务管理和声明式事务管理,帮助你理解这两种方式的差异与应用场景。 首先,编程式事务管理依赖于编程的方式显式地控制事务的开始、提交、回滚等操作。它通过实现 `...
本教程将深入探讨如何在Spring中实现自定义事务管理器、编程式事务处理以及声明式事务`@Transactional`的使用。 首先,让我们了解事务管理的基本概念。事务是一组数据库操作,这些操作要么全部执行,要么全部回滚,...
Spring框架提供了两种主要类型的事务管理方式:编程式事务管理和声明式事务管理。声明式事务管理通过XML配置或注解的形式定义事务边界,使得业务逻辑与事务控制分离。 ### 描述分析:XML配置示例 提供的XML配置...
- 声明式事务管理背后的实现原理是基于Spring的AOP(面向切面编程),它会在方法执行前后应用事务增强,从而实现事务的自动管理。 在提供的链接中,博主可能详细解释了这些概念,并给出了实际的应用示例,包括如何...
Spring提供两种事务管理方式:编程式事务管理和声明式事务管理。编程式事务管理通过编写代码来控制事务的开始、提交、回滚等操作,灵活性高但侵入性强。相比之下,声明式事务管理则更加简洁,它通过配置或注解来...