Spring中的事务控制知识总结

一、环境准备

为了演示 Spring 中的事务控制,我们创建一个空项目,项目目录如下:

导入依赖:

<dependencies>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>5.0.2.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-jdbc</artifactId>
	    <version>5.0.2.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-tx</artifactId>
	    <version>5.0.2.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>5.1.6</version>
	</dependency>
	<dependency>
	    <groupId>org.aspectj</groupId>
	    <artifactId>aspectjweaver</artifactId>
	    <version>1.8.7</version>
	</dependency>
	<dependency>
	    <groupId>junit</groupId>
	    <artifactId>junit</artifactId>
	    <version>4.12</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-test</artifactId>
	    <version>5.0.2.RELEASE</version>
	</dependency>
</dependencies>

业务层及其实现类:

/**
 * 账户的业务层接口
 */
public interface IAccountService {

    void transfer(String sourceName, String targetName, Float money);
}
/**
 * 转账的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    /**
     * 转账
     * @param sourceName    转出账户名称
     * @param targetName    转入账户名称
     * @param money         转账金额
     */
    public void transfer(String sourceName, String targetName, Float money) {
            //1. 根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);//  1. 第一次事务,提交
            //2. 根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);//  2. 第二次事务提交
            //3. 转出账户减钱
            source.setMoney(source.getMoney()-money);
            //4. 转入账户加钱
            target.setMoney(target.getMoney()+money);
            //5. 更新转出账户
            accountDao.updateAccount(source);  //  3. 第三次事务提交
            int i = 1/0;  					   //  4. 报异常
            //6. 更新转入账户
            accountDao.updateAccount(target);  //  5. 事务不执行
    }
}

账户持久层及其接口:

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 根据Id查询账户
     * @param accountId
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 根据名称查询账户
     * @param accountName
     * @return
     */
    Account findAccountByName(String accountName);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);
}
/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

    public Account findAccountById(Integer accountId) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    public Account findAccountByName(String accountName) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
        if(accounts.isEmpty()){
            return null;
        }
        if(accounts.size()>1){
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    public void updateAccount(Account account) {
        super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
    }
}

这里配置的是 Spring 内置数据源,当然也可以应用 JdbcTemplate。

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

    <!--配置业务层-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/springdb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="000000"></property>
    </bean>

</beans>

二、基于 XML 的事务控制

Spring 中基于 xml 的声明式事务控制配置步骤

1.配置事务管理器

<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"></bean>

2.配置事务的通知 (需要导入事务的约束 tx 和 aop 的名称空间和约束)
使用 tx:advice 标签配置事务通知

属性:

id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用

<!--配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager"></tx:advice>

3.配置AOP的通用切入点表达式

<!--配置AOP的通用切入点表达式-->
<aop:config>
	<aop:pointcut id="pt1" expression="execution(* com.itheima.service.*.*(..))"></aop:pointcut>
</aop:config>

4.建立事务通知 与 切入点表达式的对应关系

<!--配置AOP的通用切入点表达式-->
<aop:config>
	<aop:pointcut id="pt1" expression="execution(* com.itheima.service.*.*(..))"></aop:pointcut>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>

5.配置事务的属性

在事务的通知 tx:advice 标签的内部

  • isolation: 用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
  • propagation: 用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORT。
  • read-only: 用于指定事务是否只读。只有查询方法才能设置为true。默认值时false,表示读写。
  • timeout: 用于指定事务的超时时间。默认值是-1,表示永不超时。如果指定了数值,则以秒为单位。
  • rollback-for: 用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常,事务不回滚。没有默认值。表示任何异常都回滚。
  • no-rollback-for: 用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值。表示任何异常都回滚。
<!--配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
        <tx:method name="find*" propagation="REQUIRED" read-only="false"></tx:method> <!--优先级高于通配符 * -->
    </tx:attributes>
</tx:advice>

