国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

如何更新網(wǎng)站緩存濟(jì)南網(wǎng)絡(luò)優(yōu)化廠家

如何更新網(wǎng)站緩存,濟(jì)南網(wǎng)絡(luò)優(yōu)化廠家,網(wǎng)站一般怎么維護(hù),安裝wordpress 403本文全面的介紹了JDBC的相關(guān)知識(shí),包括其基礎(chǔ)與高級(jí)應(yīng)用、Service層的事務(wù)管理、ThreadLocal(本地線程變量)、 數(shù)據(jù)庫(kù)連接池、Commons Dbutils的原理及其使用! 文章目錄 一、JDBC基礎(chǔ)1.1JDBC介紹1.2JDBC的核心類與接口1.java.sql.D…

本文全面的介紹了JDBC的相關(guān)知識(shí),包括其基礎(chǔ)與高級(jí)應(yīng)用、Service層的事務(wù)管理、ThreadLocal(本地線程變量)、 數(shù)據(jù)庫(kù)連接池、Commons Dbutils的原理及其使用!

文章目錄

  • 一、JDBC基礎(chǔ)
    • 1.1JDBC介紹
    • 1.2JDBC的核心類與接口
      • 1.java.sql.DriverManager類 (`驅(qū)動(dòng)管理器`)
      • 2.java.sql.Connection接? (`數(shù)據(jù)庫(kù)連接`)
      • 3.java.sql.Connection接? (`數(shù)據(jù)庫(kù)連接`)
      • 4.java.sql.ResultSet接? (`結(jié)果集`)
    • 1.3SQL注?問(wèn)題
    • 1.4 JDBC開發(fā)步驟
  • 二、JDBC高級(jí)應(yīng)用
    • 2.1 三層架構(gòu)與面向結(jié)構(gòu)編程
    • 2.1 封裝
    • 2.2 Service層的事務(wù)管理
    • 2.3 ThreadLocal(本地線程變量)
    • 2.4 數(shù)據(jù)庫(kù)連接池
    • 2.5 Commons Dbutils(Apache提供的dao層工具類)
      • (1)原理(自定義DaoUtils實(shí)現(xiàn)通用)
      • (2)Apache的DbUtils

一、JDBC基礎(chǔ)

1.1JDBC介紹

  • JDBC (全稱Java DataBase Contectivity) :Java與數(shù)據(jù)庫(kù)的連接,數(shù)據(jù)庫(kù)編程。
  • JDBC 是Java語(yǔ)?(JDK)為完成數(shù)據(jù)庫(kù)的訪問(wèn)操作提供的?套統(tǒng)?的標(biāo)準(zhǔn)
  • 驅(qū)動(dòng)包下載: 下載驅(qū)動(dòng)jar包,下載地址:https://mvnrepository.com/,打開?址搜索 mysql 。
  • (開發(fā)者通過(guò)JDK提供的規(guī)范與數(shù)據(jù)庫(kù)廠商提供的驅(qū)動(dòng),將驅(qū)動(dòng)類加載到程序中使用,進(jìn)而達(dá)到通過(guò)程序操作數(shù)據(jù)庫(kù))

請(qǐng)?zhí)砑訄D片描述


1.2JDBC的核心類與接口

1.java.sql.DriverManager類 (驅(qū)動(dòng)管理器)

  • 注冊(cè)驅(qū)動(dòng)
  • 創(chuàng)建數(shù)據(jù)庫(kù)連接

(1)注冊(cè)驅(qū)動(dòng)

  • 在Driver類中的靜態(tài)初始化塊中,注冊(cè)驅(qū)動(dòng):DriverManager.registerDriver(new
    Driver());
public class Driver extends NonRegisteringDriver implements >java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}
  • 在我們的應(yīng)?程序中?動(dòng)注冊(cè)驅(qū)動(dòng)的代碼也可以省略
    【Class.forName(“com.mysql.cj.jdbc.Driver”);】

    如果我們沒(méi)有?動(dòng)注冊(cè)驅(qū)動(dòng),驅(qū)動(dòng)管理器在獲取連接的時(shí)候發(fā)現(xiàn)沒(méi)有注冊(cè)驅(qū)動(dòng)則讀取 驅(qū)動(dòng)jar/META-INF/servicesjava.sql.Driver?件中配置的驅(qū)動(dòng)類路徑進(jìn)?注冊(cè) 不推薦
    在這里插入圖片描述

(2)獲取連接

// url 數(shù)據(jù)庫(kù)服務(wù)器的地址
// username 數(shù)據(jù)庫(kù)連接??名
// password 數(shù)據(jù)庫(kù)連接密碼
Connection connection = DriverManager.getConnection(url, "root","123456");

2.java.sql.Connection接? (數(shù)據(jù)庫(kù)連接)

