全面分析 Spring 的编程式事务管理及声明式事务管理
spring事务配置的五种方式
Spring事务配置的五种方式前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。
通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的。
总结如下:Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
具体如下图:根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:第一种方式:每个Bean都有一个代理<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/ beans/schema/beans/spring-bea ns-2.5.xsd/schema/context/schema/context/spring-co ntext-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionF actoryBean"><property name="configLocation"value="classpath:hibernate.cfg.xml"/><property name="configurationClass"value="org.hibernate.cfg.AnnotationConfiguration"/></bean><!-- 定义事务管理器(声明式的事务)--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransac tionManager"><property name="sessionFactory" ref="sessionFactory"/> </bean><!-- 配置DAO --><bean id="userDaoTarget"class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory"/> </bean><bean id="userDao"class="org.springframework.transaction.interceptor.Transactio nProxyFactoryBean"><!-- 配置事务管理器--><property name="transactionManager"ref="transactionManager"/><property name="target" ref="userDaoTarget"/><property name="proxyInterfaces"value="com.bluesky.spring.dao.GeneratorDao"/><!-- 配置事务属性--><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop> </props></property></bean></beans>第二种方式:所有Bean共享一个代理基类<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/ beans/schema/beans/spring-bea ns-2.5.xsd/schema/context/schema/context/spring-co ntext-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionF actoryBean"><property name="configLocation"value="classpath:hibernate.cfg.xml"/><property name="configurationClass"value="org.hibernate.cfg.AnnotationConfiguration"/></bean><!-- 定义事务管理器(声明式的事务)--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/> </bean><bean id="transactionBase"class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean"lazy-init="true" abstract="true"><!-- 配置事务管理器--><property name="transactionManager"ref="transactionManager"/><!-- 配置事务属性--><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop> </props></property></bean><!-- 配置DAO --><bean id="userDaoTarget"class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory"/> </bean><bean id="userDao" parent="transactionBase"><property name="target" ref="userDaoTarget"/> </bean></beans>第三种方式:使用拦截器<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/ beans/schema/beans/spring-bea ns-2.5.xsd/schema/context/schema/context/spring-co ntext-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionF actoryBean"><property name="configLocation"value="classpath:hibernate.cfg.xml"/><property name="configurationClass"value="org.hibernate.cfg.AnnotationConfiguration"/></bean><!-- 定义事务管理器(声明式的事务)--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/> </bean><bean id="transactionInterceptor"class="org.springframework.transaction.interceptor.Transactio nInterceptor"><property name="transactionManager"ref="transactionManager"/><!-- 配置事务属性--><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop> </props></property></bean><beanclass="org.springframework.aop.framework.autoproxy.BeanNameA utoProxyCreator"><property name="beanNames"><list><value>*Dao</value></list></property><property name="interceptorNames"><list><value>transactionInterceptor</value></list></property></bean><!-- 配置DAO --><bean id="userDao"class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory"/> </bean></beans>第四种方式:使用tx标签配置的拦截器<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/ beans/schema/beans/spring-bea ns-2.5.xsd/schema/context/schema/context/spring-co ntext-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd /schema/tx/schema/tx/spring-tx-2.5.xsd"><context:annotation-config/><context:component-scan base-package="com.bluesky"/><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionF actoryBean"><property name="configLocation"value="classpath:hibernate.cfg.xml"/><property name="configurationClass"value="org.hibernate.cfg.AnnotationConfiguration"/></bean><!-- 定义事务管理器(声明式的事务)--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransac tionManager"><property name="sessionFactory" ref="sessionFactory"/> </bean><tx:advice id="txAdvice"transaction-manager="transactionManager"><tx:attributes><tx:method name="*" propagation="REQUIRED"/> </tx:attributes></tx:advice><aop:config><aop:pointcut id="interceptorPointCuts"expression="execution(* com.bluesky.spring.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice"pointcut-ref="interceptorPointCuts"/></aop:config></beans>第五种方式:全注解<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/conte xt"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/ beans/schema/beans/spring-bea ns-2.5.xsd/schema/context/schema/context/spring-co ntext-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd /schema/tx/schema/tx/spring-tx-2.5.xsd"><context:annotation-config/><context:component-scan base-package="com.bluesky"/><tx:annotation-driven transaction-manager="transactionManager "/><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionF actoryBean"><property name="configLocation"value="classpath:hibernate.cfg.xml"/><property name="configurationClass"value="org.hibernate.cfg.AnnotationConfiguration"/></bean><!-- 定义事务管理器(声明式的事务)--><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransac tionManager"><property name="sessionFactory" ref="sessionFactory"/> </bean></beans>此时在DAO上需加上@Transactional注解,如下:package com.bluesky.spring.dao;import java.util.List;import org.hibernate.SessionFactory;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.support.HibernateDaoSupport;import ponent;import er;@Transactional@Component("userDao")public class UserDaoImpl extends HibernateDaoSupport implements Us erDao {public List<User>listUsers() {return this.getSession().createQuery("from User").list();}}。
全面分析Spring的编程式事务管理及声明式事务管理
开始之前关于本教程本教程将深入讲解Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务。
通过对本教程的学习,您将能够理解Spring 事务管理的本质,并灵活运用之。
先决条件本教程假定您已经掌握了Java 基础知识,并对Spring 有一定了解。
您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等。
本文将直接使用这些概念而不做详细解释。
另外,您最好掌握数据库的基础知识,虽然这不是必须。
系统需求要试验这份教程中的工具和示例,硬件配置需求为:至少带有512MB 内存(推荐1GB)的系统。
需要安装以下软件:•Sun JDK 5.0 或更新版本或IBM Developer Kit for the Java 5 platform 版本。
•Spring framework 2.5。
本教程附带的示例代码已经在Spring 2.5.6 上测试过。
•MySQL 5.0 或更新版本。
Spring 事务属性分析事务管理对于企业应用而言至关重要。
它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。
就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。
在Spring 中,事务是通过TransactionDefinition 接口来定义的。
该接口包含与事务属性有关的方法。
具体如清单1所示:清单1. TransactionDefinition 接口中定义的主要方法public interface TransactionDefinition{int getIsolationLevel();int getPropagationBehavior();int getTimeout();boolean isReadOnly();}也许你会奇怪,为什么接口只提供了获取属性的方法,而没有提供相关设置属性的方法。
Spring事务配置的五种方式
Spring事务原理统观spring事务,围绕着两个核心PlatformTransactionManager和TransactionStatusspring提供了几个关于事务处理的类:TransactionDefinition //事务属性定义TranscationStatus //代表了当前的事务,可以提交,回滚。
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
一般事务定义步骤:TransactionDefinition td = new TransactionDefinition();TransactionStatus ts = transactionManager.getTransaction(td);try{ //do sthmit(ts);}catch(Exception e){transactionManager.rollback(ts);}spring提供的事务管理可以分为两类:编程式的和声明式的。
编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。
编程式主要使用transactionTemplate。
省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象.void add(){transactionTemplate.execute( new TransactionCallback(){pulic Object doInTransaction(TransactionStatus ts){ //do sth}}}声明式:使用TransactionProxyFactoryBean:<bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><property name="transactionManager"><ref bean="transactionManager"/></property><property name="target"><ref local="userManagerTarget"/></property><property name="transactionAttributes"><props><prop key="insert*">PROPAGATION_REQUIRED</prop><prop key="update*">PROPAGATION_REQUIRED</prop><prop key="*">PROPAGATION_REQUIRED,readOnly</prop></props></property></bean>围绕Poxy的动态代理能够自动的提交和回滚事务org.springframework.transaction.interceptor.TransactionProxyFactoryBeanPROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。
Spring编程式事务详解
Spring编程式事务详解为了更细粒度的事务划分,Spring提供如下两种⽅式的编程式事务管理:1 PlatformTransactionManager你也可以使⽤ org.springframework.transaction.PlatformTransactionManager 来直接管理你的事务。
只需通过bean的引⽤,简单的把你在使⽤的PlatformTransactionManager 传递给你的bean。
然后,使⽤TransactionDefinition和TransactionStatus对象, 你可以启动,回滚和提交事务。
DefaultTransactionDefinition def =new DefaultTransactionDefinition();// explicitly setting the transaction name is something that can only be done programmaticallydef.setName("SomeTxName");def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus status = txManager.getTransaction(def);try{// 执⾏业务逻辑}catch(MyException ex){txManager.rollback(status);throw ex;}mit(status);2 TransactionTemplatePlatformTransactionManager中部分代码是可以重⽤的,所以spring对其进⾏了优化,采⽤模板⽅法模式就其进⾏封装,主要省去了提交或者回滚事务的代码。
若你选择编程式事务管理,Spring推荐使⽤ TransactionTemplate。
springboot中的声明式事务管理及编程式事务管理
springboot中的声明式事务管理及编程式事务管理这⼏天在做⼀个功能,具体的情况是这样的: 项⽬中原有的⼏个功能模块中有数据上报的功能,现在需要在这⼏个功能模块的上报之后⽣成⼀条消息记录,然后⼊库,在写个接⼝供前台来拉取消息记录。
看到这个需求,⾸先想到的是使⽤AOP来实现了,然后,我去看了下现有功能模块中的代码,发现了问题,这些模块中的业务逻辑并没有放在service层来处理,直接在controller中处理了,controller中包含了两个甚⾄多个service处理,这样是不能保证事务安全的,既然这样,那么我们如何实现能保证事务安全呢。
我想直接在controller中定义切⼊点,然后before中⼿动开启事务,在afterReturn之后根据需要来提交或者回滚事务。
然后趁着这个机会就查了下spring boot中的事务这块,就从最基础的说起。
1.spring boot中声明式事务的使⽤ 想要在spring boot中使⽤声明式事务,有两种⽅式,⼀种是在各个service层中添加注解,还有⼀种是使⽤AOP配置全局的声明式事务管理 先来说第⼀种,需要⽤到两个注解就,⼀个是@EnableTransactionManagement⽤来开启注解事务管理,等同于xml配置⽅式的 <tx:annotation-driven />,另⼀个是@Transactional 具体代码如下:1package com.example.demo;23import org.springframework.boot.SpringApplication;4import org.springframework.boot.autoconfigure.SpringBootApplication;5import org.springframework.transaction.annotation.EnableTransactionManagement;67// @SpringBootApplication是Sprnig Boot项⽬的核⼼注解,主要⽬的是开启⾃动配置10 @SpringBootApplication11 @EnableTransactionManagement // 启注解事务管理,等同于xml配置⽅式的 <tx:annotation-driven />12public class DemoApplication {14public static void main(String[] args) {16 SpringApplication.run(DemoApplication.class, args);18 }1920 } 然后,注解@Transactional直接加在service层就可以了,放两个service⽤来验证事务是否按预期回滚package com.example.demo.service;import com.example.demo.bean.ResUser;import org.springframework.transaction.annotation.Transactional;import java.util.List;/*** 注解加在接⼝上表名接⼝的所有⽅法都⽀持事务;* 如果加在⽅法上,则只有该⽅法⽀持事务* 可以根据需要在CUD操作上加注解**/@Transactionalpublic interface IUserService {int insertUser(ResUser resUser);int updateUser(ResUser resUser);List<ResUser> getResUserList();}1package com.example.demo.service;23import com.example.demo.bean.ResPartner;4import org.springframework.transaction.annotation.Transactional;56import java.util.List;7import java.util.Map;89 @Transactional10public interface IPartnerService {1112int add(ResPartner resPartner);1314int deleteByIds(String ids);1516int update(ResPartner resPartner);1718 ResPartner queryById(int id);1920 List<ResPartner> queryList(Map<String, Object> params);2122 } 实现类1package com.example.demo.service.impl;23import com.example.demo.bean.ResPartner;4import com.example.demo.dao.PartnerMapperXml;5import com.example.demo.service.IPartnerService;6import org.slf4j.Logger;7import org.slf4j.LoggerFactory;8import org.springframework.beans.factory.annotation.Autowired;9import ponent;1011import java.util.List;12import java.util.Map;1314 @Component("partnerService")15public class PartnerServiceImpl implements IPartnerService {1617private Logger logger = LoggerFactory.getLogger(this.getClass());18 @Autowired19private PartnerMapperXml partnerMapperXml;2021 @Override22public int add(ResPartner resPartner) {23 StringBuilder sbStr = new StringBuilder();24 sbStr.append("id = ").append(resPartner.getId())25 .append(", name = ").append(resPartner.getName())26 .append(", city = ").append(resPartner.getCity())27 .append(", displayName = ").append(resPartner.getDisplayName());(sbStr.toString());29return this.partnerMapperXml.add(resPartner);30 }31 }1package com.example.demo.service.impl;23import com.example.demo.bean.ResPartner;4import com.example.demo.bean.ResUser;5import com.example.demo.dao.PartnerMapperXml;6import com.example.demo.dao.ResUserMapper;7import com.example.demo.service.IUserService;8import org.springframework.beans.factory.annotation.Autowired;9import ponent;1011import java.util.List;1213 @Component("userService")14public class UserServiceImpl implements IUserService {1516 @Autowired17private ResUserMapper resUserMapper;18 @Autowired19private PartnerMapperXml partnerMapperXml;2021 @Override22public int insertUser(ResUser resUser) {2324int i = resUserMapper.insert(resUser);25// ResPartner partner = new ResPartner();26// partner.setId(resUser.getId());27// partner.setName(resUser.getName());28// partner.setDisplayName(resUser.getLogin());29//30// if (true) // ⽤来验证异常,使事务回滚31// throw new RuntimeException("xxxxxxxxxxxxxxx");32// int a = 1/0;33// partnerMapperXml.add(partner);3435return i;36 }3738 } controller代码,JSONMsg是⼀个⾃定义类,就三个属性code,msg,data⽤来给前台返回数据。
J2EE项目实训 Spring框架技术——第9章 Spring中的事务管理技术及实现(第3部分)
第9章Spring中的事务管理技术及实现(第3/3部分)1.1.1采用TransactionTemplate类简化事务编程实现操作1、TransactionTemplate模板类TransactionTemplate模板类封装了事务管理的功能,这包括产生数据访问异常时的事务回滚,以及操作成功后的事务提交等。
和Spring 框架DAO组件中的JdbcTemplate类一样,它使得开发者无需再关注数据访问中的各种异常出现时的try/catch/finally等代码,这样也将能够帮助开发者省去了部分事务提交、回滚代码。
2、应用TransactionTemplate模板类对前面的DAO类中的doUpdateUserInfo方法进行简化(1)修改原来的DAOImple类中的doUpdateUserInfo方法为下面的【例9-19】中所示的状态由于TransactionTemplate模板类需要采用Java中的内部类的编程风格,为了能够在内部类中访问上层类中的成员数据,将原来在updateOneUserInfo方法中定义的一些参数(请参考【例9-17】中的代码示例)移出到类中进行定义。
并请注意其中的黑体部分的代码。
【例9-19】应用TransactionTemplate模板类的代码示例Object parameter[]=new Object[3];String updateSQL1 =null;String updateSQL2 =null;public boolean updateOneUserInfo(UserInfoVO oneUserInfoVO,String newUserPassWord){String userName=oneUserInfoVO.getUserName();String userPassWord=oneUserInfoVO.getUserPassWord();parameter[0]=newUserPassWord;parameter[1]=userName;parameter[2]=userPassWord;updateSQL1 ="update userInfo set userPassWord = ? where userName =? and userPassWord=?";updateSQL2 ="update abcTable set userPassWord = ? where userName =? and userPassWord=?";TransactionTemplate transactionTemplate =new TransactionTemplate(transactionManager);transactionTemplate.execute(new TransactionCallbackWithoutResult(){public void doInTransactionWithoutResult(TransactionStatus status) {jdbcTemplate.update(updateSQL1,parameter);jdbcTemplate.update(updateSQL2,parameter);}});return true;}(2)对比【例9-19】和【例9-16】中有关事务控制方面的代码明显地能够发现出,应用TransactionTemplate模板类能够简化对事务控制方面的代码实现。
spring事务
Spring事务管理(详解+实例)1 初步理解理解事务之前,先讲一个你日常生活中最常干的事:取钱。
比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。
这两个步骤必须是要么都执行要么都不执行。
如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。
所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。
事务就是用来解决类似问题的。
事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。
事务有四个特性:ACID∙原子性(Atomicity):事务是一个原子操作,由一系列动作组成。
事务的原子性确保动作要么全部完成,要么完全不起作用。
∙一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。
在现实中的数据不应该被破坏。
∙隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
∙持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。
通常情况下,事务的结果被写到持久化存储器中。
2 核心接口Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略。
Spring事务管理涉及的接口的联系如下:2.1 事务管理器Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
Spring中的事务管理实例详解
Spring中的事务管理实例详解本文实例讲述了Spring中的事务管理。
分享给大家供大家参考。
具体分析如下:事务简介:事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性事务就是一系列的动作,它们被当作一个单独的工作单元。
这些动作要么全部完成,要么全部不起作用事务的四个关键属性(ACID)①原子性(atomicity):事务室一个原子操作,有一系列动作组成。
事务的原子性确保动作要么全部完成,要么完全不起作用②一致性(consistency):一旦所有事务动作完成,事务就被提交。
数据和资源就处于一种满足业务规则的一致性状态中③隔离性(isolation):可能有许多事务会同时处理相同的数据,因此每个事物都应该与其他事务隔离开来,防止数据损坏④持久性(durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。
通常情况下,事务的结果被写到持久化存储器中Spring中的事务管理作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层。
而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制。
Spring既支持编程式事务管理,也支持声明式的事务管理编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码声明式事务管理:大多数情况下比编程式事务管理更好用。
它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
事务管理作为一种横切关注点,可以通过AOP方法模块化。
Spring通过Spring AOP框架支持声明式事务管理。
Spring事务的传播属性:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以由传播属性指定。
Spring定义了7种传播行为:Spring支持的事务传播行为传播行为含义PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。
Spring声明式事务管理源码解读之事务开始与提交
Spring声明式事务管理源码解读简介:事务是所有企业应用系统的核心,之前人们使用ejb的时候,容器事务管理(CMT),是slsb最令人称道的地方,据说很多人使用ejb,使用slsb就是为了cmt,但是spring出现之后,格局就变了,因为程序员又多了一种选择,就是声明式f事务管理,声明式事务管理是基于AOP的,及AOP是它的底层特性,本文的目的就是为了和大家探讨一下spring的声明式事务管理,从源代码来分析它的背后的思想。
spring声明式事务管理的事务开始部分这个是我昨天在解决问题是看源码得一点体验,可能说得比较大概,希望大家多多讨论,把本贴得质量提高上去,因为spring实现的事务管理这部分我相信还是有点复杂的。
一个人未必能想得十分清楚在spring的声明式事务管理中,它是如何判定一个及标记一个方法是否应该是处在事务体之中呢。
首先要理解的是spring是如何来标记一个方法是否应该处在事务体之中的。
有这样一个接口TransactionDefinition,其中定义了很多常量,它还有一个子接口TransactionAttribute,其中只有一个方法rollback。
TransactionDefinition中有很多常量定义,它们分别属于两种类型,传播途径和隔离级别Java代码1./**2.* Support a current transaction, create a new one if none exists.3.* Analogous to EJB transaction attribute of the same name.4.* <p>This is typically the default setting of a transactiondefinition.5.*/6.int PROPAGATION_REQUIRED = 0;当然其中也定义了隔离级别/**Java代码1.* A constant indicating that dirty reads are prevented;non-repeatable reads2.* and phantom reads can occur. This level only prohibits atransaction3.* from reading a row with uncommitted changes in it.4.* @see java.sql.Connection#TRANSACTION_READ_COMMITTED5.*/6.int ISOLATION_READ_COMMITTED =Connection.TRANSACTION_READ_COMMITTED;同时还有两个对应的方法来得到这样的传播途径和隔离级别Java代码1./**2.* Return the propagation behavior.3.* Must return one of the PROPAGATION constants.4.* @see #PROPAGATION_REQUIRED5.* @seeorg.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()6.*/7.int getPropagationBehavior();8.9./**10.* Return the isolation level.11.* Must return one of the ISOLATION constants.12.* <p>Only makes sense in combination with PROPAGATION_REQUIRED or13.* PROPAGATION_REQUIRES_NEW.14.* <p>Note that a transaction manager that does not support custom15.* isolation levels will throw an exception when given any otherlevel16.* than ISOLATION_DEFAULT.17.* @see #ISOLATION_DEFAULT18.*/19.int getIsolationLevel();这个接口有一个默认的实现DefaultTransactionDefinition。
Spring2.5声明式事务管理详解
大多数Spring用户选择声明式事务管理。
这是对应用代码影响最小的选择,因此也最符合非侵入式轻量级容器的理念。
Spring的声明式事务管理是通过Spring AOP实现的,因为事务方面的代码与Spring绑定并以一种样板式风格使用,不过尽管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的声明式事务管理。
从考虑EJB CMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。
它们的基本方法是相似的:都可以指定事务管理到单独的方法;如果需要可以在事务上下文调用setRollbackOnly()方法。
不同之处在于:∙不像EJB CMT绑定在JTA上,Spring声明式事务管理可以在任何环境下使用。
只需更改配置文件,它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作。
∙Spring的声明式事务管理可以被应用到任何类(以及那个类的实例)上,不仅仅是像EJB那样的特殊类。
∙Spring提供了声明式的回滚规则:EJB没有对应的特性,我们将在下面讨论。
回滚可以声明式的控制,不仅仅是编程式的。
∙Spring允许你通过AOP定制事务行为。
例如,如果需要,你可以在事务回滚中插入定制的行为。
你也可以增加任意的通知,就象事务通知一样。
使用EJB CMT,除了使用setRollbackOnly(),你没有办法能够影响容器的事务管理。
∙Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。
如果你需要这些特性,我们推荐你使用EJB。
然而,不要轻易使用这些特性。
因为通常我们并不希望事务跨越远程调用。
TransactionProxyFactoryBean在哪儿?Spring2.0及以后的版本中声明式事务的配置与之前的版本有相当大的不同。
主要差异在于不再需要配置TransactionProxyFactoryBean了。
Spring2.0之前的旧版本风格的配置仍然是有效的;你可以简单地认为新的<tx:tags/>替你定义了T ransactionProxyFactoryBean。
spring事务管理
5事务管理为了描述事务的概念,我们拿买电影票来举例。
买一张电影票通常有一下步骤:检查剩余座位的数量,确定是否能给你提供你需要的座位个数每卖出一张票,可用座位的数量就应该减一付款售票员把票给你如果一切顺利的话,你就可以欣赏到一场一鸣惊人的电影,而影院也增加了收入。
但是如果有环节出差错了怎么办呢?比如说:你用来付款的信用卡没钱了?显然,你不会拿到票,影院也拿不到钱。
但是如果说座位的数量在下个人购买之前没有被恢复到原来的状态,那么电影也许因为人为原因而不会满场了。
或者如果出现这样的情况:一切都很顺利,但是发放票的时候出了问题。
你只好乖乖的呆在家里看电视了,而且还损失了一小笔钱。
为了保证剧院和你都不受到损失,上面的操作应该用事务封装起来。
作为事务,它应该被看成是一个单独的动作,以保证要么所有的操作都成功,或者所有的操作都回滚到初始的状态。
在软件中,事务有着举足轻重的地位,确保数据和资源保持一致的状态。
如果没有事务,那么数据有可能因为应用程序的业务逻辑而变成脏数据,或者变成与其他数据不统一的数据。
让我们快速浏览一下事务向导和他是如何工作的。
有以下四个因素。
5.1.1 用四句话来解释事务在软件开发的一个重要传统里,可以用一个单词首字母的缩写来描述一个事务:ACID,简言之,ACID代表Atomic(原子性)事务由一个或多个动作绑定起来作为一个单独的工作单元。
原子性保证事务中所有的操作要么都执行,或者都不执行。
如果所有的动作都执行了,那么事务就是成功的,如果其中有一个动作失败了,那么整个事务都失败,而且要执行回滚操作。
Consistent(一致性)一旦事务结束(可能成功了也可能失败了),那么系统所模拟的业务逻辑要处于一致的状态。
数据不应该被实体关系破坏。
Isolated(隔离性)事务应该允许多个用户操作一个数据,一个用户的操作应该不受另一个用户操作的影响。
因此事务之间应该是相互隔离的,以阻止他们在操作中同时读写同一数据。
SpringBoot事务注解@Transactional
SpringBoot事务注解@TransactionalSpringBoot提供了⾮常⽅便的事务操作,通过注解就可以实现事务的回滚,⾮常⽅便快捷,下⾯我们就说⼀下如何进⾏事务操作。
1. 事务说明在Spring中,事务有两种实现⽅式,分别是编程式事务管理和声明式事务管理两种⽅式。
编程式事务管理:编程式事务管理使⽤TransactionTemplate或者直接使⽤底层的PlatformTransactionManager。
对于编程式事务管理,spring推荐使⽤TransactionTemplate。
声明式事务管理:建⽴在AOP之上的。
其本质是对⽅法前后进⾏拦截,然后在⽬标⽅法开始之前创建或者加⼊⼀个事务,在执⾏完⽬标⽅法之后根据执⾏情况提交或者回滚事务。
声明式事务管理不需要⼊侵代码,通过@Transactional就可以进⾏事务操作,更快捷⽽且简单。
推荐使⽤2. 如何使⽤在Mybatis中使⽤事务,⾮常简单,只需要在函数增加注解@Transactional,⽆需任何配置。
我们通过在controller层增加事务例⼦看下:@AutowiredOrderServiceorderService; //order操作的Service层@ApiOperation(value = "增加OrderCustomer")@RequestMapping(value = "", method = RequestMethod.POST)@ResponseBody@Transactionalpublic JsonBean<Order> insertOrder(@RequestParam(value = "order") String order) {try {//创建订单Order order = orderService.insert(user.getId(),is_company,fk_want_company_id);return new JsonBean(SUCCESS, orderCustomer);}catch (ErrorCodeException e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return new JsonBean(e.getErrorCode());}}@Transactional可以作⽤于接⼝、接⼝⽅法、类以及类⽅法上。
Spring源代码解析6:Spring声明式事务处理
我们看看Spring中的事务处理的代码,使用Spring管理事务有声明式和编程式两种方式,声明式事务处理通过AOP的实现把事物管理代码作为方面封装来横向插入到业务代码中,使得事务管理代码和业务代码解藕。
在这种方式我们结合IoC容器和Spirng已有的FactoryBean来对事务管理进行属性配置,比如传播行为,隔离级别等。
其中最简单的方式就是通过配置TransactionProxyFactoryBean来实现声明式事物;在整个源代码分析中,我们可以大致可以看到Spring实现声明式事物管理有这么几个部分:* 对在上下文中配置的属性的处理,这里涉及的类是TransactionAttributeSourceAdvisor,这是一个通知器,用它来对属性值进行处理,属性信息放在TransactionAttribute中来使用,而这些属性的处理往往是和对切入点的处理是结合起来的。
对属性的处理放在类TransactionAttributeSource中完成。
* 创建事物的过程,这个过程是委托给具体的事物管理器来创建的,但Spring 通过TransactionStatus来传递相关的信息。
* 对事物的处理通过对相关信息的判断来委托给具体的事物管理器完成。
我们下面看看具体的实现,在TransactionFactoryBean中:代码1.public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean2. implements FactoryBean, BeanFactoryAware {3.//这里是Spring事务处理而使用的AOP拦截器,中间封装了Spring对事务处理的代码来支持声明式事务处理的实现4. private final TransactionInterceptor transactionInterceptor= new TransactionInterceptor();5.6. private Pointcut pointcut;7.8.//这里Spring把TransactionManager注入到TransactionInterceptor中去9. public void setTransactionManager(PlatformTransactionManager transactionManager) {10. this.transactionInterceptor.setTransactionManager(transactionManager);11. }12.13.//这里把在bean配置文件中读到的事务管理的属性信息注入到TransactionInterceptor中去14. public void setTransactionAttributes(Properties transactionAttributes) {15. this.transactionInterceptor.setTransactionAttributes(transactionAttributes);16. }17.18. .........中间省略了其他一些方法.......19.20. //这里创建Spring AOP对事务处理的Advisor21. protected Object createMainInterceptor() {22. this.transactionInterceptor.afterPropertiesSet();23. if (this.pointcut != null) {24. //这里使用默认的通知器25. return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);26. }27. else {28. // 使用上面定义好的TransactionInterceptor作为拦截器,同时使用TransactionAttributeSourceAdvisor29. return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);30. }31. }32.}那什么时候Spring的TransactionInterceptor被注入到Spring AOP中成为Advisor中的一部分呢?我们看到在TransactionProxyFactoryBean中,这个方法在IOC初始化bean的时候被执行:代码1.public void afterPropertiesSet() {2. .......3. //TransactionProxyFactoryBean实际上使用ProxyFactory完成AOP的基本功能。
【Spring】Spring的事务管理-2、声明式事务管理(实现基于XML、Annotat。。。
【Spring】Spring的事务管理-2、声明式事务管理(实现基于XML、Annotat。
声明式事务管理⽂章⽬录简单记录 - 简单记录-Java EE企业级应⽤开发教程(Spring+Spring MVC+MyBatis)和 Spring 3.0就这么简单 -Spring的事务管理声明式事务管理数据访问的技术很多,如JDBC、JPA、Hibernate、分布式事务等。
⾯对众多的数据访问技术,Spring在不同的事务管理API上定义了⼀个抽象层PlatformTransaction-Manager,应⽤程序开发⼈员不必了解底层的事务管理API就可以使⽤Spring的事务管理机制。
Spring并不直接管理事务,⽽是提供了许多内置事务管理器实现,常⽤的有DataSourceTransactionManager、JdoTransactionManager、JpaTransactionManager以及HibernateTransactionManager等。
(Spring作为企业级应⽤程序框架,在不同的事务管理API上定义了⼀个抽象层,使应⽤程序开发⼈员不必了解底层的事务管理API,就可以使⽤Spring的事务管理机制。
)Spring事务管理分两种⽅式,⼀种是传统的编程式事务管理(也称编码式事务),另⼀种是声明式事务管理。
编程式事务管理通过编写代码实现的事务管理,包括定义事务的开始、正常执⾏后的事务提交和异常时的事务回滚。
编程式事务管理是将事务管理代码嵌⼊业务⽅法中来控制事务的提交和回滚。
在编程式事务中,必须在每个业务操作中包含额外的事务管理代码。
声明式事务管理声明式事务管理是指将事务管理代码从业务⽅法中分离出来,以声明的⽅式来实现事务管理。
在⼤多数情况下,声明式事务管理⽐编程式事务管理更好⽤。
Spring是通过AOP框架技术⽀持实现的事务管理,主要思想是将事务作为⼀个“切⾯”代码单独编写,然后通过AOP技术将事务管理的“切⾯”植⼊到业务⽬标类中。
Spring声明式事务管理
Spring声明式事务管理案例分析 本案例是图书管理系统精简部分,在数据库中有3张表。
分别保存图书库存、图书信息和⽤户信息。
下⾯是建表SQL语句 1DROP TABLE IF EXISTS store;2DROP TABLE IF EXISTS book ;3DROP TABLE IF EXISTS user;45-- 图书表6CREATE TABLE book(7 sn VARCHAR(20) PRIMARY KEY , -- 图书编码8 name VARCHAR(20) NOT NULL, -- 图书名称9 price NUMERIC(9,2) NOT NULL-- 图书价格10 );1112-- 仓库表13CREATE TABLE store(14 sn VARCHAR(20), -- 图书编码15 stock INT(9) NOT NULL, -- 图书库存16CONSTRAINT fk_sn FOREIGN KEY (sn) REFERENCES book(sn)17 );1819-- ⽤户表20CREATE TABLE user(21 id INT(11) PRIMARY KEY AUTO_INCREMENT, -- id22 name VARCHAR(20) NOT NULL, -- 姓名23 balance NUMERIC(9,2) NOT NULL DEFAULT0-- 余额24 );2526INSERT INTO book VALUES ('1001','Java从⼊门到精通',100);27INSERT INTO book VALUES ('1002','Spring从⼊门到精通',90);28INSERT INTO book VALUES ('1003','J2EE核⼼框架',80);2930INSERT INTO store VALUES ('1001',50);31INSERT INTO store VALUES ('1002',20);32INSERT INTO store VALUES ('1003',10);3334INSERT INTO user (name,balance) VALUES ('caoyc',150);实体类Book.java1package com.proc.bean;23public class Book {45private String sn;6private String name;7private Double price;89public String getSn() {10return sn;11 }1213public void setSn(String sn) {14this.sn = sn;15 }1617public String getName() {18return name;19 }2021public void setName(String name) { = name;23 }2425public Double getPrice() {26return price;27 }2829public void setPrice(Double price) {30this.price = price;31 }3233public String toString() {34return "Book [sn=" + sn + ", name=" + name + ", price=" + price + "]";35 }3637 }Store.java1package com.proc.bean;23/**仓库类*/4public class Store {56private String sn;7private Integer stock;8public String getSn() {9return sn;10 }11public void setSn(String sn) {12this.sn = sn;13 }14public Integer getStock() {15return stock;16 }17public void setStock(Integer stock) {18this.stock = stock;19 }20 @Override21public String toString() {22return "Store [sn=" + sn + ", stock=" + stock + "]";23 }242526 }User.java1package com.proc.bean;23/**4 * @author caoyc5 *6*/7public class User {89private Integer id;10private String name;11private Double balance;12public Integer getId() {13return id;14 }15public void setId(Integer id) {16this.id = id;17 }18public String getName() {19return name;20 }21public void setName(String name) { = name;23 }24public Double getBalance() {25return balance;26 }27public void setBalance(Double balance) {28this.balance = balance;29 }30 @Override31public String toString() {32return "User [id=" + id + ", name=" + name + ", balance=" + balance33 + "]";34 }353637 }Spring配置信息使⽤db.properties记录数据库配置信息,这样便于后期维护1 er=root2 jdbc.password=1234563 jdbc.driverClass=com.mysql.jdbc.Driver4 jdbc.jdbcUrl=jdbc\:mysql\:///test配置applicationContext.xml信息1<!-- 配置⾃动扫描策略 -->2<context:component-scan base-package="com.proc"/>34<!-- 读取db.properties配置信息 -->5<context:property-placeholder location="classpath:db.properties"/>67<!-- 配置⼀个C3P0数据源 -->8<bean id="dataSource" class="boPooledDataSource">9<property name="user" value="${er}"/>10<property name="password" value="${jdbc.password}"/>11<property name="driverClass" value="${jdbc.driverClass}"/>12<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>13</bean>1415<!-- 配置⼀个JdbcTemplate,⽤来操作数据库 -->16<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">17<property name="dataSource" ref="dataSource"/>18</bean> 这⾥我们使⽤⾃动扫描策略,使⽤的是C3P0连接池。
spring的事务面试题
spring的事务面试题Spring框架在Java开发中广泛应用于处理事务。
面试中可能会遇到与Spring事务相关的问题,本文将介绍一些常见的Spring事务面试题及其解答,帮助读者更好地准备面试。
一、什么是Spring事务管理?Spring事务管理是指通过Spring框架对数据库事务进行管理的一种机制。
它可以有效地处理数据库操作中的并发问题、事务回滚、事务隔离级别等问题,确保数据库操作的一致性和完整性。
二、Spring事务管理的方式有哪些?Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。
1. 编程式事务管理:通过编写代码来显式管理事务的提交、回滚等操作。
这种方式允许开发者更加灵活地控制事务的细节,但会使代码变得复杂。
2. 声明式事务管理:通过在配置文件中或使用注解的方式来声明事务的管理,将事务处理与业务逻辑分离。
这种方式使得代码更加简洁,但对开发者的要求较高。
三、Spring事务管理的传播行为有哪些?Spring事务的传播行为定义了多个事务方法相互调用时事务如何进行传播。
常用的事务传播行为有以下几种:1. PROPAGATION_REQUIRED(默认):若当前存在事务,则加入该事务;若当前没有事务,则创建一个新的事务。
2. PROPAGATION_SUPPORTS:支持当前事务,若当前不存在事务,则以非事务方式执行。
3. PROPAGATION_MANDATORY:支持当前事务,若当前不存在事务,则抛出异常。
4. PROPAGATION_REQUIRES_NEW:创建新事务,若当前存在事务,则将当前事务挂起。
5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,若当前存在事务,则将当前事务挂起。
6. PROPAGATION_NEVER:以非事务方式执行操作,若当前存在事务,则抛出异常。
7. PROPAGATION_NESTED:若当前存在事务,则在嵌套事务中执行;若当前没有事务,则创建一个新的事务。
Spring编程式和声明式事务实例讲解小结
Spring编程式和声明式事务实例讲解⼩结Spring事务管理Spring⽀持两种⽅式的事务管理:编程式事务管理:通过Transaction Template⼿动管理事务,实际应⽤中很少使⽤,使⽤XML配置声明式事务:推荐使⽤(代码侵⼊性最⼩),实际是通过AOP实现实现声明式事务的四种⽅式:基于 TransactionInterceptor 的声明式事务: Spring 声明式事务的基础,通常也不建议使⽤这种⽅式,但是与前⾯⼀样,了解这种⽅式对理解 Spring 声明式事务有很⼤作⽤。
基于 TransactionProxyFactoryBean 的声明式事务: 第⼀种⽅式的改进版本,简化的配置⽂件的书写,这是 Spring 早期推荐的声明式事务管理⽅式,但是在 Spring 2.0 中已经不推荐了。
基于< tx> 和< aop>命名空间的声明式事务管理:⽬前推荐的⽅式,其最⼤特点是与 Spring AOP 结合紧密,可以充分利⽤切点表达式的强⼤⽀持,使得管理事务更加灵活。
基于 @Transactional 的全注解⽅式:将声明式事务管理简化到了极致。
开发⼈员只需在配置⽂件中加上⼀⾏启⽤相关后处理 Bean 的配置,然后在需要实施事务管理的⽅法或者类上使⽤ @Transactional 指定事务规则即可实现事务管理,⽽且功能也不必其他⽅式逊⾊。
我们今天要将的是使⽤编程式以及基于AspectJ的声明式和基于注解的事务⽅式,实现烂⼤街的转账业务。
再来说⼀下这个案例的思想吧,我们在两次转账之间添加⼀个错误语句(对应银⾏断电等意外情况),如果这个时候两次转账不能成功,则说明事务配置正确,否则,事务配置不正确。
你需要完成的任务:使⽤编程式事务管理完成转账业务使⽤基于AspectJ的声明式事务管理完成转账业务使⽤基于 @Transactional 的全注解⽅式事务管理完成转账业务备注:下⾯的代码是在很久之前,我刚学Sping还没有接触Maven的时候写的,所以我使⽤的原始添加jar的⽅式,使⽤Maven的⼩伙伴可以⾃⾏添加Maven依赖项⽬结构:Spring编程式和声明式事务实例讲解开发⼯具:Myeclipse2017SQL:create table `account` (`username` varchar (99),`salary` int (11));insert into `account` (`username`, `salary`) values('⼩王','3000');insert into `account` (`username`, `salary`) values('⼩马','3000');(1)编程式事务管理注意:通过添加/删除accountMoney() ⽅法中int i = 10 / 0这个语句便可验证事务管理是否配置正确。
关于Spring中声明式事务的使用详解
关于Spring中声明式事务的使⽤详解⽬录⼀、前⾔⼆、回顾JDBC的数据库事务三、数据库事务隔离级别3.1 数据库事务的基本特征3.2 详解数据库隔离级别3.2.1 未提交读3.2.2 读提交3.2.3 可重复读3.2.4 串⾏化3.2.5 各个隔离级别的总结四、数据库事务传播⾏为五、Spring中的声明式事务的使⽤5.1 @Transactional的配置属性5.2 Spring的事务管理器5.3 配置事务的传播⾏为和隔离级别六、总结⼀、前⾔在Spring中,数据库事务是通过AOP技术来提供服务的。
使⽤原⽣的JDBC操作时会存在⼤量的try{}catch{}finally{}语句,所以会存在⼤量的冗余代码,例如打开和关闭数据库连接和数据库事务回滚等。
通过Spring的AOP之后,这些冗余的代码就都被处理了。
⼆、回顾JDBC的数据库事务接下来我们⼀起回顾⼀下,刚⼊门使⽤JDBC操作的时候,写得让⼈烦躁代码⽚段吧。
@Servicepublic class JdbcTransaction {@Autowiredprivate DataSource dataSource;public int insertStudent(Student student) {Connection connection = null;int result = 0;try {// 获取数据连接connection = dataSource.getConnection();// 开始事务connection.setAutoCommit(false);// 设置隔离级别connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);// 执⾏sqlPreparedStatement prepareStatement = connection.prepareStatement("insert into t_student(name,gender,age) values (?,?,?)");prepareStatement.setString(1, student.getName());prepareStatement.setString(2, student.getGender());prepareStatement.setInt(3, student.getAge());result = prepareStatement.executeUpdate();// 提交事务mit();} catch (Exception e1) {if (connection != null) {try {// 事务回滚connection.rollback();} catch (Exception e2) {e2.printStackTrace();}}e1.printStackTrace();} finally {try {if (connection != null && !connection.isClosed()) {// 关闭连接connection.close();}} catch (SQLException e) {e.printStackTrace();}}return result;}}在上述的⼀⼤串代码中也就⼀下已⾏的业务代码是我们最为关注的,在每个使⽤JDBC的业务代码中,都经常可以看到数据库连接的获取和关闭以及事务的提交和回滚,⼤量的try...catch...finally..语句会充斥在代码块中。
Spring事务管理之声明式事务管理-基于AspectJ的XML方式
Spring事务管理之声明式事务管理-基于AspectJ的XML⽅式© 版权声明:本⽂为博主原创⽂章,转载请注明出处案例 - 利⽤Spring的声明式事务(AspectJ)管理模拟转账过程数据库准备-- 创建表CREATE TABLE `account`(`id` INT NOT NULL AUTO_INCREMENT,`name` VARCHAR(100) NOT NULL,`money` DOUBLE DEFAULT 0,PRIMARY KEY (`id`))ENGINE = INNODB DEFAULT CHARSET = UTF8;-- 初始化数据INSERT INTO account (name, money) VALUES ('张三', 1000);INSERT INTO account (name, money) VALUES ('李四', 1000);INSERT INTO account (name, money) VALUES ('王五', 1000);实例1.项⽬结构2.pom.xml<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.spring</groupId><artifactId>SpringTransaction-AspectJ</artifactId><packaging>war</packaging><version>0.0.1-SNAPSHOT</version><name>SpringTransaction-AspectJ Maven Webapp</name><url></url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>4.3.8.RELEASE</spring.version></properties><dependencies><!-- junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- spring core --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><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><!-- spring dao --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!-- spring test --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!-- C3P0 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><!-- MySQL --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.42</version></dependency><!-- AspectJ --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.10</version></dependency></dependencies><build><finalName>SpringTransaction-AspectJ</finalName></build></project>3.AccountDao.javapackage org.spring.dao;/*** 转账操作DAO层接⼝**/public interface AccountDao {/*** 转出** @param out* 转出账户* @param money* 转出⾦额*/void outMoney(String out, double money);/*** 转⼊** @param in* 转⼊账户* @param money* 转⼊⾦额*/void inMoney(String in, double money);}4.AccountDaoImpl.javapackage org.spring.dao.impl;import org.spring.dao.AccountDao;import org.springframework.jdbc.core.support.JdbcDaoSupport;/*** 转账操作DAO层实现类**/public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { /*** 转出** @param out* 转出账户* @param money* 转出⾦额*/public void outMoney(String out, double money) {String sql = "update account set money = money - ? where name = ?";this.getJdbcTemplate().update(sql, money, out);}/*** 转⼊** @param in* 转⼊账户* @param money* 转⼊⾦额*/public void inMoney(String in, double money) {String sql = "update account set money = money + ? where name = ?";this.getJdbcTemplate().update(sql, money, in);}}5.AccountService.javapackage org.spring.service;/*** 转账操作业务层接⼝**/public interface AccountService {/*** 转账** @param out* 转出账户* @param in* 转⼊账户* @param money* 转账⾦额*/void transfer(String out, String in, double money);}6.AccountServiceImpl.javapackage org.spring.service.impl;import org.spring.dao.AccountDao;import org.spring.service.AccountService;/*** 转账操作业务层实现类**/public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 转账*/public void transfer(String out, String in, double money) {accountDao.outMoney(out, money);accountDao.inMoney(in, money);}}7.jdbc.propertiesjdbc.driver=com.mysql.jdbc.Driverername=rootjdbc.password=***jdbc.url=jdbc:mysql:///spring_transaction?useSSL=true&characterEncoding=UTF-88.applicationContext.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:tx="/schema/tx"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/tx/schema/tx/spring-tx.xsd/schema/aop/schema/aop/spring-aop.xsd"><!-- 引⼊外部属性⽂件 --><context:property-placeholder location="classpath:jdbc.properties"/><!-- 配置C3P0连接池 --><bean id="dataSource" class="boPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="user" value="${ername}"/><property name="password" value="${jdbc.password}"/><property name="jdbcUrl" value="${jdbc.url}"/></bean><!-- 配置业务类 --><bean id="accountService" class="org.spring.service.impl.AccountServiceImpl"><!-- 注⼊DAO --><property name="accountDao" ref="accountDao"/></bean><!-- 配置DAO类 --><bean id="accountDao" class="org.spring.dao.impl.AccountDaoImpl"><!-- 注⼊数据库连接池 --><property name="dataSource" ref="dataSource"/></bean><!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注⼊数据库连接池 --><property name="dataSource" ref="dataSource"/></bean><!-- 配置事务的通知 --><tx:advice id="txAdvice"><tx:attributes><tx:method name="transfer" propagation="REQUIRED"/></tx:attributes></tx:advice><!-- 配置切⾯ --><aop:config><!-- 配置切⼊点 --><aop:pointcut expression="execution(* org.spring.service.*+.*(..))" id="pointcut"/><!-- 配置切⾯ --><aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/></aop:config></beans>9.TestAspectJTransaction.javapackage org.spring.test;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.spring.service.AccountService;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestAspectJTransaction {@Resource(name="accountService")private AccountService accountService;@Testpublic void testTransfer() {accountService.transfer("张三", "李四", 200d);}}10.效果预览 10.1 正常执⾏ 10.2 ⾮正常执⾏(修改AccountServiceImpl.java如下)package org.spring.service.impl;import org.spring.dao.AccountDao;import org.spring.service.AccountService;/*** 转账操作业务层实现类**/public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 转账*/public void transfer(String out, String in, double money) {accountDao.outMoney(out, money);int i = 1 / 0;accountDao.inMoney(in, money);}} 结果如下:参考:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
开始之前关于本教程本教程将深入讲解Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务。
通过对本教程的学习,您将能够理解Spring 事务管理的本质,并灵活运用之。
先决条件本教程假定您已经掌握了Java 基础知识,并对Spring 有一定了解。
您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等。
本文将直接使用这些概念而不做详细解释。
另外,您最好掌握数据库的基础知识,虽然这不是必须。
系统需求要试验这份教程中的工具和示例,硬件配置需求为:至少带有512MB 内存(推荐1GB)的系统。
需要安装以下软件:•Sun JDK 或更新版本或IBM Developer Kit for the Java 5 platform 版本。
•Spring framework 。
本教程附带的示例代码已经在Spring 上测试过。
•MySQL 或更新版本。
•Spring 事务属性分析事务管理对于企业应用而言至关重要。
它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。
就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。
在Spring 中,事务是通过TransactionDefinition 接口来定义的。
该接口包含与事务属性有关的方法。
具体如清单1所示:清单1. TransactionDefinition 接口中定义的主要方法public interface TransactionDefinition{int getIsolationLevel();int getPropagationBehavior();int getTimeout();boolean isReadOnly();}也许你会奇怪,为什么接口只提供了获取属性的方法,而没有提供相关设置属性的方法。
其实道理很简单,事务属性的设置完全是程序员控制的,因此程序员可以自定义任何设置属性的方法,而且保存属性的字段也没有任何要求。
唯一的要求的是,Spring 进行事务操作的时候,通过调用以上接口提供的方法必须能够返回事务相关的属性取值。
事务隔离级别隔离级别是指若干个并发的事务之间的隔离程度。
TransactionDefinition 接口中定义了五个表示隔离级别的常量:•:这是默认值,表示使用底层数据库的默认隔离级别。
对大部分数据库而言,通常这值就是。
••:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。
该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
••:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。
该级别可以防止脏读,这也是大多数情况下的推荐值。
••:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。
即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。
该级别可以防止脏读和不可重复读。
••:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
但是这将严重影响程序的性能。
通常情况下也不会用到该级别。
•事务传播行为所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
在TransactionDefinition定义中包括了如下几个表示传播行为的常量:•:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
••:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
••:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
••:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
••:以非事务方式运行,如果当前存在事务,则抛出异常。
••:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
••:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于。
这里需要指出的是,前面的六种事务传播行为是Spring 从EJB 中引入的,他们共享相同的概念。
而PROPAGATION_NESTED是Spring 所特有的。
以PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。
如果熟悉JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。
另外,外部事务的回滚也会导致嵌套子事务的回滚。
事务超时所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。
在TransactionDefinition 中以int 的值来表示超时时间,其单位是秒。
事务的只读属性事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。
所谓事务性资源就是指那些被事务管理的资源,比如数据源、JMS 资源,以及自定义的事务性资源等等。
如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。
在TransactionDefinition 中以boolean 类型来表示该事务是否只读。
事务的回滚规则通常情况下,如果在事务中抛出了未检查异常(继承自RuntimeException 的异常),则默认将回滚事务。
如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。
这通常也是大多数开发者希望的处理方式,也是EJB 中的默认处理方式。
但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。
Spring 事务管理API 分析Spring 框架中,涉及到事务管理的API 大约有100个左右,其中最重要的有三个:TransactionDefinition、PlatformTransactionManager、TransactionStatus。
所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。
“给定的事务规则”就是用TransactionDefinition 表示的,“按照……来执行提交或者回滚操作”便是用PlatformTransactionManager 来表示,而TransactionStatus 用于表示一个运行着的事务的状态。
打一个不恰当的比喻,TransactionDefinition 与TransactionStatus 的关系就像程序和进程的关系。
TransactionDef...该接口在前面已经介绍过,它用于定义一个事务。
它包含了事务的静态属性,比如:事务传播行为、超时时间等等。
Spring 为我们提供了一个默认的实现类:DefaultTransactionDefinition,该类适用于大多数情况。
如果该类不能满足需求,可以通过实现TransactionDefinition 接口来实现自己的事务定义。
PlatformTrans...PlatformTransactionManager 用于执行具体的事务操作。
接口定义如清单2所示:清单2. PlatformTransactionManager 接口中定义的主要方法Public interface PlatformTransactionManager{?TransactionStatus getTransaction(TransactionDefinition definition) ? throws TransactionException;? void commit(TransactionStatus status)throws TransactionException;? void rollback(TransactionStatus status)throwsTransactionException;}根据底层所使用的不同的持久化API 或框架,PlatformTransactionManager 的主要实现类大致如下:•DataSourceTransactionManager:适用于使用JDBC和iBatis进行数据持久化操作的情况。
••HibernateTransactionManager:适用于使用Hibernate进行数据持久化操作的情况。
••JpaTransactionManager:适用于使用JPA进行数据持久化操作的情况。
••另外还有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等。
如果我们使用JTA进行事务管理,我们可以通过JNDI 和Spring 的JtaTransactionManager 来获取一个容器管理的DataSource。
JtaTransactionManager 不需要知道DataSource 和其他特定的资源,因为它将使用容器提供的全局事务管理。
而对于其他事务管理器,比如DataSourceTransactionManager,在定义时需要提供底层的数据源作为其属性,也就是DataSource。
与HibernateTransactionManager 对应的是SessionFactory,与JpaTransactionManager 对应的是EntityManagerFactory 等等。
TransactionStatus(…) 方法返回一个TransactionStatus 对象。
返回的TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。
TransactionStatus 接口提供了一个简单的控制事务执行和查询事务状态的方法。
该接口定义如清单3所示:清单3. TransactionStatus 接口中定义的主要方法public ?interface TransactionStatus{? boolean isNewTransaction();? void setRollbackOnly();? boolean isRollbackOnly();}编程式事务管理Spring 的编程式事务管理概述在Spring 出现以前,编程式事务管理对基于POJO 的应用来说是唯一选择。
用过Hibernate 的人都知道,我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。