1. 數(shù)據(jù)庫(kù)連接池為什么要用threadlocal呢?不用會(huì)怎樣?

        共 2172字,需瀏覽 5分鐘

         ·

        2021-05-28 18:30

        作者 | 奔跑的烏龜

        來源 | blog.csdn.net/qq_42405666/article/details/108258820


        這個(gè)問題我疑問了很久很久,主要如下截圖。

        我先說為什么引入threadlocal,其實(shí)是為了解決數(shù)據(jù)庫(kù)事務(wù),而事務(wù)是和連接有關(guān)的,每個(gè)連接對(duì)應(yīng)一個(gè)事務(wù),多個(gè)連接的事務(wù)是不一樣的,先大概了解一下,往下看??

        本人是在學(xué)threadlocal的時(shí)候,網(wǎng)上大部分人都是說數(shù)據(jù)庫(kù)連接池是典型的用了threadloca的例子,然后我就又查數(shù)據(jù)庫(kù)連接池和threadloca的關(guān)系,但是,99%都說threadlocal是為了在并發(fā)的情況下,為了保證線程安全,創(chuàng)建了副本什么的,其實(shí)這只是threadlocal的用法之一,它還有個(gè)用法就是確保同一線程之間參數(shù)傳遞的方便(扯遠(yuǎn)了)

        回歸正題,還是拿上面的圖來說事。。。。

        我只講兩個(gè)關(guān)鍵點(diǎn),明白人一看就懂:

        1、兩者有根本性的區(qū)別,用處不一樣!

        連接池是緩存并托管數(shù)據(jù)庫(kù)連接,主要是為了提高性能。

        而ThreadLocal緩存連接,是為了把同一個(gè)數(shù)據(jù)庫(kù)連接“分享”給同一個(gè)線程的不同調(diào)用方法。(不管調(diào)用哪個(gè)方法,都是使用的同一個(gè)連接,方便進(jìn)行“跨方法”的事務(wù)控制)

        舉個(gè)栗子:

        如果一個(gè)請(qǐng)求中涉及多個(gè) DAO 操作,而如果這些DAO中的Connection都是獨(dú)立的話,就沒有辦法完成一個(gè)事務(wù)。但是如果DAO 中的 Connection 是從 ThreadLocal 中獲得的(意味著都是同一個(gè)對(duì)象), 那么這些 DAO 就會(huì)被納入到同一個(gè) Connection 之下。

        2、重點(diǎn)要理解“連接池”。

        連接池里面有一定數(shù)量的連接資源,比如最大20個(gè)連接。

        題外話:如果直接通過 Java原生API 獲取“直連”的話:

        底層方法一般都是這樣寫的:

        java.sql.DriverManager.getConnection(url, props);

        java.sql.Driver.connect(url, props);

        特點(diǎn)是:要傳入url、用戶名和密碼等信息)

        這種方式,肯定就沒有使用數(shù)據(jù)庫(kù)連接池。

        使用數(shù)據(jù)庫(kù)連接池,通常都是得到一個(gè)所謂的javax.sql.DataSource[接口]的實(shí)例對(duì)象,它里面包含了Connection,并且數(shù)據(jù)庫(kù)連接池工具類(比如C3P0、JNDI、DBCP等),肯定是重新定義了getConnection、closeConnection等方法,所以你每次得到的Connection,幾乎都不是新建立的連接(而是已經(jīng)建立好并放到緩存里面的連接),你調(diào)用closeConnection方法,也不是真正的關(guān)閉連接(一般都是起到一個(gè)標(biāo)識(shí)作用,標(biāo)識(shí)當(dāng)前連接已經(jīng)使用完畢,歸還給連接池,讓這個(gè)連接處于待分配狀態(tài))

        PS:所以說:使用數(shù)據(jù)庫(kù)連接池時(shí),還是要顯式的調(diào)用數(shù)據(jù)庫(kù)連接池API提供的關(guān)閉連接的方法。

        理解一下這句話:

        不同的線程在同一個(gè)時(shí)間( 或者 同一個(gè)線程在多個(gè)地方)從連接池中拿到的Connection,肯定不是同一個(gè)連接。(反過來講:不同時(shí)間的兩個(gè)線程,一前一后,則有可能拿到同一個(gè)連接)

        總結(jié):

        再好好理解一下上面的一段話,我再最后解釋一下。。。

        • 首先,我們?yōu)榱吮苊鈫我粩?shù)據(jù)庫(kù)連接的創(chuàng)建和關(guān)閉耗費(fèi)時(shí)間和性能,引入了數(shù)據(jù)庫(kù)連接池,提前創(chuàng)建好了n條連接放入池中,如果是單線程情況下,那這樣挺好的
        • 那如果是多線程情況下呢?還是上面那段話,假設(shè)同一時(shí)間多個(gè)線程從數(shù)據(jù)庫(kù)連接池獲取連接,那肯定拿的是不同的連接,我當(dāng)前線程和別的線程拿的連接不一樣,那我當(dāng)前在crud的時(shí)候,不在一個(gè)事務(wù)之內(nèi)。
        • 假設(shè)不同時(shí)間的多個(gè)線程要從數(shù)據(jù)庫(kù)連接池拿連接,那這個(gè)時(shí)候就可能拿到的是同一個(gè)連接了,那我多個(gè)線程線程拿到的是同一個(gè)連接,也就是說在多個(gè)線程在同一個(gè)事務(wù)之內(nèi),線程a執(zhí)行了插入還沒來得及提交,線程b此時(shí)來了個(gè)更新,在線程a還未操作完之前,線程b更新完了后,直接把連接給close了,線程a插了一半發(fā)現(xiàn)插不了了。。。此時(shí)肯定在想,這?是誰(shuí)在搞我。
        • 為了確保不同時(shí)間多個(gè)線程可能拿到的是同一個(gè)連接,那么此時(shí)threadlocal閃亮登場(chǎng),就算我拿的是“同一個(gè)連接”,在引入了threadlocal后,每個(gè)線程之間都會(huì)創(chuàng)建獨(dú)立的連接副本,將collection各自copy一份,這樣就互相不干擾了。

        以上只是我的個(gè)人見解。歡迎在留言區(qū)來波評(píng)論交流溝通!

        1、Intellij IDEA這樣 配置注釋模板,讓你瞬間高出一個(gè)逼格!
        2、吊炸天的 Docker 圖形化工具 Portainer,必須推薦給你!
        3、最牛逼的 Java 日志框架,性能無敵,橫掃所有對(duì)手!
        4、把Redis當(dāng)作隊(duì)列來用,真的合適嗎?
        5、驚呆了,Spring Boot居然這么耗內(nèi)存!你知道嗎?
        6、全網(wǎng)最全 Java 日志框架適配方案!還有誰(shuí)不會(huì)?
        7、Spring中毒太深,離開Spring我居然連最基本的接口都不會(huì)寫了

        點(diǎn)分享

        點(diǎn)收藏

        點(diǎn)點(diǎn)贊

        點(diǎn)在看

        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 色欲综合插插 | 日韩黄片 | 午夜爱爱免费视频 | 成人免费黄色视频在线观看 | 国产91无码网站在线观看 |