Connection對(duì)象表?Java應(yīng)?程序與數(shù)據(jù)庫(kù)之間的連接

  • 通過(guò)Connection接?對(duì)象,獲取執(zhí)?SQL語(yǔ)句的Statement對(duì)象
  • 完成數(shù)據(jù)的事務(wù)管理

(1) 獲取Statement對(duì)象

  • Statement接?: 編譯執(zhí)?靜態(tài)SQL指令
Statement statement = connection.createStatement();
  • PreparedStatement接?:繼承了Statement接?,預(yù)編譯動(dòng)態(tài)SQL指令(解決SQL注?問(wèn)題)
PreparedStatement preparedStatement = connection.prepareStatement(sql);
  • CallableStatement接?:繼承了PreparedStatement接?,可以調(diào)?存儲(chǔ)過(guò)程
CallableStatement callableStatement = connection.prepareCall(sql);

(2)事務(wù)管理

//開啟事務(wù)(關(guān)閉事務(wù)?動(dòng)提交)
connection.setAutoCommit(false);
//事務(wù)回滾
connection.rollback();
//提交事務(wù)
connection.commit();

3.java.sql.Connection接? (數(shù)據(jù)庫(kù)連接)

—用于編譯、執(zhí)行SQL指令
在這里插入圖片描述

// 執(zhí)?DML操作的SQL指令(返回值是受影響行數(shù))
int row = statement.executeUpdate(sql);
// 執(zhí)?DQL操作的SQL指令(返回結(jié)果集)
ResultSet rs = statement.executeQuery(sql);

