博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring的事务管理基础知识
阅读量:6197 次
发布时间:2019-06-21

本文共 4388 字,大约阅读时间需要 14 分钟。

1、数据库事务基础知识

    1)数据库事务有严格的定义,它必须同时满足4个特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称ACID。
    2)数据并发的问题:脏读、不可重复读、幻想读、第一类丢失更新、第二类丢失更新。
    3)数据库锁机制:
        按锁定的对象的不同:一般可以分别表锁定和行锁定,前者对整个表进行锁定,而后者对表中特定行进行锁定。从并发事务锁定的关系上看,可以分为共享锁定和独占锁定。共享锁定会防止独占锁定,但允许其他的共享锁定。而独占锁定既防止其他的独占锁定,也防止其他的共享锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定,INSERT、UPDATE、DELETE和SELECT FOR UPDATE语句都会隐式采用必要的行锁定。
    4)事务隔离级别:READ UNCOMMITED 、 READ COMMITTED、REPEATABLE READ、SERIALIZABLE。
    5)JDBC对事务支持
        用户可以通过Connection#getMetaData()方法获取DatabaseMetaData对象,并通过该对象的supportsTransactions()、supportsTransactionIsolationLevel(int level)方法查看底层数据库的事务支持情况。Connection默认情况下是自动提交的,也即每条执行的SQL都对应一个事务,为了能够将多条SQL当成一个事务执行,必须先通过Connection#setAutoCommit(false)阻止Connection自动提交,并可通过Connection#setTransactionIsolation()设置事务的隔离级别,Connection中定义了对应SQL92标准4个事务隔离级别的常量。通过Connection#commit()提交事务,通过Connection#rollback()回滚事务。
    典型的JDBC事务数据操作的代码:
Connection conn;try{  conn = DriverManager.getConnection();  conn.setAutoCommit(false);  conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);  Statement stmt = conn.createStatement();  int rows = stmt.executeUpdate("INSERT INTO t_topic VALUES(1,'tom')");  rows = stmt.executeUpdate("UPDATE t_user set topic_nums = topic_nums + 1 WHERE user_id = 1");   conn.commit();}catch(Exception e){  ...  conn.rollback();}finally(  ...)

 

2、ThreadLocal基础知识
    ThreadLocal,顾名思义,他不是一个线程,而是线程的一个本地化对象。当工作于多线程中的对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。从线程的角度看,这个变量就像是线程的本地变量,这也是类名中“Local”所要表达的意思。
    ThreadLocal类接口很简单,只有4个方法:
    1)void set(Object value):设置当前线程的线程局部变量的值;
    2)public Object get():该方法返回当前线程所对应的线程局部变量;
    3)public void remove():将当前线程局部变量的值删除,目的是为了减少内存的利用。
    4)protected Object initialValue():返回该线程局部变量的初始值。
    ThreadLocal是如何做到为每一个线程维护一份独立的变量副本呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素键为线程对象,而值对应线程的变量副本。
简单的实现版本:
package com.yyq.transaction;import java.util.Collections;import java.util.HashMap;import java.util.Map;public class SimpleThreadLocal {    private Map valueMap = Collections.synchronizedMap(new HashMap());    public void set(Object newValue){        valueMap.put(Thread.currentThread(),newValue);    }        public Object get(){        Thread currentThread = Thread.currentThread();        Object o = valueMap.get(currentThread);        if (o == null && !valueMap.containsKey(currentThread)){            o = initialValue();            valueMap.put(currentThread,o);        }        return o;    }        public void remove(){        valueMap.remove(Thread.currentThread());    }        public Object initialValue(){        return null;    }}

一个ThreadLocal实例:

package com.yyq.transaction;public class SequenceNumber {    private static ThreadLocal
seqNum = new ThreadLocal
() { public Integer initialValue() { return 0; } }; public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn) { this.sn = sn; } public void run() { for (int i = 0; i < 3; i++) { System.out.println("thread[" + Thread.currentThread().getName() + "]sn[" + sn.getNextNum() + "]"); } } } public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); }}
输出结果:
thread[Thread-1]sn[1]
thread[Thread-1]sn[2]
thread[Thread-1]sn[3]
thread[Thread-0]sn[1]
thread[Thread-0]sn[2]
thread[Thread-0]sn[3]
thread[Thread-2]sn[1]
thread[Thread-2]sn[2]
thread[Thread-2]sn[3]
 
    根据输出结果可以发现每个线程所产生的序号虽然都共享同一个SequenceNumber实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。
    在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序缜密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
    而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程对访问数据的冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对变量进行同步了。ThreadLocal提供了线程安全的对象封装,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
    概况起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。而ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

 

转载于:https://www.cnblogs.com/yangyquin/p/5583112.html

你可能感兴趣的文章
机器废渣!AI离占领华尔街还早着呢
查看>>
DHTML快速入门
查看>>
linux shell基础
查看>>
logstash之input
查看>>
科来抓包验证OSPF选择DR
查看>>
Android多功能日期选择控件
查看>>
Netty实践(四):心跳检测实现
查看>>
1-消息队列简介
查看>>
SQLServer图数据库一些优点
查看>>
selenium-----简单的页面元素查找方法
查看>>
自动化运维之批量修改主机名
查看>>
二分查找法
查看>>
Redistribute配置实例
查看>>
mysql性能测试工具之mysqlslap
查看>>
Java Http断点下载文件
查看>>
文件服务器之Branchcache托管式缓存
查看>>
桌面虚拟化(四):第二阶段,形影不离的贴身秘书
查看>>
EIGRP auto-summary
查看>>
我眼中的服务提供和服务消费
查看>>
[unity3d]汽车的开关门动画播放
查看>>