事务管理、事务特性、数据库并发访问问题、事务应用【转账】

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 事务管理、事务特性、数据库并发访问问题、事务应用【转账】

事务管理


1.什么是事务呢?


事务指的是:在一组业务逻辑中,要么全部成功,要么全部失败。


2. 事务的特性又有那些呢?【ACID】


原子性【Atomicity】:在一组事务操作中,要么全都成功,要么全都失败,互相不可分割


一致性【Consistency】: 在事务发生的前后数据的完整性必须保存一致。


隔离性【Isolation】:事务被多个用户并发访问时,多个用户之间的数据要互相隔离


持久性【Durability】:事务一旦提交,对数据的修改将是持久的。


3. 并发访问会出现那些问题?【三种隔离问题】


------ 如果不考虑事务的隔离性,事务会出现并发访问问题


3.1 脏读


---- 含义: 一个事务读到了另一个事务没有提交是事务


详解:举例转账功能 --- 事务A、B各有10元


事务A说 : 给事务B转账2元 ----- 8 元


事务B说:好的我已经收到了 ----- 12元


-------------【可在A、B事务并发访问时,出现了脏读问题,事务B读到了事务A没有提交的事务】


结果:事务A和事务B的金额还是没有进行转账前的各自10元


-------------【脏读:读到了没有提交的事务,事务进行了回滚操作,恢复了原来的数据信息】


图集详解


d71a804c5eb9477eba14c5ae51daa42b.png


3.2 不可重复读

----含义:一个事务读到了另一个事务已经提交的事务【update】,造成在一个事务中多次查询结果不一致


详解:


事务A进行查账100元,事务B从账号取出20元


事务A: 第一次查询到100快,并没有提交事务commit


事务B:从账户上取出20元,并对账户余额进行update修改


----------- 事务A第二次查询,查到了事务B已经提交的数据80元


----------- 两次查询结果不一样,发生并发访问问题,不可重复读


图集详解


37430d16e9a740169e12a8a069455787.png


3.3 虚读/幻读


--- 含义:一个事务读到了另一个事务已经提交的事务【insert】,在事务中多次查询结果不一致。(数据量不同)


详解


事务A进行数据查询功能,事务B进行insert添加功能


事务A: 第一次查询到3条,并没有提交事务commit


事务B:添加了一条数据


---------- 事务A第二次查询查询到了4条数据,查到了事务B已经提交的数据


---------- 两次查询结果不一样,发生并发访问问题,不可重复读


图集详解


b618a0a605e64ba183867f678e8f0993.png


4 那不可重复读【update】和幻读【insert】又有什么区别呢?


不可重复读是基于update修改发生的并发访问问题


幻读是基于insert添加,发生的并发访问问题


5 隔离级别有那些?


------ 为了解决并发访问问题,数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况


1)读未提交【read uncommitted】:一个事务读到了另一个事务没有提交的数据


存放:3个问题【脏读、不可重复读、虚读】


解决:0个问题


------- 效率最高,引发所有读问题,基本不设置


2)读已提交【read committed】: 一个事务读到了另一个事务已经提交的数据


存放:2个问题【不可重复读、虚读】


解决:1个问题【脏读】


------- 如果要效率,那么选择这个 read committed 读已提交


3)可重复读【repeatable read】: 在一个事务中读到的数据信息始终保持一致,无论另一个事务是否提交


存放:1个问题【虚读】


解决:2个问题【脏读、不可重复读】


------- 如果要安全,那么选择这个 repeatable read 可重复读


------ 还剩一个问题未解决,但是虚读的问题可以通过程序来规避


事务刚开启时,可以count(*)


事务要关闭时,可以count(*)


对比:如果两次数据一致,说明没有虚读


4)串行化【serializable】: 同时只能执行一个事务,相当事务中的单线程


存放:0个问题


解决:3个问题【脏读、不可重复读、虚读】


------- 没有效率,但安全性最高,基本不设置


5.1 事务性能和安全性的比较

性能:读未提交 > 读已提交 > 可重复读 > 串行化


安全:串行化 > 可重复读 > 读已提交 > 读未提交


5.2 常见数据库的默认隔离级别

MySql : 可重复读:安全,本身做的优化比较好


Oracle : 读已提交:效率高


6.事务注解关联Spring


相关注解


@EnableTransactionManagement  //书写在SpringConfiguration配置类中

@Transactional  //开启事务 书写在service接口实现类中


7.转账案例,事务应用


7.1图集导航


2cf6921aacdf4003b2ccaf89521ddb4f.png


7.2 代码数据【可参考】


7.2.1 config 配置类


MyBatisConfiguration

