日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

解決spring結合mybatis時一級緩存失效的問題

瀏覽:50日期:2023-07-30 17:03:04

之前了解到mybatis的一級緩存是默認開啟的,作用域是sqlSession,是基 HashMap的本地緩存。不同的SqlSession之間的緩存數據區域互不影響。

當進行select、update、delete操作后并且commit事物到數據庫之后,sqlSession中的Cache自動被清空

<setting name='localCacheScope' value='SESSION'/>

結論

spring結合mybatis后,一級緩存作用:

在未開啟事物的情況之下,每次查詢,spring都會關閉舊的sqlSession而創建新的sqlSession,因此此時的一級緩存是沒有啟作用的

在開啟事物的情況之下,spring使用threadLocal獲取當前資源綁定同一個sqlSession,因此此時一級緩存是有效的

案例

情景一:未開啟事物

@Service('countryService')public class CountryService { @Autowired private CountryDao countryDao; // @Transactional 未開啟事物 public void noTranSactionMethod() throws JsonProcessingException { CountryDo countryDo = countryDao.getById(1L); CountryDo countryDo1 = countryDao.getById(1L); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(countryDo); String json1 = objectMapper.writeValueAsString(countryDo1); System.out.println(json); System.out.println(json1); }}

測試案例:

@Testpublic void transactionTest() throws JsonProcessingException { countryService.noTranSactionMethod();}

結果:

[DEBUG] SqlSessionUtils Creating a new SqlSession[DEBUG] SpringManagedTransaction JDBC Connection [com.mysql.jdbc.JDBC4Connection@14a54ef6] will not be managed by Spring[DEBUG] getById ==> Preparing: SELECT * FROM country WHERE country_id = ?[DEBUG] getById ==> Parameters: 1(Long)[DEBUG] getById <== Total: 1[DEBUG] SqlSessionUtils Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3359c978][DEBUG] SqlSessionUtils Creating a new SqlSession[DEBUG] SqlSessionUtils SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2aa27288] was not registered for synchronization because synchronization is not active[DEBUG] SpringManagedTransaction JDBC Connection [com.mysql.jdbc.JDBC4Connection@14a54ef6] will not be managed by Spring[DEBUG] getById ==> Preparing: SELECT * FROM country WHERE country_id = ?[DEBUG] getById ==> Parameters: 1(Long)[DEBUG] getById <== Total: 1[DEBUG] SqlSessionUtils Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2aa27288]{'countryId':1,'country':'Afghanistan','lastUpdate':'2006-02-15 04:44:00.0'}{'countryId':1,'country':'Afghanistan','lastUpdate':'2006-02-15 04:44:00.0'}

可以看到,兩次查詢,都創建了新的sqlSession,并向數據庫查詢,此時緩存并沒有起效果

情景二: 開啟事物

打開@Transactional注解:

@Service('countryService')public class CountryService { @Autowired private CountryDao countryDao; @Transactional public void noTranSactionMethod() throws JsonProcessingException { CountryDo countryDo = countryDao.getById(1L); CountryDo countryDo1 = countryDao.getById(1L); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(countryDo); String json1 = objectMapper.writeValueAsString(countryDo1); System.out.println(json); System.out.println(json1); }}

使用原來的測試案例,輸出結果:

[DEBUG] SqlSessionUtils Creating a new SqlSession[DEBUG] SqlSessionUtils Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@109f5dd8][DEBUG] SpringManagedTransaction JDBC Connection [com.mysql.jdbc.JDBC4Connection@55caeb35] will be managed by Spring[DEBUG] getById ==> Preparing: SELECT * FROM country WHERE country_id = ?[DEBUG] getById ==> Parameters: 1(Long)[DEBUG] getById <== Total: 1[DEBUG] SqlSessionUtils Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@109f5dd8]// 從當前事物中獲取sqlSession[DEBUG] SqlSessionUtils Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@109f5dd8] from current transaction[DEBUG] SqlSessionUtils Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@109f5dd8]{'countryId':1,'country':'Afghanistan','lastUpdate':'2006-02-15 04:44:00.0'}{'countryId':1,'country':'Afghanistan','lastUpdate':'2006-02-15 04:44:00.0'}

可以看到,兩次查詢,只創建了一次sqlSession,說明一級緩存起作用了

跟蹤源碼

從SqlSessionDaoSupport作為路口,這個類在mybatis-spring包下,sping為sqlSession做了代理

public abstract class SqlSessionDaoSupport extends DaoSupport { private SqlSession sqlSession; private boolean externalSqlSession; public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (!this.externalSqlSession) { this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); } } //....omit}

