Spring学习笔记[6]之事务概述

数据库事务

定义

事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。

以A转账给B为例:

  • 正常操作:A扣钱,B收钱
  • 异常:A扣钱,异常导致B未收到钱,则事务会回滚,将A的钱退回

A扣钱+B收钱,这两个逻辑单元就组成了一个事务,要么一起操作成功,要么一起操作失败

数据库事务的特性 ACID

  • 原子性Atomic表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。
  • 一致性Consistency事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。
  • 隔离性Isolation在并发数据操作的时,不同事务拥有各自的数据空间,它们的操作不会对对方产生干扰。
  • 持久性Durabiliy一旦事务提交成功后,事务中的所有数据操作都必须被持久化到数据库中。

数据并发问题

  • 脏读:A事务读到了B事务的未提交的数据,并在这个数据的基础上进行操作

  • 不可重复读:A事务读取了B事务已经提交的更改数据(更改或者删除)

    解决方案:对操作的事务添加行级锁,阻止操作中的数据发生变化

  • 虚读/幻象读:A事务读取B事务提交的新增数据,导致A多次统计结果不一致

    解决方案:添加表级锁 — 将整张表锁定,防止新增数据

  • 第一类丢失更新:A事务撤销时,把已经提交的B事务的更新数据覆盖了

  • 第二类丢失更新:A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失

数据库锁机制

锁定对象不同:表锁定和行锁定

并发事务锁定的关系:共享锁定和独占锁定

数据库常用5种锁定:行共享锁定、行独占锁定、表共享锁定、表共享行独占锁定、表独占锁定

事务隔离级别

只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加合适的锁。

事务的隔离级别和数据库并发性是对立的,READ UNCOMMITED隔离级别的数据库拥有最高的并发性和吞吐量。

隔离级别脏读不可重复读取幻象读第一类丢失更新第二类丢失更新
READ UNCOMMITEDOOOXO
READ COMMITEDXOOXO
REPEATABLE READXXOXX
SERIALIZABLEXXXXX

Spring与线程安全

ThreadLocal

Spring中多个DAO可以复用同一个模板实例而不会发生冲突,主要是应用了ThreadLocal.

ThreadLocal:不是一个线程,而是保存线程本地化对象的容器,当运行于多线程环境的某个对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。

实现:在ThreadLocal类中有一个Map,用于存储每个线程的变量副本,Map中元素的键为线程对象,值为对应线程的变量副本。

解决多线程中的并发访问:

线程同步机制:通过对象的锁机制保证同一时间只有一个线程访问变量,以时间换空间,访问串行化,对象共享化

ThreadLocal:为每个线程提供一个独立的变量副本,从而隔离了多个线程堆访问数据的冲突。以空间换时间,访问并行化,对象独享化

一般在Web应用中,从接收请求到返回响应经过的所有程序调用都同属于一个线程。

Spring利用ThreadLocal对Bean改造实现线程安全

public class Demo{
    //一个非线程安全的变量
    private Connection conn;
    
    public void add() throw SQLException{
        //引用非线程安全变量
        Statement statement=getConnection().createStatement();
    }
}
/*********************** ThreadLocal 线程安全 **************************************/
public class Demo {
    //使用ThreadLocal保存Connection变量
    private static ThreadLocal<Connection> connectionThreadLocal=new ThreadLocal<Connection>();

    public static Connection getConnection(){
        //如果connThreadLocal没有本线程对应的Connection,
        // 则创建一个新的Connection,保存到线程本地变量中
        if(connectionThreadLocal.get()==null){
            Connection connection=ConnectionMan.getConnection();
            connectionThreadLocal.set(connection);
            return connection;
        }else{
            //直接返回线程本地变量
            return connectionThreadLocal.get();
        }
    }
    public void add(){
        try {
            Statement statement=getConnection().createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

下一篇:Spring学习笔记[7]之Spring事务管理  https://blog.youkuaiyun.com/Rabbit_Judy/article/details/81842676 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值