package com.czxy.demo17_accountSW.config;
import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
public class MyBatisConfiguration {
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        //1 创建工厂
        // 1.通过工厂bean创建对象,最后需要调用 getObject()获得具体的对象
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        //2 设置数据-- SqlMapConfig.xml 配置信息
        // 1.1 设置数据源
        factoryBean.setDataSource(dataSource);
        // 1.2 设置别名包扫描
        factoryBean.setTypeAliasesPackage("com.czxy.demo17_accountSW.doamin");
        // 1.3 全局配置:驼峰映射
        org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
        config.setMapUnderscoreToCamelCase(true);
        factoryBean.setConfiguration(config);
        // 2 插件配置
        // 2.1 分页插件
        PageHelper pageHelper = new PageHelper();
        Properties pageProps = new Properties();
        pageProps.setProperty("dialect", "mysql");
        pageProps.setProperty("rowBoundsWithCount", "true");
        pageHelper.setProperties(pageProps);
        factoryBean.setPlugins(new Interceptor[] { pageHelper });
        // 返回SqlSessionFactory
        return factoryBean.getObject();
    }
    /**
     * 扫描Dao的包,查找各种XxxMapper接口,创建好UserMapper等对象存入到IOC的容器中
     * @return
     */
    @Bean
    public MapperScannerConfigurer mapperScanner() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.czxy.demo17_accountSW.mapper");
        return configurer;
    }
}

SpringConfiguration

package com.czxy.demo17_accountSW.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@PropertySource("classpath:db2.properties")
@ComponentScan(basePackages = "com.czxy.demo17_accountSW")
@EnableTransactionManagement
public class SpringConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url ;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
    //事务管理器【管理事务,事务出现异常会进行回滚事务】
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

7.2.2 daomain

  • Account
@Table(name = "account")
public class Account {
    @Id
    private Integer id;
    private String name;
    private Float money;
 //注:构造和set/get方法省略
}

7.2.3 mapper

  • AccountMapper
public interface AccountMapper extends Mapper<Account> {
}

7.2.4  service

  • AccountService接口
public interface AccountService {
    /**
     * 转账
     * @param outId  汇款
     * @param inId   收款
     * @param money  金额
     */
    public void change(Integer outId,Integer inId,Float money);
}
  • AccountServiceImpl接口实现类
package com.czxy.demo17_accountSW.service.impl;
import com.czxy.demo17_accountSW.doamin.Account;
import com.czxy.demo17_accountSW.mapper.AccountMapper;
import com.czxy.demo17_accountSW.service.AccountService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
@Transactional  //开启事务
public class AccountServiceImpl implements AccountService {
    @Resource
    private AccountMapper accountMapper;
    //转账 ---》  汇款、收款、金额
    @Override
    /**
     * 转账
     * @param outId  汇款
     * @param inId   收款
     * @param money  金额
     */
    public void change(Integer outId, Integer inId, Float money) {
        //(id查询、修改金额、更新)
        //根据汇款人id进行汇款,返回一个汇款人的对象信息
        Account outAccount = accountMapper.selectByPrimaryKey(outId);
        //进行设置汇款人的剩余金额 = 汇款钱的金额 - 汇款的金额
        outAccount.setMoney(outAccount.getMoney() - money);
        //进行更新设置剩余金额,根据id进行修改保存
        accountMapper.updateByPrimaryKey(outAccount);
        //模拟错误异常,出错了,
        // 但是汇款已经完成,数据已经修改,但收款人这边由于报错没有收到汇款,那怎么办呢?
        // 不用担心事务注解@Transactional 就是为了防止该类事情发生而存在的。
        // 开启事务,当报异常了,停止了业务的进行,那么事务就会执行回滚事务,恢复数据
        int i = 1/0 ;
        //收款人 + 钱
        //根据收款人id,获取收款人对象
        Account inAccount = accountMapper.selectByPrimaryKey(inId);
        //对其收款人金额进行累加 = 原本金额+汇款金额
        inAccount.setMoney(inAccount.getMoney() +money);
        //根据收款人id进行更新保存金额
        accountMapper.updateByPrimaryKey(inAccount);
    }
}

7.2.5 properties 文本

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/day12_02_affair
jdbc.username=root
jdbc.password=1234

7.2.6测试类

package com.czxy.demo17_accountSW;
import com.czxy.demo17_accountSW.config.MyBatisConfiguration;
import com.czxy.demo17_accountSW.config.SpringConfiguration;
import com.czxy.demo17_accountSW.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class, MyBatisConfiguration.class})
public class TestTx {
    @Resource
    private AccountService accountService;
    @Test
    public void testDemo(){
        accountService.change(1,2,300f);
    }
}


  • 测试结果
  • 测试前


f7f2a0e7ae3a47cd9c6c4b0c59b9e34d.png


  • 测试后

0a6542175d1045bb83a0c4d68342e26f.png