創建了SqlSessionTemplate后,在SqlSessionTemplate中:

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, 'Property ’sqlSessionFactory’ is required'); notNull(executorType, 'Property ’executorType’ is required'); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; //代理了SqlSession this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor());}

再看SqlSessionInterceptor,SqlSessionInterceptor是SqlSessionTemplate的內部類:

public class SqlSessionTemplate implements SqlSession, DisposableBean { // ...omit.. private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SqlSession sqlSession = getSqlSession( SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); try { Object result = method.invoke(sqlSession, args); //如果尚未開啟事物(事物不是由spring來管理),則sqlSession直接提交 if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() // 手動commit 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 { //一般情況下,默認都是關閉sqlSession if (sqlSession != null) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } }}

再看getSqlSession方法,這個方法是在SqlSessionUtils.java中的:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED); //獲取holder SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); //從sessionHolder中獲取SqlSession SqlSession session = sessionHolder(executorType, holder); if (session != null) { return session; } if (LOGGER.isDebugEnabled()) { LOGGER.debug('Creating a new SqlSession'); } //如果sqlSession不存在,則創建一個新的 session = sessionFactory.openSession(executorType); //將sqlSession注冊在sessionHolder中 registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session); return session;}private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator, SqlSession session) { SqlSessionHolder holder; //在開啟事物的情況下 if (TransactionSynchronizationManager.isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); //由spring來管理事物的情況下 if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if (LOGGER.isDebugEnabled()) { LOGGER.debug('Registering transaction synchronization for SqlSession [' + session + ']'); } holder = new SqlSessionHolder(session, executorType, exceptionTranslator); //將sessionFactory綁定在sessionHolde相互綁定 TransactionSynchronizationManager.bindResource(sessionFactory, holder); TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(true); 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'); } }

再看TransactionSynchronizationManager.bindResource的方法:

