成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

mybatis 為什么每次插入的時(shí)候總會(huì)創(chuàng)建一個(gè)SqlSession?

sixgo / 2209人閱讀

摘要:?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> resources中 
              TransactionSynchronizationManager.bindResource(sessionFactory, holder);
              //將holder, sessionFactory的同步加入本地線程緩存中ThreadLocal> synchronizations 
              TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
              //設(shè)置當(dāng)前holder和當(dāng)前事務(wù)同步 
              holder.setSynchronizedWithTransaction(true);
              //holder 引用次數(shù)+1
             holder.requested();
          } else {
                if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
                    }
                } else {
                       throw new TransientDataAccessResourceException( "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
                }
          }
} else {
  if (LOGGER.isDebugEnabled()) {
    LOGGER.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
  }
}
} 補(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)目逐步深入了解Mybatis(四)

    摘要:相關(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...

    kuangcaibao 評(píng)論0 收藏0
  • Mybatis入門看這一篇就夠了

    摘要:什么是本是的一個(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,...

    livem 評(píng)論0 收藏0
  • MyBatis知識(shí)點(diǎn)整理

    摘要:得到用戶信息,將用戶信息存儲(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、 ...

    zhangqh 評(píng)論0 收藏0
  • Mybatis學(xué)習(xí)筆記(一)——基本CRUD操作

    摘要:將語(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...

    evin2016 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<