spring入门三【事务控制】

在开发中需要操作数据库,进行增、删、改操作的过程中属于一次操作,如果在一个业务中需要更新多张表,那么任意一张表的更新失败,整个业务的更新就是失败,这时那些更新成功的表必须回滚,否则业务会出错,这时就要用到事务,即这个业务的操作属于一个事务,事务具有原子性、隔离性、一致性、持续性。这时便用到了事务,事务控制的目的是保证一组操作要么全部成功,要么全部失败。spring提供了对事务的支持,在spring中主要有两种方式使用事务,一、编程式事务控制;二、声明式事务控制。

一、编程式事务控制

所谓编程式事务控制即通过编写代码的方式实现事务的控制。

spring为了方便处理事务,提供了事务管理器,对事务的控制归根到底是通过事务管理器进行控制,在spring中所有的事务控制必须要有事务管理器。下面是一个编程式事务控制的例子,实现账户之间的转账,我们把对事务的控制放在系统的service层(分为controller层、service层、DAO层)来处理,下面是我的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:aop="http://www.springframework.org/schema/aop"
	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-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
	
	>
	<!--spring 自动检测-->
	
	<context:component-scan base-package="com.cn.study.day5" />
	<!---->
	<context:property-placeholder location="classpath:db.properties"/>
	<!---->

     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>${db.driver}</value>
		</property>
		<property name="url">
			<value>${db.url}</value>
		</property>
		<property name="username">
			<value>${db.username}</value>
		</property>
		<property name="password">
			<value>123456</value>
		</property>
	</bean>	
	
		<bean id="dao" class="com.cn.study.day5.service.inter.impl.AccountDaoImpl">
		
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!--配置事务管理器-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
		
	</bean>
	<!--事务管理器模板 方便使用事务-->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager"></property>
	</bean>

</beans>

  配置了事务管理器,这里使用DataSourceTransactionManager,事务管理器有一个dataSource属性必须配置,这里使用ref属性引用上边的。有了事务管理器之后要使用事务还是比较麻烦,spring又提供了事务管理器模板,我们配置事务管理器模板,事务管理器模板需要一个事务管理器属性,我们引用上边的事务管理器。至此关于编程式的事务控制的配置文件已经准备完毕,下面进行编程式开发。由于,我们把事务控制放在service层,下面是我的service层的代码,

package com.cn.study.day5.service.inter.impl;

import org.springframework.beans.factory.annotation.Autowired;
 org.springframework.stereotype.Component;
 org.springframework.transaction.TransactionStatus;
 org.springframework.transaction.support.TransactionCallback;
 org.springframework.transaction.support.TransactionCallbackWithoutResult;
 org.springframework.transaction.support.TransactionTemplate;

 com.cn.study.day5.service.inter.AccountDaoInter;
 com.cn.study.day5.service.inter.AccountServiceIter;

@Component
public class AccountServiceImpl implements AccountServiceIter {
    @Autowired
    private AccountDaoInter adi;
    @Autowired
     TransactionTemplate tt;
    //转账方法,由out向in转money元
    @Override
    void transfer(final String out,final String in,1)">final double money) {
         TODO Auto-generated method stub

        使用事务管理器模板进行事务控制
        tt.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                 TODO Auto-generated method stub
                adi.outMoney(out,money);
                一个异常,使用了事务控制,在出现了异常之后,事务会回滚
                int i = 1 / 0;
                adi.inMoney(in,money);
            }
        });

    }

}

由于是面向接口编程,这里我只贴出了service层的实现,使用了自动扫描机制(扫描类、属性上的注解@Component、@Autowired),transfer方法是实现转账的方法,首先从一个账户转出,然后转入另一个账户,使用事务管理器模板的execute方法,需要一个TransactionCallBack的实例,这里使用匿名内部类的方式,把要执行的方法放在doInTransactionWithoutResult中执行,保证了事务的控制。

使用这种方式可以保证事务控制,但是在实际开发过程当中这种方式对代码的改动太大,不符合低侵入开发原则,所有这种方式在开发中几乎很少用到,用的最多的是声明式的事务控制。

 

二、声明式事务控制

声明式事务控制又分为三种方式,一、基于TransactionProxyFactoryBean代理的声明式事务控制;二、使用AOP的声明式事务控制;三、基于@Transactional注解的声明式事务控制。

1、基于TransactionProxyFactoryBean的声明式事务控制

TransactionProxyFactoryBean是事务的代理类,spring会为目标类生成一个代理,具体的配置如下,

<!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置业务层代理-->
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="target" ref="accountServiceImpl"></property>
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="transactionAttributes">
            <props>
                <prop key="transfer"></prop>
            </props>
        </property>
    </bean>

这里只贴出了事务管理器和业务层代理的配置,剩余的数据源和业务类的配置可以执行配置,前面说到无论使用哪种方式配置事务管理,都需要使用事务管理器。重点看业务层代理,配置的class属性为TransactionProxyFactoryBean,需要配置三个属性:target(要代理的具体业务层实现类)、transactionManager(事务管理器)、transactionAttributes(要拦截的业务层方法)。配置完成之后,便可以进行测试,测试代码如下,

ApplicationContext ac=getApplicationContext();
        AccountServiceIter asi=(AccountServiceIter)ac.getBean("accountServiceProxy");
        asi.transfer("aa","cc",10d);

通过getApplicationContext()方法获得了ApplicationContext实例,然后获得accountServiceProxy的实例,这里获得的不是AccountServiceImpl的实例而是代理的实例对象,因为使用代理,代理了实际的业务类,所有这里不能再使用实际的类而应是代理类。

使用这种方式的需要为每一个需要使用事务的业务类配置一个代理比教麻烦,所以在开发过程中这种方式几乎不用。

2、使用AOP的声明式事务控制

这种方式是在开发过程中使用的比较多的一种,配置如下,

<!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置事务增强-->
    <tx:advice id="advicer" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transfer*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置切点、事务通知-->
    <aop:config>
        <aop:pointcut id="myPointcut" expression="execution(* com.cn.study.day555.service.inter.impl.*.*(..))"/>
        <aop:advisor advice-ref="advicer" pointcut-ref="myPointcut"/>
    </aop:config>

配置了事务增强<tx:advice>配置对要增强的方法的事务的传播行为等,配置<aop:config>配置切点和对应的事务通知,这样就完成了AOP的声明式事务控制。

3、基于@Transactional注解

使用@Transactional注解需要再配置文件中开启对这个注解的扫描:<tx:annotation-driven transaction-manager="transactionManager" />,引用了事务管理器,然后就可以使用@Transactional注解,此注解可以使用在类上,也可以使用在方法上,使用在类上即对此类的所有方法都起作用,使用在方法上则表示对单个方法起作用,还可以配置一些属性,放在另一篇文章中进行解释。

通过对以上四种配置事务的方式的描述,其中声明式方式中的第二种方式使用比较普通,对代码的侵入比较小,第三种因为配置简单,也比较常用,但是需要在业务类或方法上加@Transcational注解,对代码有一定的侵入。

有不正之处欢迎指出,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下