8 .当测试时发生异常报错了怎么呢?在我已经汇款之后就出现系统异常,导致收款方没有收到款,怎么办呢?


//模拟错误异常,出错了,
// 但是汇款已经完成,数据已经修改,但收款人这边由于报错没有收到汇款,那怎么办呢?
// 不用担心事务注解@Transactional 就是为了防止该类事情发生而存在的。
// 开启事务,当报异常了,停止了业务的进行,那么事务就会执行回滚事务,恢复数据
//------ 这里已除0异常为例
 int i = 1/0 ;


9.图集总结


fa7c87b2739145ea865e161a6bbd2f53.png


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
29天前
|
SQL Java 数据库连接
除了JDBC,还有哪些常见的数据库访问技术?
除了JDBC,还有哪些常见的数据库访问技术?
206 2
|
1月前
|
存储 人工智能 NoSQL
AI大模型应用实践 八:如何通过RAG数据库实现大模型的私有化定制与优化
RAG技术通过融合外部知识库与大模型,实现知识动态更新与私有化定制,解决大模型知识固化、幻觉及数据安全难题。本文详解RAG原理、数据库选型(向量库、图库、知识图谱、混合架构)及应用场景,助力企业高效构建安全、可解释的智能系统。
|
4月前
|
存储 关系型数据库 数据库
附部署代码|云数据库RDS 全托管 Supabase服务:小白轻松搞定开发AI应用
本文通过一个 Agentic RAG 应用的完整构建流程,展示了如何借助 RDS Supabase 快速搭建具备知识处理与智能决策能力的 AI 应用,展示从数据准备到应用部署的全流程,相较于传统开发模式效率大幅提升。
附部署代码|云数据库RDS 全托管 Supabase服务:小白轻松搞定开发AI应用
|
5月前
|
安全 druid Nacos
0 代码改造实现应用运行时数据库密码无损轮转
本文探讨了敏感数据的安全风险及降低账密泄漏风险的策略。国家颁布的《网络安全二级等保2.0标准》强调了企业数据安全的重要性。文章介绍了Nacos作为配置中心在提升数据库访问安全性方面的应用,并结合阿里云KMS、Druid连接池和Spring Cloud Alibaba社区推出的数据源动态轮转方案。该方案实现了加密配置统一托管、帐密全托管、双层权限管控等功能,将帐密切换时间从数小时优化到一秒,显著提升了安全性和效率。未来,MSE Nacos和KMS将扩展至更多组件如NoSQL、MQ等,提供一站式安全服务,助力AI时代的应用安全。
370 14
|
2月前
|
存储 弹性计算 Cloud Native
云原生数据库的演进与应用实践
随着企业业务扩展,传统数据库难以应对高并发与弹性需求。云原生数据库应运而生,具备计算存储分离、弹性伸缩、高可用等核心特性,广泛应用于电商、金融、物联网等场景。阿里云PolarDB、Lindorm等产品已形成完善生态,助力企业高效处理数据。未来,AI驱动、Serverless与多云兼容将推动其进一步发展。
182 8
|
2月前
|
存储 弹性计算 安全
现有数据库系统中应用加密技术的不同之处
本文介绍了数据库加密技术的种类及其在不同应用场景下的安全防护能力,包括云盘加密、透明数据加密(TDE)和选择列加密。分析了数据库面临的安全威胁,如管理员攻击、网络监听、绕过数据库访问等,并通过能力矩阵对比了各类加密技术的安全防护范围、加密粒度、业务影响及性能损耗。帮助用户根据安全需求、业务改造成本和性能要求,选择合适的加密方案,保障数据存储与传输安全。
|
4月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
3月前
|
存储 人工智能 数据库
视图是什么?为什么要用视图呢?数据库视图:定义、特点与应用
本文三桥君深入探讨数据库视图的概念与应用,从定义特点到实际价值全面解析。视图作为虚拟表具备动态更新、简化查询、数据安全等优势,能实现多角度数据展示并保持数据库重构的灵活性。产品专家三桥君还分析了视图与基表关系、创建维护要点及性能影响,强调视图是提升数据库管理效率的重要工具。三桥君通过系统讲解,帮助读者掌握这一常被忽视却功能强大的数据库特性。
913 0
|
5月前
|
中间件 关系型数据库 Go
Go语言数据库编程:数据迁移与事务控制
本文介绍了《Go语言实战指南》中关于数据库编程的核心内容,涵盖使用 GORM 进行数据迁移与事务控制。主要内容包括:AutoMigrate 方法自动创建或更新表结构;事务控制的自动与手动实现方式;事务隔离级别的设置;以及在 Gin 框架中统一管理事务的实践建议。适合开发阶段的数据库结构管理和事务性操作需求。

热门文章

最新文章