zoukankan      html  css  js  c++  java
  • Spring的事务管理(一)

    数据库事务必须同时满足4个特性:原子性(Atomic),一致性(Consistency),隔离性(Isolation),持久性(Durabiliy),简称ACID.

    原子性:表示组成一个事务的多个数据库操作是一个不可分割的原子单元,要么全部执行成功,整个事务提交;要么回滚,回到初始状态.

    一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏.

    隔离性:在并发数据操作时,每一个事务本身拥有各自的数据空间,事务之间不会产生彼此干扰.准确的说,并非要求做到完全无干扰,数据库本身规定了多种事务隔离级别,

    不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱.

    持久性:一旦事务提交成功后,事务中所有的数据操作必须被持久化到数据库中,即使在提交事务后,数据库崩溃,在数据库重启时,也必须要保证能够通过某种机制恢复数据.

    数据并发的问题

    1:脏读:A事务读取B事务尚未提交的更改数据.

    2:不可重复读:A事务读取了B事务已经提交的更改数据.

    3:幻象读:A事务读取了B事务提交的新增数据,这时A事务将出现幻想读的问题.

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

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

    数据库锁机制/事务隔离级别

    按锁定的对象的不同,一般可以分为表锁定和行锁定.前者对整张表进行锁定,后者只对所要操作的表中的行记录进行锁定.从并发事务锁定的关系上看,可以分为共享锁定和独占锁定.

    共享锁定会防止独占锁定,但允许其他的共享锁定.而独占锁定即防止其他的独占锁定也防止其他的共享锁定.为了更改数据,数据库必须在更改的行上施加行独占锁定,INSERT,UPDATE,DELETE和SELECT FOR UPDATE语句都会隐式采用必要的行独占锁定.

    尽管数据库为用户提供了锁的DML操作方式,但直接使用锁管理是非常麻烦的,因此数据库为用户提供了自动锁机制.只要用户指定了会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加合适的锁.

    ANSI/ISO SQL92标准定义了4个等级的事务隔离级别.

    隔离级别 脏读 不可重复读 幻象读 第一类丢失更新 第二类丢失更新
    READ UNCOMMITED 允许 允许 允许 不允许 允许
    READ COMMITED 不允许 允许 允许 不允许 允许
    REPEATABLE READ 不允许 不允许 允许 不允许 不允许
    SERIALIZABLE 不允许 不允许 不允许 不允许 不允许

    ThreadLocal

    针对并发中对象非线程安全的问题有两种处理方式:

    1:传统的同步方式,即对对象的访问采用synchronized进行线程同步,但线程同步会降低并发性,影响系统性能.(时间换空间)

    2:采用空间换时间的方式,给每个对象添加当前线程的副本,即采用ThreadLocal方式.

    什么是ThreadLocal?通过分析源码:

       public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
     ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
      public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
      void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

    以上列出了一些重要的源码:

    通过源码我们可以知道:ThreadLocal在其内部维护了一个内部类ThreadLocalMap,而其构造函数为

     ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue)

    可见ThreadLocalMap的key为当前线程的对象本身.

    所以jdk1.8版本的ThreadLocal的核心就是在其内部维护了一个以当前线程的对象本身为key,来存储一个value的容器.

    ThreadLocal在spring中发挥着重要的作用,在管理request作用域的Bean,事务管理,任务调度,AOP等模块中都出现了它的身影.

    如创建一个线程安全的Connection类

    package com.springboot.transaction;
    
    import java.sql.Connection;
    
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    
    public class ConnUtil {
        private static ThreadLocal<Connection> connThreadLocal  = new ThreadLocal<Connection>();
        private static final String DRIVER_CLASS = "";
        private static final String URL = "";
        private static final String USER_NAME = "";
        private static final String PASS_WORD = "";
        
        public static  Connection getConnection() {
                try {
                    if(connThreadLocal.get() == null) {
    //                    Connection conn = DriverManager.getConnection("", "", "");
                        DriverManagerDataSource ds = new DriverManagerDataSource();
                        ds.setDriverClassName(DRIVER_CLASS);
                        ds.setUrl(URL);
                        ds.setUsername(USER_NAME);
                        ds.setPassword(PASS_WORD);
                        Connection conn = ds.getConnection();
                        connThreadLocal.set(conn);
                        return conn;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return connThreadLocal.get();
        }
    }
  • 相关阅读:
    C语言基础--函数
    C语言基础--for循环
    C语言基础--while循环
    C语言基础--switch
    iOS UIView常用方法和属性
    iOS UIView简单缩放动画
    Android ListView动态改变Item高度
    iOS UILabel自定义行间距时获取高度
    iOS UILable高度自适应
    iOS 简单block的使用
  • 原文地址:https://www.cnblogs.com/xibushijie/p/12857485.html
Copyright © 2011-2022 走看看