Spring 声明式事务

事务的特性/概念

事务:一组操作要么都成功要么失败;

事务的四个关键属性(ACID):

  • 原子性(atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。
  • 一致性(consistency):“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚。
  • 隔离性(isolation):在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。隔离性原则要求多个事务在并发执行过程中不会互相干扰。
  • 持久性(durability):持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。

jar包

c3p0-0.9.1.2.jar

com.springsource.net.sf.cglib-2.2.0.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

commons-logging-1.1.3.jar

mysql-connector-java-5.1.7-bin.jar

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

spring-beans-4.0.0.RELEASE.jar

spring-context-4.0.0.RELEASE.jar

spring-core-4.0.0.RELEASE.jar

spring-expression-4.0.0.RELEASE.jar

spring-jdbc-4.0.0.RELEASE.jar

spring-orm-4.0.0.RELEASE.jar

spring-tx-4.0.0.RELEASE.jar

基本配置:

<!--1、配置连接池  -->
    <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
    </bean>
<!--2、数据库的增删改查   JdbcTemplate  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
<!--配置事务切面;控制住连接池  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>

<!--开启基于注解的事务功能;依赖tx名称空间
    transaction-manager:指定事务管理器是哪个
    -->
    <tx:annotation-driven/>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * [1]根据isbn的值查询书的价格,
    public int getPrice(String isbn);
[2]根据isbn的值减少书的库存,假设每次都只买1本书,
    public void updateStock(String isbn);
[3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
    public void updateBalance(int price,String user);
 * @author lfy
 *
 */
@Repository
public class BookDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    /**
     * [1]根据isbn的值查询书的价格,
     * public int getPrice(String isbn);
     * 操作:book
     */
    public int getPrice(String isbn){
        String sql = "select price from book where isbn=?";
        Integer price = jdbcTemplate.queryForObject(sql, Integer.class, isbn);
        return price;
    };

    /**
     * [2]根据isbn的值减少书的库存,假设每次都只买1本书,
     * public void updateStock(String isbn);
     * 操作:book_stock
     */
    public void updateStock(String isbn){
        String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";
        jdbcTemplate.update(sql, isbn);
    }

    /**
     * [3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
     * public void updateBalance(int price,String user);
     * 给用户减余额;account
     * String user:要减余额的用户名
     * int price:要减掉多少(减少的额度就是书的价格)
     */
    public void updateBalance(int price,String user){
        String sql = "update account set balance = balance-? where username=?";
        jdbcTemplate.update(sql, price,user);

    }

    public void updatePrice(String isbn){
        String sql = "update book set price = 999 WHERE isbn=?";
        jdbcTemplate.update(sql, isbn);
    }
}

事务注解主要添加在Service层,通过Aop来实现事务操作:

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.atguigu.dao.BookDao;

@Service
public class BookService {

    @Autowired
    BookDao bookDao;

    @Transactional(noRollbackFor=ArithmeticException.class,
            timeout=3,propagation=Propagation.REQUIRES_NEW)
    public void checkout(String username,String isbn){
        //0、查出图书价格
        int price = bookDao.getPrice(isbn);
        //1、减用户余额
        bookDao.updateBalance(price, username);
        //2、减图书的库存
        bookDao.updateStock(isbn);

        //Thread.sleep(3000);
        //new FileInputStream("D://ahahahah//aa.txt");
        System.out.println("结账完成....");
    }

    @Transactional(propagation=Propagation.REQUIRED,timeout=3)
    public void updatePrice(String isbn){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bookDao.updatePrice(isbn);
    }

}

Spring事务管理器

事务控制的属性:

propagation:事务的传播行为;我们可以通过控制指定大事务和小事务的关系;

传播(共用一个事务的情况下大事务的属性配置会传播给小事务)+行为(是否共用一个事务)。

isolation:事务的隔离级别,隔离各个事务的;

isolation=Isolation.READ_UNCOMMITTED;

根据实际的业务逻辑;

不适用事务的话会出现可能会出现如下问题:

  1. 脏读:同一事务期间,数据还没提交就给回滚了。
  2. 不可重复读:同一事务期间,多次读取数据内容不一样。
  3. 幻读:同一事务期间,多次读取数据,发现记录变少或者变多了。

本质上一个再读,一个在改;

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

读未提交:READ UNCOMMITTED

允许Transaction01读取Transaction02未提交的修改。

读已提交:READ COMMITTED

要求Transaction01只能读取Transaction02已提交的修改。

可重复读:REPEATABLE READ

确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。

串行化:SERIALIZABLE

确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

⑤各个隔离级别解决并发问题的能力见下表

⑥各种数据库产品对事务隔离级别的支持程度

在Spring中指定事务隔离级别

注解

用@Transactional注解声明式地管理事务时可以在@Transactional的isolation属性中设置隔离级别

XML

在Spring 2.x事务通知中,可以在<tx:method>元素中指定隔离级别

触发事务回滚的异常

默认情况

捕获到RuntimeException或Error时回滚,而捕获到编译时异常不回滚。

设置途经

注解

@Transactional 注解

  1. rollbackFor属性:指定遇到时必须进行回滚的异常类型,可以为多个
  2. noRollbackFor属性:指定遇到时不回滚的异常类型,可以为多个

XML

在Spring 2.x事务通知中,可以在<tx:method>元素中指定回滚规则。如果有不止一种异常则用逗号分隔。

事务的超时和只读属性

简介

由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。

如果一个事物只读取数据但不做修改,数据库引擎可以对这个事务进行优化。

超时事务属性:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。

只读事务属性: 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务。

设置

注解

@Transaction注解

XML

在Spring 2.x事务通知中,超时和只读属性可以在<tx:method>元素中进行指定

举个比较完整的xml配置:

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:component-scan base-package="com.atguigu"></context:component-scan>

    <!--1、配置连接池  -->
    <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
    </bean>

    <!--2、数据库的增删改查   JdbcTemplate  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>

    <!--3、配置事务切面;控制住连接池  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>

    <!--4、开启基于注解的事务功能;依赖tx名称空间
    transaction-manager:指定事务管理器是哪个
    -->
    <!-- <tx:annotation-driven/> -->

    <!--基于xml的事务配置;需要aop和tx名称空间  -->
    <!-- transactionManager事务切面 -->
    <aop:config>
        <!--指定事务管理器要切入哪些方法进行事务控制  -->
        <aop:pointcut expression="execution(* com.soyoungboy.service.*.*(..))" id="txPoint"/>
        <!-- aop:advisor:建议;  pointcut-ref:使用指定的切入点表达式切入事务 -->
        <aop:advisor advice-ref="myTxAdvice" pointcut-ref="txPoint"/>
    </aop:config>

    <!-- 使用tx名称空间和配置(事务建议、事务属性、事务增强);事务方法怎么执行
        id="myTxAdvice":随便起,别人要引用<aop:advisor advice-ref="myTxAdvice"
        transaction-manager="transactionManager":指定配置哪个事务管理器
     -->
    <tx:advice id="myTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 指定事务方法:代表所有方法是事务方法 -->
            <tx:method name="*"/>
            <tx:method name="checkout" rollback-for="java.lang.Exception"/>
            <tx:method name="updatePrice" propagation="REQUIRES_NEW"/>
            <!--以get开头的,通过只读来进行优化-->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- 基于xml配置的事务控制更多一点 -->

</beans>
时间: 2024-10-15 15:57:05

Spring 声明式事务的相关文章

spring声明式事务配置详解

spring声明式事务配置详解 君子不器 2013年06月16日 编程世界 5273次阅读 查看评论 理解Spring的声明式事务管理实现 本节的目的是消除与使用声明式事务管理有关的神秘性.简单点儿总是好的,这份参考文档只是告诉你给你的类加上@Transactional注解,在配置文件中添加('<tx:annotation-driven/>')行,然后期望你理解整个过程是怎么工作的.此节讲述Spring的声明式事务管理内部的工作机制,以帮助你在面对事务相关的问题时不至于误入迷途,回朔到上游平静

Spring声明式事务管理(基于注解方式实现)

----------------------siwuxie095 Spring 声明式事务管理(基于注解方式实现) 以转账为例 1.导入相关 jar 包(共 10 个包) (1)导入核心 jar 包和日志相关的 jar 包 (2)导入 JdbcTemplate 的 jar 包 (3)导入 MySQL 的 JDBC 驱动包 mysql-connector-java 下载链接: https://dev.mysql.com/downloads/connector/j/ (4)导入 AOP 的 jar

spring 声明式事务管理

简单理解事务: 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元:如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元.所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的. 当这两个步骤提交了,执行完毕

JavaEE学习之Spring声明式事务

一.引言 上一篇文章,学习了AOP相关知识,并做了一个简单的Hello world.本文在上篇文章的基础上,进一步学习下Spring的声明式事务. 二.相关概念 1. 事务(Transaction)——它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位 2. 事务的几大特性(A.C.I.D): A——Atomicity(原子性).数据库中的事务执行是作为原子.即不可再分,整个语句要么执行,要么不执行. C——Consistency(一致性).在事务开始之前和事务结束以

Spring声明式事务管理与配置详解

转载:http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html 1.Spring声明式事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之前对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. 总结如下: Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionMa

spring 声明式事务管理注解方式实现

使用注解实现Spring的声明式事务管理,更加简单! 步骤: 1) 必须引入Aop相关的jar文件 2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类 3)在需要添加事务控制的地方,写上: @Transactional @Transactional注解: 1)应用事务的注解 2)定义到方法上: 当前方法应用spring的声明式事务 3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理; 4)定义到父类上: 当执行父类的方法时候应用事务. 案例: 1.