4.java.sql.ResultSet接? (結(jié)果集

— ResultSet接?對(duì)象,表?查詢操作返回的結(jié)果集,提供了便利的?法?于獲取結(jié)果集中的數(shù)據(jù)

	//res.next()用于判斷下一個(gè)位置是否還有值,初始時(shí)位于首元素之前while (res.next()){//res.getInt("tid"):通過(guò)數(shù)據(jù)庫(kù)字段名獲取數(shù)據(jù)//res.getInt(2):通過(guò)字段列標(biāo)獲取數(shù)據(jù)(列標(biāo)從1開始)teacher=new Teacher(res.getInt("tid"),res.getString("tname"),res.getString("gender"),res.getDate("workingdate"),res.getString("workgrade"));}

1.3SQL注?問(wèn)題

(1)什么是SQL注?問(wèn)題

  • 在JDBC操作SQL指令編寫過(guò)程中,如果SQL指令中需要數(shù)據(jù),我們可以通過(guò)字符串拼接的形式將參數(shù)拼接到SQL指令中,如 String sql = "delete from books where book_id="+s; (s就是拼接到SQL中的變量)
  • 使?字符串拼接變量的形式來(lái)設(shè)置SQL語(yǔ)句中的數(shù)據(jù),可能會(huì)導(dǎo)致因變量值的改變引起SQL指令的原意發(fā)?改變 ,這就被稱為SQL注?。SQL注?問(wèn)題是需要避免的
  • 例如:
    如果s的值為1,SQL指令 : delete from books where book_id=1,
    如果s的值為1 or 1=1,SQL指令:delete from books where book_id=1 or 1=1, 那么SQL中的條件則是?個(gè)恒等式(sql指令發(fā)生變化)

(2)如何解決SQL注?問(wèn)題

使?PreparedStatement進(jìn)?SQL預(yù)編譯解決SQL注?問(wèn)題:

  • 在編寫SQL指令時(shí),如果SQL指令中需要參數(shù),?律使??參數(shù)占位符
  • 如果SQL指令中有?,在JDBC操作步驟中不再使?Statement,?是從Conection對(duì)象獲取PreparedStatement對(duì)SQL指令進(jìn)?預(yù)編譯 PreparedStatement preparedStatement = connection.prepareStatement(sql);
  • 預(yù)編譯完成之后,通過(guò)PreparedStatement對(duì)象給預(yù)編譯后的SQL指令的?賦值
    • prepareadStatement.setInt(參數(shù)占位符序號(hào),值);
    • prepareadStatement.setString(參數(shù)占位符序號(hào),值);
  • SQL指令中的所有?完成賦值之后,通過(guò)PreparedStatement執(zhí)?SQL執(zhí)?SQL時(shí)不再加載SQL語(yǔ)句
    • int row = prepareadStatement.executeUpdate();
    • ResultSet rs = preparedStatement.executeQuery();

1.4 JDBC開發(fā)步驟

  • 加載驅(qū)動(dòng)
 //	1.加載驅(qū)動(dòng)類
Class.forName("com.mysql.jdbc.Driver");
  • 創(chuàng)建連接
//2.建立連接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/javaTest", "root", "123456");
  • 編寫sql指令
   //3.編寫sql語(yǔ)句String sql="insert into student values(2,'李四')";
  • 創(chuàng)建執(zhí)行體
//4.創(chuàng)建執(zhí)行體stmt = conn.createStatement();
  • 執(zhí)行sql指令
//5.執(zhí)行sql語(yǔ)句int row = stmt.executeUpdate(sql);
  • 處理執(zhí)行結(jié)果(集)
//6.處理結(jié)果if (row>-1){System.out.println("插入成功!");}else{System.out.println("插入失敗!");}
  • 釋放占用資源
  //釋放資源try {stmt.close();conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}

二、JDBC高級(jí)應(yīng)用

2.1 三層架構(gòu)與面向結(jié)構(gòu)編程

(1)三層架構(gòu)

三層架構(gòu)是指:視圖層 View、服務(wù)層 Service,與持久層 Dao。它們分別完成不同的功能。

  • View 層:用于接收用戶提交請(qǐng)求。
  • Service 層:用以實(shí)現(xiàn)系統(tǒng)的業(yè)務(wù)邏輯
  • Dao 層:用以實(shí)現(xiàn)直接對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作。

(2)面向接口 (抽象) 編程

面向接口編程:程序設(shè)計(jì)時(shí),考慮易修改、易擴(kuò)展,為Service層和DAO層設(shè)計(jì)接口,便于未來(lái)更換實(shí)現(xiàn)類
在三層架構(gòu)程序設(shè)計(jì)中,采用面向接口(抽象)編程。

  • 實(shí)現(xiàn)方式
    • 上層對(duì)下層的調(diào)用,是通過(guò)下層接口實(shí)現(xiàn)的
    • 而下層對(duì)上層的真正服務(wù)提供者,是下層接口的實(shí)現(xiàn)類
      img
  • 特點(diǎn):
    • 服務(wù)標(biāo)準(zhǔn)(接口:規(guī)范相同)是相同的,服務(wù)提供者(實(shí)現(xiàn)類)可以更換。這就實(shí)現(xiàn)了層間解耦合與編程的靈活性

2.1 封裝

(1)DAO封裝 — (DAO Data Access Object 數(shù)據(jù)訪問(wèn)對(duì)象)

將對(duì)數(shù)據(jù)庫(kù)中同?張數(shù)據(jù)表的JDBC操作?法封裝到同?個(gè)Java類中,這個(gè)類就是訪問(wèn)此數(shù)據(jù)表的 數(shù)據(jù)訪問(wèn)對(duì)象

(2)DTO封裝 — ( Data Transfer Object 數(shù)據(jù)傳輸對(duì)象(實(shí)體類))

在Java程序中創(chuàng)建?個(gè)屬性與數(shù)據(jù)庫(kù)表匹配的類,通過(guò)此類的對(duì)象封裝查詢到的數(shù)據(jù),我們把?于傳遞JDBC增刪查改操作的數(shù)據(jù)的對(duì)象稱之為 數(shù)據(jù)傳輸對(duì)象

2.2 Service層的事務(wù)管理

(1)事務(wù)的概念

事務(wù)是指是程序中一系列嚴(yán)密的邏輯操作,而且所有操作必須全部成功完成,否則在每個(gè)操作中所作的所有更改都會(huì)被撤消。

(2)事務(wù)的四大特性

  • 原子性(Atomicity):操作這些指令時(shí),要么全部執(zhí)行成功,要么全部不執(zhí)行。只要其中一個(gè)指令執(zhí)行失敗,所有的指令都執(zhí)行失敗,數(shù)據(jù)進(jìn)行回滾,回到執(zhí)行指令前的數(shù)據(jù)狀態(tài)。
  • 一致性(Consistency): 事務(wù)的執(zhí)行使數(shù)據(jù)從一個(gè)狀態(tài)轉(zhuǎn)換為另一個(gè)狀態(tài),但是對(duì)于整個(gè)數(shù)據(jù)的完整性保持穩(wěn)定。
  • 隔離性(Isolation): 隔離性是當(dāng)多個(gè)用戶并發(fā)訪問(wèn)數(shù)據(jù)庫(kù)時(shí),比如操作同一張表時(shí),數(shù)據(jù)庫(kù)為每一個(gè)用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾,多個(gè)并發(fā)事務(wù)之間要相互隔離。
  • 持久性(Durability): 當(dāng)事務(wù)正確完成后,它對(duì)于數(shù)據(jù)的改變是永久性的。

(3)事務(wù)的隔離級(jí)別

  • 第一種隔離級(jí)別:Read uncommitted(讀未提交)

    • 如果一個(gè)事務(wù)已經(jīng)開始寫數(shù)據(jù),則另外一個(gè)事務(wù)不允許同時(shí)進(jìn)行寫操作,但允許其他事務(wù)讀此行數(shù)據(jù),該隔離級(jí)別可以通過(guò)“排他寫鎖”,但是不排斥讀線程實(shí)現(xiàn)。這樣就避免了更新丟失,卻可能出現(xiàn)臟讀,也就是說(shuō)事務(wù)B讀取到了事務(wù)A未提交的數(shù)據(jù)

    • 解決了更新丟失,但還是可能會(huì)出現(xiàn)臟讀


    第二種隔離級(jí)別:Read committed(讀提交)

    • 如果是一個(gè)讀事務(wù)(線程),則允許其他事務(wù)讀寫,如果是寫事務(wù)將會(huì)禁止其他事務(wù)訪問(wèn)該行數(shù)據(jù),該隔離級(jí)別避免了臟讀,但是可能出現(xiàn)不可重復(fù)讀。事務(wù)A事先讀取了數(shù)據(jù),事務(wù)B緊接著更新了數(shù)據(jù),并提交了事務(wù),而事務(wù)A再次讀取該數(shù)據(jù)時(shí),數(shù)據(jù)已經(jīng)發(fā)生了改變。

    • 解決了更新丟失和臟讀問(wèn)題


    第三種隔離級(jí)別:Repeatable read(可重復(fù)讀取)

    • 可重復(fù)讀取是指在一個(gè)事務(wù)內(nèi),多次讀同一個(gè)數(shù)據(jù),在這個(gè)事務(wù)還沒(méi)結(jié)束時(shí),其他事務(wù)不能訪問(wèn)該數(shù)據(jù)(包括了讀寫),這樣就可以在同一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是一樣的,因此稱為是可重復(fù)讀隔離級(jí)別,讀取數(shù)據(jù)的事務(wù)將會(huì)禁止寫事務(wù)(但允許讀事務(wù)),寫事務(wù)則禁止任何其他事務(wù)(包括了讀寫),這樣避免了不可重復(fù)讀和臟讀,但是有時(shí)可能會(huì)出現(xiàn)幻讀。(讀取數(shù)據(jù)的事務(wù))可以通過(guò)“共享讀鏡”和“排他寫鎖”實(shí)現(xiàn)。

    • 解決了更新丟失、臟讀、不可重復(fù)讀、但是還會(huì)出現(xiàn)幻讀


    第四種隔離級(jí)別:Serializable(序列化)

    • 提供嚴(yán)格的事務(wù)隔離,它要求事務(wù)序列化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,但不能并發(fā)執(zhí)行,如果僅僅通過(guò)“行級(jí)鎖”是無(wú)法實(shí)現(xiàn)序列化的,必須通過(guò)其他機(jī)制保證新插入的數(shù)據(jù)不會(huì)被執(zhí)行查詢操作的事務(wù)訪問(wèn)到。序列化是最高的事務(wù)隔離級(jí)別,同時(shí)代價(jià)也是最高的,性能很低,一般很少使用,在該級(jí)別下,事務(wù)順序執(zhí)行,不僅可以避免臟讀、不可重復(fù)讀,還避免了幻讀

    • 解決了更新丟失、臟讀、不可重復(fù)讀、幻讀(虛讀)


    隔離級(jí)別臟讀不可重復(fù)度幻讀
    Read uncommitted(讀未提交)
    Read committed(讀提交)×
    Repeatable read(可重復(fù)讀取)××
    Serializable(序列化)×××
    • 臟讀
      • 所謂臟讀是指一個(gè)事務(wù)中訪問(wèn)到了另外一個(gè)事務(wù)未提交的數(shù)據(jù)
    • 幻讀
      • 一個(gè)事務(wù)讀取2次,得到的記錄條數(shù)不一致
    • 不可重復(fù)讀
      • 一個(gè)事務(wù)讀取同一條記錄2次,得到的結(jié)果不一致
  • MySQL事務(wù)管理:

    • start transaction (開啟事務(wù))
    • end transaction (結(jié)束事務(wù))
    • rollback (事務(wù)回滾)
    • commit (提交事務(wù))

(4)JDBC事務(wù)管理

  • ?個(gè)事務(wù)中的多個(gè)DML操作需要基于同?個(gè)數(shù)據(jù)庫(kù)連接
  • 創(chuàng)建連接之后,設(shè)置事務(wù)?動(dòng)提交(關(guān)閉?動(dòng)提交connection.setAutoCommit(false);
  • 當(dāng)當(dāng)前事務(wù)中的所有DML操作完成之后?動(dòng)提交 connection.commit();
  • 當(dāng)事務(wù)中的任何?個(gè)步驟出現(xiàn)異常,在catch代碼塊中執(zhí)?事務(wù)回滾
    connection.rollback();

(5)Service層簡(jiǎn)介

DAO負(fù)責(zé)特定的數(shù)據(jù)庫(kù)操作,業(yè)務(wù)由service層進(jìn)?管理

  • 業(yè)務(wù):指的是完成某一功能(軟件提供的一個(gè)功能)
    • 例如:A給B轉(zhuǎn)帳(其包含A賬戶減錢,B賬戶加錢),其整體為一個(gè)業(yè)務(wù)的操作
  • Servcie進(jìn)?業(yè)務(wù)處理,Service業(yè)務(wù)處理過(guò)程如果需要數(shù)據(jù)庫(kù)操作,則調(diào)?DAO完成
  • Service層的一個(gè)業(yè)務(wù),可能需要調(diào)用一個(gè)或若干個(gè)DAO層對(duì)數(shù)據(jù)庫(kù)進(jìn)行處理

(6)Service層事務(wù)管理

事務(wù)管理要滿?以下條件:

  • 多個(gè)DML操作需使?同?個(gè)數(shù)據(jù)庫(kù)連接
  • 第?個(gè)DML操作之前設(shè)置事務(wù)?動(dòng)提交
  • 所有DML操作執(zhí)?完成之后提交事務(wù)
  • 出現(xiàn)異常則進(jìn)?事務(wù)回滾

1.需要解決的問(wèn)題

  • Servcie層事務(wù)可能涉及多個(gè)DAO層,其中多個(gè)數(shù)據(jù)庫(kù)的DML操作是相互獨(dú)?的,如何保證所有DML要么同時(shí)成功,要么同時(shí)失敗呢?

2.解決辦法:讓Service事務(wù)中的多個(gè)DML使?同?個(gè)數(shù)據(jù)庫(kù)連接

方式一:在Service獲取連接對(duì)象,將連接對(duì)象傳遞到DAO中

  • 分析: DAO類中的Connection對(duì)象需要通過(guò)Service傳遞給進(jìn)來(lái),這種對(duì)象傳遞本來(lái)也?可厚?,但是當(dāng)我們通過(guò)?向接?開發(fā)時(shí)(?向接?,是為了能夠靈活的定義實(shí)現(xiàn)類),容易造成接?的冗余(接?污染)
  • 接口污染典型示例: 不同的數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)連接對(duì)象是不同的,MySQL的連接對(duì)象是Connection 但Oracle數(shù)據(jù)庫(kù)則不是

方式二:使?ThreadLocal容器,實(shí)現(xiàn)多個(gè)DML操作使?相同的連接

  • 不使用自定義List集合的原因:
    • 存儲(chǔ)Connection的容器可以使?List集合,使?List集合做容器,在多線程并發(fā)編程中會(huì)出現(xiàn)資源競(jìng)爭(zhēng)問(wèn)題,多個(gè)并發(fā)的線程使?的是同?個(gè)數(shù)據(jù)庫(kù)連接對(duì)象我們的要求是同?個(gè)事務(wù)中使?同?個(gè)連接,?并?多個(gè)線程共享同一個(gè)連接
    • 為了解決并發(fā)編程的連接對(duì)象共享問(wèn)題,我們可以 使?ThreadLocal作為數(shù)據(jù)庫(kù)連接對(duì)象的容器

2.3 ThreadLocal(本地線程變量)

(1)ThreadLocal簡(jiǎn)介

ThreadLocal 叫做本地線程變量,意思是說(shuō),ThreadLocal 中填充的的是當(dāng)前線程的變量,該變量對(duì)其他線程而言是封閉且隔離的,ThreadLocal 為變量在每個(gè)線程中創(chuàng)建了一個(gè)副本,這樣每個(gè)線程都可以訪問(wèn)自己內(nèi)部的副本變量。

(2)ThreadLocal的應(yīng)用

  • 在進(jìn)行對(duì)象跨層傳遞的時(shí)候,使用ThreadLocal可以避免多次傳遞,打破層次間的約束。
  • 線程間數(shù)據(jù)隔離
  • 進(jìn)行事務(wù)操作,用于存儲(chǔ)線程事務(wù)信息。
  • 數(shù)據(jù)庫(kù)連接,Session會(huì)話管理。

(3)ThreadLocal常用的方法

  • set()方法:
    ThreadLocal對(duì)象.set() 會(huì)為ThreadLocal對(duì)象調(diào)用set()方法所在的線程中的ThreadLocal.ThreadLocalMap threadLocals = null;進(jìn)行賦值,賦值類型為一個(gè)Map,Map的鍵為當(dāng)前的ThreadLocal對(duì)象,值為所傳入的值.

  • set()的源碼

public void set(T value) {
//獲取當(dāng)前ThreadLocal對(duì)象所在的線程
Thread t = Thread.currentThread();
//獲取所在線程中存儲(chǔ)的threadLocals(ThreadLocalMap)
ThreadLocalMap map = getMap(t);
//判斷map是否為空
if (map != null)//不為空,則替換值map.set(this, value);
else//為空則為當(dāng)前線程創(chuàng)建ThreadLocalMap對(duì)象并為threadLocals賦值createMap(t, value);
}void createMap(Thread t, T firstValue) {
//為線程t中的threadLocals創(chuàng)建一個(gè)ThreadLocalMap對(duì)象進(jìn)行賦值
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMapThreadLocal 的一個(gè)靜態(tài)內(nèi)部類,里面定義了Entry 來(lái)保存數(shù)據(jù)。而且是繼承的弱引用。在Entry內(nèi)部使用ThreadLocal作為key,使用我們?cè)O(shè)置的value作為value。

對(duì)于每個(gè)線程內(nèi)部有個(gè)ThreadLocal.ThreadLocalMap 變量,存取值的時(shí)候,也是從這個(gè)容器中來(lái)獲取。


  • get()方法
public T get() {//獲取當(dāng)前ThreadLocal對(duì)象所在的線程Thread t = Thread.currentThread();//獲取所在線程中存儲(chǔ)的threadLocals(ThreadLocalMap)ThreadLocalMap map = getMap(t);//判斷線程中存儲(chǔ)的ThreadLocalMap是否為空if (map != null) {//不為空,則以當(dāng)前ThreadLocal對(duì)象為鍵獲取Entry對(duì)象ThreadLocalMap.Entry e = map.getEntry(this);//判斷Entry對(duì)象是個(gè)為空if (e != null) {//不為空則返回Entry對(duì)象的值@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}//線程中ThreadLocalMap為空或者未存儲(chǔ)以當(dāng)前ThreadLocal對(duì)象為鍵的Entry對(duì)象時(shí)設(shè)置初始值return setInitialValue();
}//設(shè)置為線程中ThreadLocalMap的初始值
private T setInitialValue() {//設(shè)置當(dāng)前值為nullT value = initialValue();//獲取當(dāng)前ThreadLocal對(duì)象所在的線程Thread t = Thread.currentThread();//獲取所在線程中存儲(chǔ)的threadLocals(ThreadLocalMap)ThreadLocalMap map = getMap(t);//判讀map是否為空if (map != null)//map不為空向map中添加一個(gè)以當(dāng)前ThreadLocal對(duì)象為鍵。值為空的Entry對(duì)象map.set(this, value);else//map為空則為當(dāng)前線程的threadLocals進(jìn)行創(chuàng)建對(duì)象初始化createMap(t, value);return value;
}protected T initialValue() {return null;
}

(4)ThreadLocal的內(nèi)存泄流問(wèn)題

  • 內(nèi)存泄漏原因
    ? 當(dāng)ThreadLocal為null時(shí),也就是要被垃圾回收器回收了,但是此時(shí)我們的ThreadLocalMap(thread 的內(nèi)部屬性)生命周期和Thread的一樣,它不會(huì)回收,這時(shí)候就出現(xiàn)了一個(gè)現(xiàn)象。那就是ThreadLocalMap的key沒(méi)了,但是value還在,這就造成了內(nèi)存泄漏。

  • 解決方法:
    ? 用完ThreadLocal后,執(zhí)行remove操作,避免出現(xiàn)內(nèi)存溢出情況。所以 如同 lock 的操作 最后要執(zhí)行解鎖操作一樣,ThreadLocal使用完畢一定記得執(zhí)行remove 方法,清除當(dāng)前線程的數(shù)值。如果不remove 當(dāng)前線程對(duì)應(yīng)的VALUE ,就會(huì)一直存在這個(gè)值。

(5)強(qiáng)引用,弱引用,軟引用

  • 強(qiáng)引用:普通的引用,強(qiáng)引用指向的對(duì)象不會(huì)被回收;
  • 軟引用:僅有軟引用指向的對(duì)象,只有發(fā)生gc且內(nèi)存不足,才會(huì)被回收;
  • 弱引用:僅有弱引用指向的對(duì)象,只要發(fā)生gc就會(huì)被回收。

(6)多線程環(huán)境下ThreadLocal在事務(wù)中操作可能出現(xiàn)的問(wèn)題

在闡述此問(wèn)題時(shí),需要簡(jiǎn)要介紹一下mysql數(shù)據(jù)庫(kù)的事務(wù)默認(rèn)隔離級(jí)別(Repeatable read(可重復(fù)讀取))

  • 第三種隔離級(jí)別:Repeatable read(可重復(fù)讀取)
    可重復(fù)讀取是指在一個(gè)事務(wù)內(nèi),多次讀同一個(gè)數(shù)據(jù),在這個(gè)事務(wù)還沒(méi)結(jié)束時(shí),其他事務(wù)不能訪問(wèn)該數(shù)據(jù)(包括了讀寫),這樣就可以在同一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是一樣的,因此稱為是可重復(fù)讀隔離級(jí)別,讀取數(shù)據(jù)的事務(wù)將會(huì)禁止寫事務(wù)(但允許讀事務(wù)),寫事務(wù)則禁止任何其他事務(wù)(包括了讀寫),這樣避免了不可重復(fù)讀和臟讀,但是有時(shí)可能會(huì)出現(xiàn)幻讀。

  • 場(chǎng)景
    • 存在兩個(gè)線程,因?yàn)門hreadLocal保存數(shù)據(jù)庫(kù)連接變量,可以保證兩個(gè)線程各自擁有自己的數(shù)據(jù)庫(kù)連接,一般在操作各自線程任務(wù)的事務(wù)時(shí)不會(huì)出現(xiàn)沖突和干擾
    • 現(xiàn)在有如下場(chǎng)景,兩個(gè)線程同時(shí)操作同一個(gè)數(shù)據(jù)中的同一張表,a線程使1號(hào)用戶給3號(hào)用戶轉(zhuǎn)賬,b線程使1號(hào)用戶給2號(hào)客戶轉(zhuǎn)賬,a、b線程同時(shí)運(yùn)行搶奪cpu的執(zhí)行權(quán),此時(shí)程序中只會(huì)有一個(gè)線程執(zhí)行成功,另一個(gè)線程執(zhí)行失敗
      • (原因:mysql默認(rèn)為Repeatable read(可重復(fù)讀取)隔離級(jí)別,ab兩線程同時(shí)操作寫,違反了mysql的事務(wù)隔離級(jí)別)
      • 根本原因:每個(gè)線程操作的數(shù)據(jù)庫(kù)中表的副本,在對(duì)數(shù)據(jù)庫(kù)的表操作過(guò)程中會(huì)有以下驗(yàn)證:當(dāng)a線程拿到表的副本后,會(huì)記錄拿到副本當(dāng)時(shí)表內(nèi)容狀態(tài)T,當(dāng)它修改完自己拿到的副本后準(zhǔn)備提交給數(shù)據(jù)庫(kù)時(shí),會(huì)將自己記錄的表狀態(tài)T 與提交前數(shù)據(jù)庫(kù)中此表狀態(tài)進(jìn)行比對(duì),如果二者不一致,線程a不會(huì)提交自己的副本給數(shù)據(jù)庫(kù),并會(huì)報(bào)錯(cuò)(比對(duì)結(jié)果,表明在a線程修改表內(nèi)容的期間,有其他線程對(duì)表進(jìn)行了更改,所以會(huì)報(bào)錯(cuò)

2.4 數(shù)據(jù)庫(kù)連接池

1.引入數(shù)據(jù)庫(kù)連接池的原因

  • 如果每個(gè)JDBC操作需要數(shù)據(jù)庫(kù)連接都重新創(chuàng)建,使?完成之后都銷毀,我們的JVM會(huì)因?yàn)轭l繁的創(chuàng)建、銷毀連接?占?額外的系統(tǒng)資源。
  • 數(shù)據(jù)庫(kù)連接本質(zhì)上是可被重?的資源(當(dāng)?個(gè)JDBC操作完成之后,其創(chuàng)建的連接是可以被其他JDBC操作使?的),基于這個(gè)特性:
    • 我們可以創(chuàng)建?個(gè) 存放數(shù)據(jù)庫(kù)連接的容器 (連接池),連接池是有最?容量的
    • 當(dāng)我們要進(jìn)?JDBC操作時(shí),直接從這個(gè)容器中獲取連接:
      • 如果容器中沒(méi)有空閑的連接且連接池中連接的個(gè)數(shù)沒(méi)有達(dá)到最?值,則創(chuàng)建新的數(shù)據(jù)庫(kù)連接存?連接池并給這個(gè)操作使?,使?完成之后?需關(guān)閉連接直接歸還這個(gè)容器中即可
      • 如果容器中沒(méi)有空閑的連接且連接池中連接的個(gè)數(shù)達(dá)到最?值,當(dāng)前操作就會(huì)進(jìn)?等待,等待連接池中的某個(gè)連接被歸還,歸還之后再使?
      • 如果容器中有空閑連接,則?需創(chuàng)建新的連接,直接從容器中獲取這個(gè)空閑連接進(jìn)?使?

