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;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

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

@Component
public class AccountServiceImpl implements AccountServiceIter {
    @Autowired
    private AccountDaoInter adi;
    @Autowired
    private TransactionTemplate tt;
    //转账方法,由out向in转money元
    @Override
    public void transfer(final String out, final String in, 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注解,对代码有一定的侵入。

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

时间: 2024-10-10 10:18:01

spring入门(三)【事务控制】的相关文章

Spring MVC一事务控制问题

在最近一个项目中用了Spring MVC作为控制层框架,但却出现了一个让人很费解的问题:事务控制. Spring MVC的配置文件名为:springMVC-servlet.xml,内容如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http:/

阶段3 2.Spring_10.Spring中事务控制_9 spring编程式事务控制1-了解

编程式的事物控制,使用的情况非常少,主要作为了解 新建项目 首先导入包坐标 复制代码 这里默认值配置了Service.dao和连接池其他的内容都没有配置 也就说现在是没有事物支持的.运行测试文件 有错误,但是金额还是被减去了 编码的方式加事务控制 事务控制都离不开提交和回滚这两个操作.在spring里面它吧提交和回滚的方法提交到事务管理器里面了. 于是我们无论如何都需要在bean.xml里面配置事务管理器 接下来要进行事务控制,那肯定需要提交和回滚的操作 spring提交了一个对象,叫做事务模板

spring aop实现事务控制

首先导入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.

spring入门(三) 使用spring mvc

1.建立project / module 新建空的project:springMvcStudy 新建module:type maven-webapp,名字mvcStudy 2.为module设置Sources和Resources 在mvcStudy/src/main下新建2个文件夹:java,resources.打开File/Project Structure/Project Settings/Modules 选择mvcStudy,点击Sources选项卡设置java文件夹为Sources,设置

Spring学习8-Spring事务管理(编程式事务管理)

一.Spring事务的相关知识   1.事务是指一系列独立的操作,但在概念上具有原子性. 比如转账:A账号-100, B账号+100,完成.这两个操作独立是没问题的. 但在逻辑上,要么全部完成,要么一起失败.    1)jdbc事务:每个Connection都带有一个事务,只是默认被设置为自动提交.一个连接可以有多个事务.对于JDBC,只有在同一个连接内,才有讨论是否提交的前提. 2)Hibernate事务:本质上也是使用JDBC来处理事务.但是不是直接操作,而是使用Session来操作事务.S

Java实战之03Spring-05Spring中的事务控制(基于AOP)

五.Spring中的事务控制(基于AOP) 1.Spring中事务有关的接口 1.1.明确: JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案 1.2.Spring事务管理主要包括3个接口 1.2.1.PlatformTransactionManager事务管理器 具体实现类: 1.2.2.TransactionDefinition事务定义信息 事务的隔离级别: 事务的传播行为:有时面试会问到 REQUIRED:如果当前没有事务,就新建一个事务

Spring入门(四):使用Maven管理Spring项目

让我们先回顾下本系列的前3篇博客: Spring入门(一):创建Spring项目 Spring入门(二):自动化装配bean Spring入门(三):通过JavaConfig装配bean 1.为什么要使用Maven? 之前我们新建的项目,项目所要依赖的第三方jar包都在项目的类路径下(通常为lib目录),如下所示: 使用这种方式,我们无法知道第三方类库的依赖关系,比如导入一个特定的jar包时,可能此jar包还依赖于其他的jar包,其他的jar包又依赖于更多的jar包,这也是我们平常遇到的Clas

Spring入门(三)— AOP注解、jdbc模板、事务

一.AOP注解开发 导入jar包 aop联盟包. aspectJ实现包 . spring-aop-xxx.jar . spring-aspect-xxx.jar 导入约束 aop约束 托管扩展类和被扩展类 <!-- 要做AOP, 一定要托管扩展类和被扩展类 --> <bean id="us" class="com.pri.service.impl.UserServiceImpl"></bean> <bean id="

spring的事务控制

1.事务介绍 (1)特性:ACID Atomicity(原子性):事务中的所有操作要么全做要么全不做 Consistency(一致性):事务执行的结果使得数据库从一个一致性状态转移到另一个一致性状态 Isolation(隔离性):一个事务的执行不受其他事务的干扰 Durability(永久性):一个事务一旦提交,对数据库的影响是永久性的 (2)事务并发问题 (3)       隔离级别 2.  Spring封装了事务管理操作 1.事务操作 打开事务  回滚事务   提交事务 2.事务操作对象 因