摘要:?jiǎn)栴}記錄工作環(huán)境是使用使用用的,在一次調(diào)試中。發(fā)現(xiàn)每一次插入一條數(shù)據(jù)都會(huì)創(chuàng)建一個(gè)。如圖圖問題可能的原因原因分析沒有使用緩存因?yàn)檫@個(gè)是插入,不是查詢,所以這里不存在什么緩存的問題。但是在在關(guān)閉的時(shí)候也是做了判斷。
問題記錄:
工作環(huán)境是使用spring boot,使用用的mybatis,在一次調(diào)試中。發(fā)現(xiàn)每一次插入一條 數(shù)據(jù)都會(huì)創(chuàng)建一個(gè)SqlSession。如圖:
圖1:
問題可能的原因: 原因分析:#1 沒有使用緩存因?yàn)檫@個(gè)是插入,不是查詢,所以這里不存在什么緩存的問題。
后來百度了一波,網(wǎng)上說是沒有使用事務(wù)。加上@Transactional
圖2:
發(fā)現(xiàn)“Creating a new SqlSession”這兩個(gè)煩人的東西居然還在。不管了,直接分析源碼
直接分析源碼,老子還不信了,搞不定你我還混什么: 1.開啟debug 2.打上斷點(diǎn)
圖3:
發(fā)現(xiàn)session為空
繼續(xù)走... 圖2 #分析public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { //從從前線程的threadLocal 中獲取sqlSessionHolder SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); //調(diào)用靜態(tài)方法sessionHoler 判斷是否存在符合要求的sqlSession SqlSession session = sessionHolder(executorType, holder); // 判斷當(dāng)前sqlSessionHolder 中是否持有sqlSession (即當(dāng)前操作是否在事務(wù)當(dāng)中) if (session != null) { //如果持有sqlSesison 的引用,則直接獲取 return session; } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Creating a new SqlSession"); } //獲取新的sqlSession 對(duì)象。這里由sessionFacory產(chǎn)生的defaultSqlSession session = sessionFactory.openSession(executorType); //判斷判斷,當(dāng)前是否存在事務(wù),將sqlSession 綁定到sqlSessionHolder 中,并放到threadLoacl 當(dāng)中 registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session); return session; }圖3 #分析
private static SqlSession sessionHolder(ExecutorType executorType, SqlSessionHolder holder) { SqlSession session = null; if (holder != null && holder.isSynchronizedWithTransaction()) { //hodler保存的執(zhí)行類型和獲取SqlSession的執(zhí)行類型不一致,就會(huì)拋出異常,也就是說在同一個(gè)事務(wù)中,執(zhí)行類型不能變化,原因就是同一個(gè)事務(wù)中同一個(gè)sqlSessionFactory創(chuàng)建的sqlSession會(huì)被重用 if (holder.getExecutorType() != executorType) { throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"); } //增加該holder,也就是同一事務(wù)中同一個(gè)sqlSessionFactory創(chuàng)建的唯一sqlSession,其引用數(shù)增加,被使用的次數(shù)增加 holder.requested(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction"); } //返回sqlSession session = holder.getSqlSession(); } return session; }當(dāng)然,這里還少了一個(gè)注冊(cè)的方法,貼上:
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator, SqlSession session) { SqlSessionHolder holder; //判斷事務(wù)是否存在 if (TransactionSynchronizationManager.isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); //加載環(huán)境變量,判斷注冊(cè)的事務(wù)管理器是否是SpringManagedTransaction,也就是Spring管理事務(wù) if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registering transaction synchronization for SqlSession [" + session + "]"); } holder = new SqlSessionHolder(session, executorType, exceptionTranslator); //如果當(dāng)前回話處在事務(wù)當(dāng)中,則將holder 綁定到ThreadLocal 中 //以sessionFactory為key,hodler為value,加入到TransactionSynchronizationManager管理的本地緩存ThreadLocal} 補(bǔ)充
sqlSessionHolder 繼承了spring的ResourceHolderSupport
public abstract class ResourceHolderSupport implements ResourceHolder { //事務(wù)是否開啟private boolean synchronizedWithTransaction = false; private boolean rollbackOnly = false; private Date deadline; // 引用次數(shù) private int referenceCount = 0; private boolean isVoid = false; }
在sqlSession 關(guān)閉session 的時(shí)候, 使用了工具了sqlSessionUtils的closeSqlSession 方法。sqlSessionHolder 也是做了判斷,如果回話在事務(wù)當(dāng)中,則減少引用次數(shù),沒有真實(shí)關(guān)閉session。如果回話不存在事務(wù),則直接關(guān)閉session
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) { notNull(session, NO_SQL_SESSION_SPECIFIED); notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); //如果holder 中持有sqlSession 的引用,(即會(huì)話存在事務(wù)) if ((holder != null) && (holder.getSqlSession() == session)) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Releasing transactional SqlSession [" + session + "]"); } //每當(dāng)一個(gè)sqlSession 執(zhí)行完畢,則減少holder 持有引用的次數(shù) holder.released(); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Closing non transactional SqlSession [" + session + "]"); } //如果回話中,不存在事務(wù),則直接關(guān)閉session session.close(); } }
到了這一步,問題已經(jīng)很明顯了。
出現(xiàn)原因 與 分析SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); 這一句:他從從前線程的threadLocal 中獲取sqlSessionHolder。但是在在sqlSession 關(guān)閉session 的時(shí)候,sqlSessionHolder也是做了判斷。如果會(huì)話在事務(wù)中,就減少引用次數(shù),沒有真實(shí)關(guān)閉session。如果會(huì)話不存在事務(wù),則直接關(guān)閉session。也就是說,必須開啟事務(wù),但這個(gè)問題好像只是插入了一下,事務(wù)已經(jīng)執(zhí)行完成了,下一次插入的時(shí)候,由于上一個(gè)事務(wù)執(zhí)行完成了, 如果不存在holder或沒有被事務(wù)鎖定,則會(huì)創(chuàng)建新的sqlSession,即 Creating a new SqlSession,通過sessionFactory.openSession()方法。如果會(huì)話不存在事務(wù),就直接把session關(guān)閉了,同時(shí),也減少了引用次數(shù)。
換一句話來說:如果在插入的代碼塊中,再加上一個(gè)查詢的代碼,或者再插入一條數(shù)據(jù)的代碼,這樣就不會(huì)出現(xiàn)Creating a new SqlSession這個(gè)煩人的家伙。好了,祝大家好運(yùn)?。?!
引用:SqlSessionHolder作用
如果有侵權(quán),馬上刪除
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69739.html
摘要:相關(guān)閱讀通過項(xiàng)目逐步深入了解一通過項(xiàng)目逐步深入了解二通過項(xiàng)目逐步深入了解三本項(xiàng)目所有代碼及文檔都托管在地址延遲加載什么是延遲加載可以實(shí)現(xiàn)高級(jí)映射使用實(shí)現(xiàn)一對(duì)一及一對(duì)多映射,具備延遲加載功能。一級(jí)緩存是級(jí)別的緩存。 相關(guān)閱讀: 1、通過項(xiàng)目逐步深入了解Mybatis 2、通過項(xiàng)目逐步深入了解Mybatis 3、通過項(xiàng)目逐步深入了解Mybatis 本項(xiàng)目所有代碼及文檔都托管在 Github...
摘要:什么是本是的一個(gè)開源項(xiàng)目年這個(gè)項(xiàng)目由遷移到了,并且改名為。如下的代碼,如果有多個(gè)條件的話,那么拼接起來很容易出錯(cuò)查詢語(yǔ)句根據(jù)是否為來判斷是否是條件查詢。而如果我們使用的話,就可以免去查詢助手類了。 什么是MyBatis MyBatis 本是apache的一個(gè)開源項(xiàng)目iBatis, 2010年這個(gè)項(xiàng)目由apache software foundation 遷移到了google code,...
摘要:得到用戶信息,將用戶信息存儲(chǔ)到一級(jí)緩存中。如果中間去執(zhí)行操作執(zhí)行插入更新刪除,則會(huì)清空中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。 基礎(chǔ): 1、 概念:Java當(dāng)中的一個(gè)持久層框架。2、 特點(diǎn)、優(yōu)勢(shì):(1)把java代碼和SQL代碼做了一個(gè)完全分離。(2)良好支持復(fù)雜對(duì)象的映射(輸入映射、輸出映射)(3)使用動(dòng)態(tài)SQL,可以預(yù)防SQL注入。3、 ...
摘要:將語(yǔ)句硬編碼到代碼中,修改語(yǔ)句需要重新編譯代碼設(shè)想使用配置文件配置。從結(jié)果集中遍歷數(shù)據(jù)的時(shí)候存在硬編碼。表示一個(gè)拼接符號(hào),會(huì)引用注入,所以不建議使用。和表示查詢出一條記錄進(jìn)行映射。 MyBatis是什么 mybatis是托管在github上的ORM框架,讓程序員將主要精力放在SQL上,通過mybatis提供映射方式,自由靈活(SQL的可定制性較高,半自動(dòng)化)生成滿足需求的SQL語(yǔ)句。m...
閱讀 2194·2021-11-24 09:38
閱讀 3255·2021-11-08 13:27
閱讀 3095·2021-09-10 10:51
閱讀 3162·2019-08-29 12:20
閱讀 674·2019-08-28 18:28
閱讀 3470·2019-08-26 11:53
閱讀 2719·2019-08-26 11:46
閱讀 1527·2019-08-26 10:56