欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring 整合mybatis后用不上session緩存的原因分析

 更新時(shí)間:2017年02月16日 10:50:23   投稿:mrr  
因?yàn)橐恢庇胹pring整合了mybatis,所以很少用到mybatis的session緩存。什么原因呢?下面小編給大家介紹spring 整合mybatis后用不上session緩存的原因分析,需要的朋友可以參考下

因?yàn)橐恢庇胹pring整合了mybatis,所以很少用到mybatis的session緩存。 習(xí)慣是本地緩存自己用map寫(xiě)或者引入第三方的本地緩存框架ehcache,Guava

所以提出來(lái)糾結(jié)下

實(shí)驗(yàn)下(spring整合mybatis略,網(wǎng)上一堆),先看看mybatis級(jí)別的session的緩存

放出打印sql語(yǔ)句

configuration.xml 加入

<settings>
    <!-- 打印查詢(xún)語(yǔ)句 -->
    <setting name="logImpl" value="STDOUT_LOGGING" />
  </settings>

測(cè)試源代碼如下:

dao類(lèi) 

/**
 * 測(cè)試spring里的mybatis為啥用不上緩存
 *
 * @author 何錦彬 2017.02.15
 */
@Component
public class TestDao {
  private Logger logger = Logger.getLogger(TestDao.class.getName());
  @Autowired
  private SqlSessionTemplate sqlSessionTemplate;
  @Autowired
  private SqlSessionFactory sqlSessionFactory;
  /**
   * 兩次SQL
   *
   * @param id
   * @return
   */
  public TestDto selectBySpring(String id) {
    TestDto testDto = (TestDto) sqlSessionTemplate.selectOne("com.hejb.TestDto.selectByPrimaryKey", id);
    testDto = (TestDto) sqlSessionTemplate.selectOne("com.hejb.TestDto.selectByPrimaryKey", id);
    return testDto;
  }
  /**
   * 一次SQL
   *
   * @param id
   * @return
   */
  public TestDto selectByMybatis(String id) {
    SqlSession session = sqlSessionFactory.openSession();
    TestDto testDto = session.selectOne("com.hejb.TestDto.selectByPrimaryKey", id);
    testDto = session.selectOne("com.hejb.TestDto.selectByPrimaryKey", id);
    return testDto;
  }
}

測(cè)試service類(lèi)

@Component
public class TestService {
  @Autowired
  private TestDao testDao;
  /**
   * 未開(kāi)啟事務(wù)的spring Mybatis查詢(xún)
   */
  public void testSpringCashe() {
    //查詢(xún)了兩次SQL
    testDao.selectBySpring("1");
  }
  /**
   * 開(kāi)啟事務(wù)的spring Mybatis查詢(xún)
   */
  @Transactional
  public void testSpringCasheWithTran() {
    //spring開(kāi)啟事務(wù)后,查詢(xún)1次SQL
    testDao.selectBySpring("1");
  }
  /**
   * mybatis查詢(xún)
   */
  public void testCash4Mybatise() {
    //原生態(tài)mybatis,查詢(xún)了1次SQL
    testDao.selectByMybatis("1");
  }
}

輸出結(jié)果:

testSpringCashe()方法執(zhí)行了兩次SQL, 其它都是一次

源碼追蹤:

先看mybatis里的sqlSession

跟蹤到最后 調(diào)用到 org.apache.ibatis.executor.BaseExecutor的query方法

try {
   queryStack++;
   list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; //先從緩存中取
   if (list != null) {
    handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); //注意里面的key是CacheKey
   } else {
    list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
   }

貼下是怎么取出緩存數(shù)據(jù)的代碼

private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
  if (ms.getStatementType() == StatementType.CALLABLE) {
   final Object cachedParameter = localOutputParameterCache.getObject(key);//從localOutputParameterCache取出緩存對(duì)象
   if (cachedParameter != null && parameter != null) {
    final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
    final MetaObject metaParameter = configuration.newMetaObject(parameter);
    for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
     if (parameterMapping.getMode() != ParameterMode.IN) {
      final String parameterName = parameterMapping.getProperty();
      final Object cachedValue = metaCachedParameter.getValue(parameterName);
      metaParameter.setValue(parameterName, cachedValue);
     }
    }
   }
  }
 }

 