spring声明式事务以及配置

使用spring提供的事务处理机制的好处是程序员可以不用关心事务的切面了,只要配置就好了,可以少写代码. spring声明式事务处理 spring 声明:针对的是程序员,程序员告诉spring容器,哪些方法需要事务,哪些方法不需要事务 事务处理   spring容器来做事务处理 目的:让spring管理事务,开发者不再关注事务 spring声明式事务处理的步骤: 1.搭建环境 2.把dao层和service层的接口和类写完 3.在spring的配置文件中,先导入dataSource 4.测试 5

Spring 声明式事务,propagation属性列表及isolation(隔离级别)

Spring 声明式事务,propagation属性列表 TransactionDefinition接口中定义,共有7种选项可用: PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择.PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行.PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,

Spring声明式事务配置管理方法

环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add librarys: 打开Add Libraries对话框,然后选定 MyEclipse Libraries: 点击Next,找到Spring 2.0 aop Libraries并勾选上,点击finsh即可. 如果在项目里面能看到下面的库文件,说明已经安装成功. 事务配置 首先在/WEB-INF/applica

Spring声明式事务的配置~~~

/*2011年8月28日 10:03:30 by Rush  */ 环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add librarys: 打开Add Libraries对话框,然后选定 MyEclipse Libraries: 点击Next,找到Spring 2.0 aop Libraries并勾选上,点击finsh即可. 如果在项目里面能看到下面的库文件,