2.概念

  • 連接池:存放數(shù)據(jù)庫(kù)連接對(duì)象的容器
  • 連接池作?:對(duì)數(shù)據(jù)庫(kù)連接進(jìn)?管理,減少因重復(fù)創(chuàng)建、銷毀連接導(dǎo)致的系統(tǒng)開銷
    preview

3.常用的線程池

功能dbcpdruidc3p0tomcat-jdbcHikariCP
是否支持PSCache
監(jiān)控jmxjmx/log/httpjmx,logjmxjmx
擴(kuò)展性
sql攔截及解析無(wú)支持無(wú)無(wú)無(wú)
代碼簡(jiǎn)單中等復(fù)雜簡(jiǎn)單簡(jiǎn)單
特點(diǎn)依賴于common-pool阿里開源,功能全面歷史久遠(yuǎn),代碼邏輯復(fù)雜,且不易維護(hù)優(yōu)化力度大,功能簡(jiǎn)單,起源于boneCP
連接池管理LinkedBlockingDeque數(shù)組FairBlockingQueuethreadlocal+CopyOnWriteArrayList
  • 由于boneCP被hikariCP替代,并且已經(jīng)不再更新,boneCP沒(méi)有進(jìn)行調(diào)研。
  • proxool網(wǎng)上有評(píng)測(cè)說(shuō)在并發(fā)較高的情況下會(huì)出錯(cuò),proxool便沒(méi)有進(jìn)行調(diào)研。
  • druid的功能比較全面,且擴(kuò)展性較好,比較方便對(duì)jdbc接口進(jìn)行監(jiān)控跟蹤等。
  • c3p0歷史悠久,代碼及其復(fù)雜,不利于維護(hù)。并且存在deadlock的潛在風(fēng)險(xiǎn)。
  • 基于連接池的性能、使?的便捷性、連接監(jiān)控等多??綜合情況,druid是?前企業(yè)應(yīng)?中使?最 ?泛的
  • Hikari在SpringBoot中默認(rèn)集成,性能是諸多競(jìng)品中最好的

