从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

    • Spring介绍
    • 程序中的耦合
    • IoC的概念和作用
    • Spring中的依赖注入
    • 基于注解的IoC
    • 使用基于XML的IoC完成单表的CRUD
    • 使用基于注解的IoC完成单表的CRUD
    • IoC的纯注解配置
    • Spring整合Junit
    • 事务问题
    • 代理模式
    • AOP的概念和入门
    • 基于注解的AOP
    • Spring的JdbcTemplate
    • JdBCDaoSupport
    • 基于XML的AOP实现事务控制
    • 基于注解的AOP实现事务控制
    • Spring的事务控制
      • 问题分析
      • 相关概念
      • 相关API
      • 环境准备
      • 源码
    • 基于XML的声明式事务控制
    • 基于注解的声明式事务控制
    • 纯注解实现事务控制
    • Spring编程式事务控制
    • Spring5新特性
    • Java
  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • Java
  • Spring
2023-05-08
目录

Spring的事务控制

# 140.Spring的事务控制

之前我们是自己实现了事务控制,其实Spring本身也有事务控制,我们可以直接拿来用   ‍

# 问题分析

在上一篇博客中,其实有一些代码是多余的:

  1. 释放连接的代码,我们可以在提交或回滚后直接释放链接
  2. 开启连接的代码,我们可以在获取connection的时候,直接开启事务

‍

因此我们剩下了添加事务和回滚事务的代码,这两个写法也是固定的,等我们后续学了Spring的事务控制之后,这也可以省略

‍

# 相关概念

JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计业务层的事务处理解决方案。

Spring 框架为我们提供了一组事务控制的接口,具体在后面介绍,这组接口在spring-tx-5.0.2.RELEASE.jar 中

Spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。

‍

我们可以在pom.xml中添加一个依赖

 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
1
2
3
4
5

‍

‍

# 相关API

‍

# PlatformTransactionManager

我们导入jar包后,可以在代码中定义一个PlatformTransactionManager:

PlatformTransactionManager ptm;
1

‍

我们可以看其源码:可以看到这是一个接口,有commit和rollback方法

package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface PlatformTransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;
}
1
2
3
4
5
6
7

‍

该接口实现类有:

  • org.springframework.jdbc.datasource.DataSourceTransactionManager 使用 Spring JDBC 或 iBatis 进行持久化数据时使用
  • org.springframework.orm.hibernate5.HibernateTransactionManager 使用 Hibernate 版本进行持久化数据时使用

‍

# TransactionDefinition

它是事务的定义信息对象,里面有如下方法:

  • ​String getName() ​​:获取事务对象名称
  • ​int getlsolationLevel()​ :获取事务隔离级别,默认使用的是数据库的级别
  • ​int getPropagationBehavior()​:获取事务传播行为,例如什么时候使用事务,什么时候不使用
  • ​int getTimeout()​:获取事务超时时间
  • ​boolean isReadonly()​:获取事务是否只读

‍

‍

事务隔离级反映事务提交并发访问时的处理态度

  • ISOLATION_DEFAULT:默认级别,归属下列某一种
  • ISOLATION_READ_UNCOMMITTED:可以读取未提交数据
  • ISOLATION_READ_COMMITTED:只能读取已提交数据,解决脏读问题(Oracle默认级别)
  • ISOLATION_REPEATABLE_READ:是否读取其他事务提交修改后的数据,解决不可重复读
    问题(MySQL默认级别)
  • ISOLATION:是否读取其他事务提交添加后的数据,解决幻影读问题

‍

事务的传播行为

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。默认值
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。

重点关注前两个,第一个是增删改时用的,第二个是查询时用的

‍

超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置。

是否是只读事务:建议查询时设置为只读。

‍

‍

# TransactionStatus

TransactionStatus接口描述了某个时间点上事务对象的状态信息,包含有6个具体的操作

  • ​void flush()​:刷新事务
  • ​boolean hasSavepoint()​:获取是否是否存在存储点,事务是按步提交的,我们可以自己设置存储点,回滚时就会回滚到这个存储点,在一些大型的复杂的事务面前,需要用到这个
  • ​boolean isCompleted()​:获取事务是否完成
  • ​boolean isNewTransaction()​:获取事务是否为新的事务
  • ​boolean isRollbackOnly()​:获取事务是否回滚
  • ​void setRollbackOnly()​:设置事务回滚

‍

‍

# 环境准备

我们这次从项目的demo14分支上进行开发,并删减相关代码:

  1. 自己实现的JdbcDaoSupport.java类
  2. jdbctemplate包

‍

‍

# 配置依赖

我们调整依赖关系如下:

<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.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.peterjxl</groupId>
    <artifactId>LearnSpring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>LearnSpring</name>

    <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>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
            <scope>test</scope>
        </dependency>
      
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

‍

‍

# 新增service接口和实现类

package com.peterjxl;
import com.peterjxl.domain.Account;

public interface IAccountService {
    Account findAccountById(Integer accountId);
    void transfer(String sourceName, String targetName, Float money);
}
1
2
3
4
5
6
7

‍

package com.peterjxl.service.impl;

import com.peterjxl.dao.IAccountDao;
import com.peterjxl.domain.Account;
import com.peterjxl.service.IAccountService;

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }
    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    @Override
    public void transfer(String sourceName, String targetName, Float money) {
        Account source = accountDao.findAccountByName(sourceName);
        Account target = accountDao.findAccountByName(targetName);
        source.setMoney(source.getMoney() - money);
        target.setMoney(target.getMoney() + money);
        accountDao.updateAccount(source);
        accountDao.updateAccount(target);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

‍

‍

# 配置bean

<bean id="accountService" class="com.peterjxl.service.impl.AccountServiceImpl">
    <!-- 注入AccountDao -->
    <property name="accountDao" ref="accountDao"/>
</bean>
1
2
3
4

‍

# 新增测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

    @Autowired
    private IAccountService as;

    @Test
    public void testTransfer(){
        as.transfer("aaa","bbb",100f);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

‍

如果有异常,是不能控制住事务的,接下来的博客我们就演示如何配置。

‍

‍

# 源码

本项目已将源码上传到GitHub (opens new window)和Gitee (opens new window)上。并且创建了分支demo17,读者可以通过切换分支来查看本文的示例代码

在GitHub上编辑此页 (opens new window)
上次更新: 2023/5/11 14:10:59
基于注解的AOP实现事务控制
基于XML的声明式事务控制

← 基于注解的AOP实现事务控制 基于XML的声明式事务控制→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式