public abstract class TransactionSynchronizationManager { //omit... private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>('Transactional resources'); // key:sessionFactory, value:SqlSessionHolder(Connection) public static void bindResource(Object key, Object value) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Assert.notNull(value, 'Value must not be null'); //從threadLocal類型的resources中獲取與當前線程綁定的資源,如sessionFactory,Connection等等 Map<Object, Object> map = resources.get(); // set ThreadLocal Map if none found if (map == null) { map = new HashMap<Object, Object>(); resources.set(map); } Object oldValue = map.put(actualKey, value); // Transparently suppress a ResourceHolder that was marked as void... if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) { oldValue = null; } if (oldValue != null) { throw new IllegalStateException('Already value [' + oldValue + '] for key [' + actualKey + '] bound to thread [' + Thread.currentThread().getName() + ']'); } if (logger.isTraceEnabled()) { logger.trace('Bound value [' + value + '] for key [' + actualKey + '] to thread [' + Thread.currentThread().getName() + ']'); } }}

這里可以看到,spring是如何做到獲取到的是同一個SqlSession,前面的長篇大論,就是為使用ThreadLocal將當前線程綁定創建SqlSession相關的資源,從而獲取同一個sqlSession

以上這篇解決spring結合mybatis時一級緩存失效的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩免费av| 久久不见久久见中文字幕免费| 国产精品色在线网站| 日韩欧美2区| 玖玖精品视频| 久久久久网站| 神马午夜久久| 久久久精品久久久久久96| 亚洲一级少妇| 国产99久久| 美女网站一区| 亚洲精品1区| 一区二区三区网站| 香蕉久久一区| 欧美在线精品一区| 日本成人手机在线| 青青草精品视频| 国产精品天天看天天狠| 国产精品115| 国产在视频一区二区三区吞精| 国产伦乱精品| 麻豆视频观看网址久久| 国产不卡av一区二区| 国产传媒在线观看| 中文字幕系列一区| 红桃视频国产一区| 亚洲美女91| 国产精品115| 老牛影视精品| 欧美成人国产| 男人操女人的视频在线观看欧美| 亚洲乱亚洲高清| 国产精品一区二区三区www| 国产一区二区三区天码| 天堂资源在线亚洲| 国产视频亚洲| 日产欧产美韩系列久久99| 国产欧美自拍| 国产亚洲一区二区手机在线观看 | 欧美特黄一级| 蜜臀av亚洲一区中文字幕| 国产精品中文字幕制服诱惑| 国内精品麻豆美女在线播放视频| 99久久久国产精品美女| 激情婷婷久久| 日韩精品免费视频人成| 精品三级av| 久久高清一区| 麻豆成人综合网| 91久久久精品国产| 国产免费av国片精品草莓男男 | 亚洲午夜黄色| 国产日本久久| 久久在线免费| 国产精品日本一区二区不卡视频| 精品丝袜在线| 日韩激情综合| 高清在线一区| 亚洲影视一区| 水蜜桃久久夜色精品一区| 午夜久久影院| 欧美91在线| 一区视频在线| 精品久久久中文字幕| 日韩视频免费| 久久这里只有精品一区二区| 亚洲精品网址| 精品国产a一区二区三区v免费| 在线一区免费观看| 精品久久免费| 日本91福利区| 五月天综合网站| 国产欧美一区二区三区国产幕精品 | 国产欧美日韩精品一区二区免费| 久久久久91| 国产精品中文字幕亚洲欧美| 日韩avvvv在线播放| 日本一区二区中文字幕| 三级久久三级久久久| 激情欧美一区二区三区| 亚洲一二三区视频| 日韩美女精品| 99xxxx成人网| 日韩福利视频导航| 欧美成人aaa| 欧美国产极品| 99视频精品| 亚洲最新av| 日韩免费小视频| 国内亚洲精品| 精品亚洲自拍| 亚洲一区二区三区四区电影| 精品国产午夜| 国产精品一区二区免费福利视频 | 欧美久久天堂| 国产精品羞羞答答在线观看| 中文字幕日韩亚洲| 欧美不卡在线| 亚洲1234区| 九九久久国产| 欧美久久一区二区三区| 蜜桃av一区二区| 国精品一区二区| а√天堂8资源中文在线| 欧美一区=区三区| 麻豆亚洲精品| 欧美va亚洲va日韩∨a综合色| 精品视频一区二区三区在线观看 | 国产亚洲高清在线观看| 亚洲丝袜啪啪| 国产精品毛片在线看| 99国产精品一区二区| 国产不卡人人| 日本а中文在线天堂| 免费视频一区二区三区在线观看| 日欧美一区二区| 一区二区91| 一区二区国产在线观看| 黄色日韩在线| 亚洲午夜黄色| 国产精品蜜芽在线观看| 久久婷婷国产| 免费亚洲婷婷| 久久精品天堂| 日本激情一区| 成人污污视频| 精品国产欧美日韩一区二区三区| 国产精品v日韩精品v欧美精品网站| 天堂va欧美ⅴa亚洲va一国产| 久久亚洲二区| 亚洲女人av| 蜜臀va亚洲va欧美va天堂| 久久亚洲图片| 免费国产亚洲视频| 中文字幕日韩亚洲| 免费在线成人网| 丝袜美腿成人在线| 视频一区免费在线观看| 视频一区二区欧美| 免费观看日韩电影| 午夜久久av| 日韩av中文在线观看| 日韩成人在线看| 国产麻豆一区二区三区精品视频| 国产精品扒开腿做爽爽爽软件| 国产精品男女| 国精品产品一区| 久久婷婷丁香| 99热精品在线| 日日夜夜免费精品视频| 97精品久久| 国产精品一国产精品| 国产一区二区三区视频在线| 日韩在线第七页| 伊人成人网在线看| 亚洲一二av| 国产精品久久久久久模特| 成人午夜亚洲| 欧美色图国产精品| 亚洲丝袜美腿一区| 国产精品永久| 日韩在线短视频| 国产亚洲精品久久久久婷婷瑜伽| 一本综合精品| 精品视频久久| 欧美手机在线| 日韩有吗在线观看| 麻豆高清免费国产一区| 久久免费国产| 亚洲tv在线| 精品一区二区三区中文字幕视频| 日韩一区二区三区在线免费观看| 国产精品普通话对白| 日韩**一区毛片| 美女久久99| 亚洲精品中文字幕乱码| 日韩精品一区二区三区av| 久久99青青| 米奇777超碰欧美日韩亚洲| 亚洲美女久久| 亚洲精品成人图区| 欧美va天堂| 国产精品尤物| 在线精品视频在线观看高清| 91欧美极品| 久久蜜桃av| 国产乱码精品一区二区三区亚洲人| 精精国产xxxx视频在线播放| 免费久久99精品国产自在现线| 日本精品一区二区三区在线观看视频 | 成人一二三区| 男女男精品视频网| av在线最新| 亚洲一级大片| 国产精品蜜芽在线观看| 自拍自偷一区二区三区| 黄色在线观看www| 日本中文字幕一区二区视频| 九九精品调教| 国产欧美精品久久|