發(fā)現(xiàn)就是從localOutputParameterCache就是一個(gè)PerpetualCache, PerpetualCache維護(hù)了個(gè)map,就是session的緩存本質(zhì)了。

重點(diǎn)可以關(guān)注下面兩個(gè)累的邏輯

PerpetualCache , 兩個(gè)參數(shù), id和map

CacheKey,map中存的key,它有覆蓋equas方法,當(dāng)獲取緩存時(shí)調(diào)用.

這種本地map緩存獲取對(duì)象的缺點(diǎn),就我踩坑經(jīng)驗(yàn)(以前我也用map去實(shí)現(xiàn)的本地緩存),就是獲取的對(duì)象非clone的,返回的兩個(gè)對(duì)象都是一個(gè)地址

而在spring中一般都是用sqlSessionTemplate,如下

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:configuration.xml" />
    <property name="mapperLocations">
      <list>
        <value>classpath*:com/hejb/sqlmap/*.xml</value>
      </list>
    </property>
  </bean>
  <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="sqlSessionFactory" />
  </bean>

在SqlSessionTemplate中執(zhí)行SQL的session都是通過(guò)sqlSessionProxy來(lái),sqlSessionProxy的生成在構(gòu)造函數(shù)中賦值,如下:

this.sqlSessionProxy = (SqlSession) newProxyInstance(
    SqlSessionFactory.class.getClassLoader(),
    new Class[] { SqlSession.class },
    new SqlSessionInterceptor());

sqlSessionProxy通過(guò)JDK的動(dòng)態(tài)代理方法生成的一個(gè)代理類(lèi),主要邏輯在InvocationHandler對(duì)執(zhí)行的方法進(jìn)行了前后攔截,主要邏輯在invoke中,包好了每次執(zhí)行對(duì)sqlsesstion的創(chuàng)建,common,關(guān)閉

代碼如下:

private class SqlSessionInterceptor implements InvocationHandler {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   // 每次執(zhí)行前都創(chuàng)建一個(gè)新的sqlSession
   SqlSession sqlSession = getSqlSession(
     SqlSessionTemplate.this.sqlSessionFactory,
     SqlSessionTemplate.this.executorType,
     SqlSessionTemplate.this.exceptionTranslator);
   try {
   // 執(zhí)行方法
    Object result = method.invoke(sqlSession, args);
    if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
     // force commit even on non-dirty sessions because some databases require
     // a commit/rollback before calling close()
     sqlSession.commit(true);
    }
    return result;
   } catch (Throwable t) {
    Throwable unwrapped = unwrapThrowable(t);
    if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
     // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
     closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
     sqlSession = null;
     Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
     if (translated != null) {
      unwrapped = translated;
     }
    }
    throw unwrapped;
   } finally {
    if (sqlSession != null) {
     closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
    }
   }
  }
 }

因?yàn)槊看味歼M(jìn)行創(chuàng)建,所以就用不上sqlSession的緩存了.

對(duì)于開(kāi)啟了事務(wù)為什么可以用上呢, 跟入getSqlSession方法

如下:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
  notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
  notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
  SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
  // 首先從SqlSessionHolder里取出session
  SqlSession session = sessionHolder(executorType, holder);
  if (session != null) {
   return session;
  }
  if (LOGGER.isDebugEnabled()) {
   LOGGER.debug("Creating a new SqlSession");
  }
  session = sessionFactory.openSession(executorType);
  registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
  return session;
 }

在里面維護(hù)了個(gè)SqlSessionHolder,關(guān)聯(lián)了事務(wù)與session,如果存在則直接取出,否則則新建個(gè)session,所以在有事務(wù)的里,每個(gè)session都是同一個(gè),故能用上緩存了

以上所述是小編給大家介紹的spring 整合mybatis后用不上session緩存的原因分析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中HashMap和HashSet的高效使用技巧分享

    Java中HashMap和HashSet的高效使用技巧分享

    這篇文章主要為大家詳細(xì)介紹了Java中HashMap和HashSet的高效使用技巧,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • 詳解Spring Boot Oauth2緩存UserDetails到Ehcache

    詳解Spring Boot Oauth2緩存UserDetails到Ehcache

    這篇文章主要介紹了詳解Spring Boot Oauth2緩存UserDetails到Ehcache,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Java中的OkHttp使用教程

    Java中的OkHttp使用教程

    OkHttp是目前非常火的網(wǎng)絡(luò)庫(kù),OKHttp與HttpClient類(lèi)似,也是一個(gè)Http客戶(hù)端,提供了對(duì)?HTTP/2?和?SPDY?的支持,并提供了連接池,GZIP?壓縮和?HTTP?響應(yīng)緩存功能,本文重點(diǎn)給大家介紹Java?OkHttp使用,感興趣的朋友一起看看吧
    2022-04-04
  • 淺談Java并發(fā)之同步器設(shè)計(jì)

    淺談Java并發(fā)之同步器設(shè)計(jì)

    這篇文章主要介紹Java并發(fā)之同步器設(shè)計(jì),本文以記錄方式并發(fā)編程中同步器設(shè)計(jì)的一些共性特征。并簡(jiǎn)單介紹了Java中的AQS,需要的朋友可以參考一下文章的詳細(xì)內(nèi)容
    2021-10-10
  • spring boot ${}占位符不起作用的解決方案

    spring boot ${}占位符不起作用的解決方案

    這篇文章主要介紹了spring boot ${}占位符不起作用的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • mybatis中的異常BindingException詳解

    mybatis中的異常BindingException詳解

    這篇文章主要介紹了mybatis中的異常BindingException詳解,此異常是mybatis中拋出的,意思是使用的這個(gè)方法找到,但是因?yàn)閙apperScan()已經(jīng)掃描到了Mapper類(lèi)了,在綁定Mapper.xml時(shí)沒(méi)有綁定到導(dǎo)致的,需要的朋友可以參考下
    2024-01-01
  • SpringBoot項(xiàng)目實(shí)用功能之實(shí)現(xiàn)自定義參數(shù)解析器

    SpringBoot項(xiàng)目實(shí)用功能之實(shí)現(xiàn)自定義參數(shù)解析器

    這篇文章主要介紹了SpringBoot項(xiàng)目實(shí)用功能之實(shí)現(xiàn)自定義參數(shù)解析器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 使用Easyexcel實(shí)現(xiàn)不同場(chǎng)景的數(shù)據(jù)導(dǎo)出功能

    使用Easyexcel實(shí)現(xiàn)不同場(chǎng)景的數(shù)據(jù)導(dǎo)出功能

    這篇文章主要為大家詳細(xì)介紹了如何在不同場(chǎng)景下使用Easyexcel實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • SpringBoot 過(guò)濾器, 攔截器, 監(jiān)聽(tīng)器的具體使用

    SpringBoot 過(guò)濾器, 攔截器, 監(jiān)聽(tīng)器的具體使用

    本文主要介紹了SpringBoot 過(guò)濾器, 攔截器, 監(jiān)聽(tīng)器的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • SpringBoot中的JPA(Java?Persistence?API)詳解

    SpringBoot中的JPA(Java?Persistence?API)詳解

    這篇文章主要介紹了SpringBoot中的JPA(Java?Persistence?API)詳解,JPA用于將?Java?對(duì)象映射到關(guān)系型數(shù)據(jù)庫(kù)中,它提供了一種面向?qū)ο蟮姆绞絹?lái)操作數(shù)據(jù)庫(kù),使得開(kāi)發(fā)者可以更加方便地進(jìn)行數(shù)據(jù)持久化操作,需要的朋友可以參考下
    2023-07-07

最新評(píng)論