最终 bean.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--配置业务层-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置账户的持久层-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/springdb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="000000"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
            <tx:method name="find*" propagation="REQUIRED" read-only="false"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!--配置AOP的通用切入点表达式-->
    <aop:config>
        <aop:pointcut id="pt1" expression="execution(* com.itheima.service.*.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
    </aop:config>

</beans>

测试结果:

三、基于注解的事务控制

Spring 中基于 xml 的声明式事务控制配置步骤

1.配置事务管理器

2.开启 Spring 对注解事物的支持

3.在需要事务支持的地方使用 @Transactional 注解

bean.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: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.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置容器时要扫描的包-->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/springdb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="000000"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启spring对注解事物的支持-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

</beans>

账户业务层实现类:

/**
 * 转账的业务层实现类
 */
@Service("accountService")
@Transactional
public class AccountServiceImpl implements IAccountService {
	......
}

账户持久层实现类:

/**
 * 账户的持久层实现类
 */
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

	......
}

测试结果如下:

到此这篇关于Spring中的事务控制知识总结的文章就介绍到这了,更多相关Spring事务控制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring源码解析之编程式事务

    一.前言 在Spring中,事务有两种实现方式: 编程式事务管理: 编程式事务管理使用TransactionTemplate可实现更细粒度的事务控制.声明式事务管理: 基于Spring AOP实现.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务. 声明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单(尤其是配合spring boot自动配置,可以说是精简至极!),且大部分业务都可

  • Spring源码解析之事务传播特性

    一.使用方式 可以采用Transactional,配置propagation即可. 打开org.springframework.transaction.annotation.Transactional可见默认传播特性是REQUIRED. /** * The transaction propagation type. * <p>Defaults to {@link Propagation#REQUIRED}. * @see org.springframework.transaction.inte

  • Spring的编程式事务和声明式事务详解

    入口(了解一些基本概念) Spring事务属性(事务的属性有哪些?) 我们都知道事务有开始,保存点,提交,回滚,隔离级别等属性.那么Spring对于事务属性定义有哪些呢?通过TransactionDefinition接口我们可以了解到: public interface TransactionDefinition{ int getIsolationLevel(); int getPropagationBehavior(); int getTimeout(); boolean isReadOnly

  • 带大家深入了解Spring事务

    一.数据库事务简介 构成单一逻辑工作单元的操作集合称作事务(transaction).即使有故障,数据库系统也必须保证事务的正确执行--要么执行整个事务,要么属于该事务的操作一个也不执行.以资金转账为例,应该保证支票账户支出金额的操作和储蓄账户的存入金额的操作在同一个逻辑工作单元内完成.简言之,事务是访问并可能更新各种数据项的一个程序执行单元(unit). 二.事务的特性 数据库需要维护事务的以下四个性质: 1.原子性(Atomicity)事务是一个原子操作,由一系列动作组成.事务的原子性确保这

  • Spring编程式和声明式事务实例讲解小结

    Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理: 通过Transaction Template手动管理事务,实际应用中很少使用, 使用XML配置声明式事务: 推荐使用(代码侵入性最小),实际是通过AOP实现 实现声明式事务的四种方式: 基于 TransactionInterceptor 的声明式事务: Spring 声明式事务的基础,通常也不建议使用这种方式,但是与前面一样,了解这种方式对理解 Spring 声明式事务有很大作用. 基于 TransactionProx

  • 详解Spring学习之编程式事务管理

    前言 在前面的内容,基本已经学习了事务的基本概念以及事务隔离级别等,接下来的几个小节,将学习怎么使用Spring进行事务管理,在Spring中,对事务进行管理有多种方法,主要分别编程式和声明式,本小节主要学习编程式事务管理,后面讲学习Spring的声明式事务管理 编程式事务管理 所谓的编程式事务管理,其实就是通过编写代码的方式来进行事务管理,也就是通过将事务管理的代码硬编码在代码中从而达到事务管理的作用,不过Spring的事务管理不同于JDBC原始的事务管理,在JDBC中,对事务进行管理首先要关

  • Spring中的事务控制知识总结

    一.环境准备 为了演示 Spring 中的事务控制,我们创建一个空项目,项目目录如下: 导入依赖: <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency&g

  • 简单了解Spring中的事务控制

    1.事务的概念 事务是一组操作的执行单元,相对于数据库的单条操作而言,事务管理的是一组SQL指令,如增删改查等,事务的特性体现在事务内包含的SQL指令必须全部执行成功,如果其中一条指令发生错误,那么整个事务内的一组操作都要进行回滚. 事务有四个特性: 原子性 Atomic ,事务是一个不可再拆分的最小单位,要么整个执行,要么整个回滚. 一致性 Consistent,事务要保证数据库整体数据的完整性和业务的数据的一致性,事务成功提交整体数据修改,事务错误则回滚到数据回到原来的状态. 隔离性 Iso

  • Spring中的事务管理实例详解

    本文实例讲述了Spring中的事务管理.分享给大家供大家参考.具体分析如下: 事务简介: 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性 事务就是一系列的动作,它们被当作一个单独的工作单元.这些动作要么全部完成,要么全部不起作用 事务的四个关键属性(ACID) ① 原子性(atomicity):事务室一个原子操作,有一系列动作组成.事务的原子性确保动作要么全部完成,要么完全不起作用 ② 一致性(consistency):一旦所有事务动作完成,事务就被提交.数据和资源就

  • 在Spring中编写事务的介绍

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

  • Spring中的事务操作、注解及XML配置详解

    事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQL 语句: update Acoount set balance = balance - money where id = 'A'; update Acoount set balance = balance + money where id = 'B' 上面这两条 SQL 就可以要看成是一个事务,必

  • Spring中的事务管理如何配置

    这篇文章主要介绍了spring中的事务管理如何配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在springboot中,使用事务非常的简单,因为springboot已经帮我们配置好了,只需要加上注解@Transactional即可 在spring中我们需要做一些配置:主要有三点: @Transactional:在相应的方法上加上这个注解 @EnableTransactionManagement:在配置类中加上,开启事务管理 需要在配置类中加

  • 在Spring 中使用@Aspect 控制自定义注解的操作

    Spring 中使用@Aspect 控制自定义注解 看这篇介绍@Aspect 1.定义系统日志注解类 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SysLog { String value() default ""; } 2.定义切面处理类 package com.kxs.common.aspect; import com.google.gso

  • 浅谈Spring中@Transactional事务回滚及示例(附源码)

    一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除某个部门的时候,假设我们默认删除对应的成员.但是在执行的时候可能会出现这种情况,我们先删除部门,再删除成员,但是部门删除成功了,删除成员的时候出异常了.这时候我们希望如果成员删除失败了,之前删除的部门也取消删除.这种场景就可以使用@Transactional事物回滚. 二.checked异常和unc

  • 基于Spring中的事务@Transactional细节与易错点、幻读

    目录 为什么要使用事务? 如何使用事务? 事务的传播带来的几种结果 两个特例 事务传播属性propagation 数据库隔离级别 1.未提交读(会有脏读的现象) 2.已提交读 3.可重复读 (有可能覆盖掉其他事务的操作) 4.串行化(没有并发操作) Spring事务隔离级别比数据库事务隔离级别多一个default ACID,事务内的一组操作具有 原子性 .一致性.隔离性.持久性. Atomicity(原子性):一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束

  • Spring中的事务传播行为示例详解

    一.背景介绍 Spring 框架应该是每一个人 javaer 都必须接触和学习的技术,Spring 公司所提供的各种框架是 Java 开发行业可参考的重要标准之一. Spring 中有 7 种类型的事务传播行为.事务传播行为是 Spring 框架提供的一种事务管理方式,它是 Spring 框架之中非常重要的一个技术点,毕竟事务关系到应用程序和数据库的交互,而数据更是互联网行业最为重要的资源. 平时开发过程中事务都会有使用,但是没有真正地总结过,尤其是事务中嵌套事务的场景,此篇基础知识文在此做一个

随机推荐