4.Druid線程池的使用

  • 參考我的另一篇博客: Druid連接池簡(jiǎn)介及其使用

2.5 Commons Dbutils(Apache提供的dao層工具類)


(1)原理(自定義DaoUtils實(shí)現(xiàn)通用)

  • 核心思想:使用泛型
  • 參考我的另一篇博客: DaoUtils實(shí)現(xiàn)通用(增、刪、改、查)

(2)Apache的DbUtils

  • 核心思想:反射
  • 注意事項(xiàng):創(chuàng)建QueryRunner對(duì)象時(shí),不能使用無(wú)參構(gòu)造方法,需要傳入一個(gè)連接池對(duì)象(配合線程池使用)
  • 參考我的另一篇博客: DaoUtils實(shí)現(xiàn)通用(增、刪、改、查)
http://m.aloenet.com.cn/news/32815.html

相關(guān)文章:

  • 網(wǎng)站中鏈接怎么做推廣網(wǎng)站公司
  • 網(wǎng)站開發(fā)進(jìn)度管理表谷歌seo工具
  • 太原網(wǎng)站建設(shè)費(fèi)用上首頁(yè)seo
  • 網(wǎng)站一般寬度windows優(yōu)化大師有哪些功能
  • 國(guó)內(nèi) 設(shè)計(jì)網(wǎng)站的公司網(wǎng)站3000行業(yè)關(guān)鍵詞
  • 手機(jī)網(wǎng)站開發(fā)教程?hào)|莞做網(wǎng)站哪家公司好
  • 網(wǎng)站有沒(méi)有做網(wǎng)站地圖怎么看今天國(guó)際新聞大事
  • 想做一個(gè)自己設(shè)計(jì)公司的網(wǎng)站怎么做的網(wǎng)站推廣公司電話
  • 電腦做系統(tǒng)網(wǎng)站鄭州網(wǎng)站優(yōu)化培訓(xùn)
  • 軟件工程師是程序員嗎電腦優(yōu)化工具
  • 建設(shè)一個(gè)大型網(wǎng)站大概費(fèi)用磁力王
  • 主流門戶網(wǎng)站百度關(guān)鍵詞搜索推廣
  • 怎樣設(shè)計(jì)網(wǎng)頁(yè)教程關(guān)鍵詞優(yōu)化外包
  • 鄭州電力高等??茖W(xué)校哪個(gè)專業(yè)好重慶seo和網(wǎng)絡(luò)推廣
  • 可視化網(wǎng)站制作軟件站長(zhǎng)之家ppt素材
  • 深圳html5網(wǎng)站建設(shè)搜索引擎營(yíng)銷sem
  • 遼寧網(wǎng)站推廣的目的網(wǎng)絡(luò)運(yùn)營(yíng)是做什么的工作
  • 做外國(guó)網(wǎng)站買域名推廣賺錢一個(gè)2元
  • 網(wǎng)站建設(shè)后期維護(hù)小魔仙網(wǎng)絡(luò)廣告宣傳平臺(tái)
  • 企業(yè)網(wǎng)絡(luò)營(yíng)銷策劃方案范文免費(fèi)seo教程資源
  • wordpress 添加搜索引擎北京網(wǎng)絡(luò)seo
  • 三合一網(wǎng)站建設(shè)方案深圳市網(wǎng)絡(luò)營(yíng)銷推廣服務(wù)公司
  • b2b網(wǎng)站建設(shè)開發(fā)china東莞seo
  • 網(wǎng)站的服務(wù)有哪些seo外鏈工具有用嗎
  • 南陽(yáng)網(wǎng)站建設(shè)大旗電商電商網(wǎng)站訂煙
  • wordpress投訴功能qq群怎么優(yōu)化排名靠前
  • 多媒體網(wǎng)站開發(fā)實(shí)驗(yàn)報(bào)告做企業(yè)網(wǎng)站建設(shè)的公司
  • 網(wǎng)頁(yè)搜索工具新站seo優(yōu)化快速上排名
  • wordpress推廣升級(jí)vipseo做什么網(wǎng)站賺錢
  • 學(xué)網(wǎng)站建設(shè)怎么樣tool站長(zhǎng)工具