您好,登錄后才能下訂單哦!
為何一定要關(guān)閉mybatis中的SqlSession,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
今天在使用mybatis查詢數(shù)據(jù)時,出現(xiàn)了一個很奇怪的問題。同一條sql語句,查詢時快時慢,并且有一定的規(guī)律性,大概每10次查詢中有一次會特別特別的慢,快的只需要1ms,慢的要20000ms,sql代碼及快慢時間截圖如下:
select fknr from jq_fkqk where jjxh = ?
通過日志打印mybatis查詢信息時,我觀察到特別慢的時候,并不是因為它查詢很慢,而是因為它需要等待一段很長的時間才開始:
==> Preparing: select fknr from jq_fkqk where jjxh = ?
說明時間長就出現(xiàn)在這里,這個等待的時間。
為什么會要等待這么久呢?我自然而然的看了一下上一次查詢的函數(shù),發(fā)現(xiàn)在函數(shù)里面沒有session.close(),把這一句加上,問題就解決了,速度就飛快了。
我本來想查看官方文檔,查看原因,但是沒找到,只能結(jié)合我自己的理解來分析一下。SqlSession是通過SqlSessionFactory來構(gòu)造的,相當(dāng)于維護(hù)一個連接池,當(dāng)我們不停的進(jìn)行查詢的時候,由于沒有關(guān)閉連接,導(dǎo)致與數(shù)據(jù)庫的連接數(shù)量達(dá)到了一個上限(可能連接池有最大連接數(shù),但是我們有找到文檔)。
到達(dá)上限之后,再次請求查詢時,F(xiàn)actory說沒有連接了,讓你先等一下,它先去判斷哪些SqlSession已經(jīng)沒有人使用了(類似于垃圾回收機(jī)制),然后調(diào)用相應(yīng)的進(jìn)程去自動關(guān)閉沒用的session連接,注意調(diào)用進(jìn)程可是要排隊的,也要耗時間。
等關(guān)閉了沒有用的session之后,F(xiàn)actory通知你,有空閑的session了,開始準(zhǔn)備你的查詢吧,所有才會有等待很長一段時間才出現(xiàn):
==> Preparing: select fknr from jq_fkqk where jjxh = ?
這純屬我自己的理解,但是重點還是表達(dá)出來了,就是Mybatis中的session一定要手動去關(guān)閉它,session.close(),不然會占著資源,導(dǎo)致性能下降?。?!
SqlSession中存儲的是編譯好的sql語句,這些sql語句是mybatis配置文件讀取mapper.xml文件生成的,將sql語句存儲到SqlSessionFactory和SqlSession中。封裝了對數(shù)據(jù)庫的操作,如:查詢、插入、更新、刪除等。
通過SqlSessionFactory創(chuàng)建SqlSession,而SqlSessionFactory是通過SqlSessionFactoryBuilder加載配置文件進(jìn)行創(chuàng)建。在開發(fā)中SqlSession在每次使用完都要進(jìn)行關(guān)閉,使用時創(chuàng)建,也就是多例的,線程安全。SqlSessionFactory在整個類中只有一個對象,也就是單例的,單例的線程不安全。
SqlSessionFactoryBuilder用于創(chuàng)建SqlSessionFacoty,SqlSessionFacoty一旦創(chuàng)建完成就不需要SqlSessionFactoryBuilder了,因為SqlSession是通過SqlSessionFactory生產(chǎn),所以可以將SqlSessionFactoryBuilder當(dāng)成一個工具類使用,最佳使用范圍是方法范圍即方法體內(nèi)局部變量。
SqlSessionFactory是一個接口,接口中定義了openSession的不同重載方法,SqlSessionFactory的最佳使用范圍是整個應(yīng)用運行期間,一旦創(chuàng)建后可以重復(fù)使用,通常以單例模式管理SqlSessionFactory。
SqlSession是一個面向用戶的接口, sqlSession中定義了數(shù)據(jù)庫操作,默認(rèn)使用DefaultSqlSession實現(xiàn)類。
執(zhí)行過程如下:
1、加載數(shù)據(jù)源等配置信息
Environment environment = configuration.getEnvironment();
2、創(chuàng)建數(shù)據(jù)庫鏈接
3、創(chuàng)建事務(wù)對象
4、創(chuàng)建Executor,SqlSession所有操作都是通過Executor完成,mybatis源碼如下:
if (ExecutorType.BATCH == executorType) { executor = newBatchExecutor(this, transaction); } elseif (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor, autoCommit); }
SqlSession的實現(xiàn)類即DefaultSqlSession,此對象中對操作數(shù)據(jù)庫實質(zhì)上用的是Executor
每個線程都應(yīng)該有它自己的SqlSession實例。SqlSession的實例不能共享使用,它也是線程不安全的。因此最佳的范圍是請求或方法范圍。絕對不能將SqlSession實例的引用放在一個類的靜態(tài)字段或?qū)嵗侄沃小?/p>
打開一個 SqlSession;使用完畢就要關(guān)閉它。通常把這個關(guān)閉操作放到 finally 塊中以確保每次都能執(zhí)行關(guān)閉。如下:
SqlSession session = sqlSessionFactory.openSession(); try { // do work } finally { session.close(); }
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。