国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Java Mybatis架構(gòu)設(shè)計(jì)深入了解

Java Mybatis架構(gòu)設(shè)計(jì)深入了解

2022-03-10 00:37女友在高考 Java教程

在本篇文章里小編給大家整理的是一篇關(guān)于Java Mybatis架構(gòu)設(shè)計(jì)詳解內(nèi)容,對(duì)此有興趣的朋友們可以參考下,希望能夠給你帶來(lái)幫助

架構(gòu)設(shè)計(jì)

Java Mybatis架構(gòu)設(shè)計(jì)深入了解

我們可以把Mybatis的功能架構(gòu)分為三層:

1.API接口層:提供給外部使用的接口API,開(kāi)發(fā)人員通過(guò)這些本地API來(lái)操縱數(shù)據(jù)庫(kù)。接口層一接收到調(diào)用請(qǐng)求就會(huì)調(diào)用數(shù)據(jù)處理層來(lái)完成具體的數(shù)據(jù)處理。

Mybatis和數(shù)據(jù)庫(kù)的交互有兩種方式:

  1. 使用傳統(tǒng)的Mybatis提供API
  2. 使用Mapper代理的方式

2.數(shù)據(jù)處理層:負(fù)責(zé)具體的SQL查找、SQL解析、SQL執(zhí)行和執(zhí)行結(jié)果映射處理等。他主要的目的是根據(jù)調(diào)用的請(qǐng)求完成一次數(shù)據(jù)庫(kù)操作。

3.基礎(chǔ)支撐層:負(fù)責(zé)最基礎(chǔ)的功能支撐,包括連接管理、事務(wù)管理、配置加載和緩存處理,這些都是共用的東西,將他們抽取出來(lái)最為基礎(chǔ)組件。為上層的數(shù)據(jù)處理層提供最基礎(chǔ)的支撐。

 

Mybatis主要構(gòu)件

構(gòu)件 描述
SqlSession 作為Mybatis工作的主要頂層API,表示和數(shù)據(jù)庫(kù)交互的會(huì)話,完成必要數(shù)據(jù)庫(kù)增刪查改功能
Executor Mybatis執(zhí)行器,是Mybatis調(diào)度的核心,負(fù)責(zé)SQL語(yǔ)句的生成和查詢緩存的維護(hù)
StatementHandler 封裝了JDBC Statement操作,負(fù)責(zé)對(duì)JDBC statement的操作,如設(shè)置參數(shù)、將Statement結(jié)果集轉(zhuǎn)換為L(zhǎng)ist集合
ParameterHandler 負(fù)責(zé)對(duì)用戶傳遞的參數(shù)轉(zhuǎn)換為JDBC Statement所需要的參數(shù)
ResultSetHandler 負(fù)責(zé)將JDBC返回的ResultSet結(jié)果集對(duì)象轉(zhuǎn)換為L(zhǎng)ist類型的集合
TypeHandler 負(fù)責(zé)java數(shù)據(jù)類型和jdbc數(shù)據(jù)類型之間的映射和轉(zhuǎn)換
MappedStatement MappedStatement維護(hù)了一條<select、 update 、 delete 、insert >節(jié)點(diǎn)的封裝
SqlSource 負(fù)責(zé)根據(jù)用戶傳遞的parameterObject,動(dòng)態(tài)的生成SQL語(yǔ)句,將信息封裝到BoundSql對(duì)象中
BoundSql 表示動(dòng)態(tài)生成的SQL語(yǔ)句以及相應(yīng)的參數(shù)信息

Java Mybatis架構(gòu)設(shè)計(jì)深入了解

總體流程:

1.加載配置并初始化

配置來(lái)源于兩個(gè)地方,一個(gè)是配置文件(conf.xml,mapper*.xml),一個(gè)是java代碼中的注解,將配置文件內(nèi)容封裝到Configuration,將sql的配置信息加載成為一個(gè)mappedstatement對(duì)象,存儲(chǔ)在內(nèi)存中。

2. 接收調(diào)用請(qǐng)求

觸發(fā)條件:調(diào)用Mybatis提供的API

傳入?yún)?shù):為SQL的ID和傳入的參數(shù)

將請(qǐng)求傳遞給下層的請(qǐng)求處理層進(jìn)行處理

3.處理操作請(qǐng)求

  • 根據(jù)SQL的ID查找對(duì)應(yīng)的MappedStatement對(duì)象
  • 根據(jù)傳入?yún)?shù)對(duì)象解析,得到最終要執(zhí)行的SQL和執(zhí)行傳入?yún)?shù)
  • 獲取數(shù)據(jù)庫(kù)連接,將最終SQL語(yǔ)句和參數(shù)給到數(shù)據(jù)庫(kù)執(zhí)行,并得到執(zhí)行結(jié)果
  • 根據(jù)MappedStatement對(duì)象中的結(jié)果映射配置對(duì)得到的執(zhí)行結(jié)果進(jìn)行轉(zhuǎn)換處理,并得到最終的處理結(jié)果
  • 釋放連接資源

4.返回處理結(jié)果

 

Mybatis緩存

Mybatis有一級(jí)緩存和二級(jí)緩存。Mybatis收到查詢請(qǐng)求后首先會(huì)查詢二級(jí)緩存,若二級(jí)緩存未命中,再去查詢一級(jí)緩存,一級(jí)緩存沒(méi)有,再查詢數(shù)據(jù)庫(kù)。

一級(jí)緩存

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  if (queryStack == 0 && ms.isFlushCacheRequired()) {
    clearLocalCache();
  }
  List<E> list;
  try {
    queryStack++;
    //從localCache緩存里查數(shù)據(jù),沒(méi)有就去查數(shù)據(jù)庫(kù)
    list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
    if (list != null) {
      handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else {
      list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
  } finally {
    queryStack--;
  }
  if (queryStack == 0) {
    for (DeferredLoad deferredLoad : deferredLoads) {
      deferredLoad.load();
    }
    // issue #601
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      // issue #482
      clearLocalCache();
    }
  }
  return list;
}

這個(gè)localCache是BaseExecutor里面的一個(gè)屬性

public abstract class BaseExecutor implements Executor {


protected PerpetualCache localCache;

PerpetualCache類

public class PerpetualCache implements Cache {

private final String id;

private Map<Object, Object> cache = new HashMap<Object, Object>();

public PerpetualCache(String id) {
  this.id = id;
}

@Override
public String getId() {
  return id;
}

@Override
public int getSize() {
  return cache.size();
}

@Override
public void putObject(Object key, Object value) {
  cache.put(key, value);
}

@Override
public Object getObject(Object key) {
  return cache.get(key);
}

二級(jí)緩存

啟用二級(jí)緩存步驟:

1.開(kāi)啟cacheEnabled(默認(rèn)打開(kāi))

<settings>
<setting name="cacheEnabled" value="true"/>
</settings>

2.需要在二級(jí)緩存的Mapper配置文件中加入

<cache></cache>

3.注意,二級(jí)緩存要想生效,必須要調(diào)用sqlSession.commit或close方法

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  Cache cache = ms.getCache();
  if (cache != null) {
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
      ensureNoOutParams(ms, parameterObject, boundSql);
      @SuppressWarnings("unchecked")
      List<E> list = (List<E>) tcm.getObject(cache, key);
      if (list == null) {
        list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578 and #116
      }
      return list;
    }
  }
  return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

注意Cache cache = ms.getCache();,這個(gè)cache是從MappedStatement中獲取到的,由于MappedStatement存在全局配置中,可以多個(gè)CachingExecutor獲取到,這樣就會(huì)出現(xiàn)線程安全問(wèn)題。除此之外,若不加以控制,多個(gè)事務(wù)共用一個(gè)緩存實(shí)例,會(huì)導(dǎo)致臟讀的存在。

那么mybatis是怎么解決臟讀的呢?借用了上面的tcm這個(gè)變量,也就是TransactionalCacheManager類來(lái)解決的。

TransactionalCacheManager類維護(hù)了Cache,TransactionalCache的關(guān)系,真正的數(shù)據(jù)還是交由TransactionalCache處理的。

結(jié)構(gòu)如圖:

Java Mybatis架構(gòu)設(shè)計(jì)深入了解

public class TransactionalCacheManager {

private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();

public void clear(Cache cache) {
  getTransactionalCache(cache).clear();
}

public Object getObject(Cache cache, CacheKey key) {
  return getTransactionalCache(cache).getObject(key);
}

public void putObject(Cache cache, CacheKey key, Object value) {
  getTransactionalCache(cache).putObject(key, value);
}

public void commit() {
  for (TransactionalCache txCache : transactionalCaches.values()) {
    txCache.commit();
  }
}

public void rollback() {
  for (TransactionalCache txCache : transactionalCaches.values()) {
    txCache.rollback();
  }
}

private TransactionalCache getTransactionalCache(Cache cache) {
  TransactionalCache txCache = transactionalCaches.get(cache);
  if (txCache == null) {
    txCache = new TransactionalCache(cache);
    transactionalCaches.put(cache, txCache);
  }
  return txCache;
}

}

接下來(lái)看一下TransactionalCache的代碼

public class TransactionalCache implements Cache {

private static final Log log = LogFactory.getLog(TransactionalCache.class);

// 真正的緩存對(duì)象
private final Cache delegate;
private boolean clearOnCommit;
//在事務(wù)被提交前,所有從數(shù)據(jù)庫(kù)中查詢的結(jié)果將緩存在此集合中
private final Map<Object, Object> entriesToAddOnCommit;
//在事務(wù)被提交前,當(dāng)緩存未命中時(shí),CacheKey 將會(huì)被存儲(chǔ)在此集合中
private final Set<Object> entriesMissedInCache;

public TransactionalCache(Cache delegate) {
  this.delegate = delegate;
  this.clearOnCommit = false;
  this.entriesToAddOnCommit = new HashMap<Object, Object>();
  this.entriesMissedInCache = new HashSet<Object>();
}

@Override
public String getId() {
  return delegate.getId();
}

@Override
public int getSize() {
  return delegate.getSize();
}

@Override
public Object getObject(Object key) {
  // issue #116
  //獲取緩存的時(shí)候從delegate里獲取的
  Object object = delegate.getObject(key);
  if (object == null) {
    //緩存未命中,將key存入entriesMissedInCache.
    entriesMissedInCache.add(key);
  }
  // issue #146
  if (clearOnCommit) {
    return null;
  } else {
    return object;
  }
}

@Override
public ReadWriteLock getReadWriteLock() {
  return null;
}

@Override
public void putObject(Object key, Object object) {
  //put的時(shí)候只是將數(shù)據(jù)庫(kù)的數(shù)據(jù)放入到了entriesToAddOnCommit
  entriesToAddOnCommit.put(key, object);
}

@Override
public Object removeObject(Object key) {
  return null;
}

@Override
public void clear() {
  clearOnCommit = true;
  entriesToAddOnCommit.clear();
}

public void commit() {
  if (clearOnCommit) {
    delegate.clear();
  }
  //刷新未緩存的結(jié)果到delegate中去
  flushPendingEntries();
  reset();
}

public void rollback() {
  unlockMissedEntries();
  reset();
}

private void reset() {
  clearOnCommit = false;
  entriesToAddOnCommit.clear();
  entriesMissedInCache.clear();
}

private void flushPendingEntries() {
  for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
    delegate.putObject(entry.getKey(), entry.getValue());
  }
  for (Object entry : entriesMissedInCache) {
    if (!entriesToAddOnCommit.containsKey(entry)) {
      delegate.putObject(entry, null);
    }
  }
}

private void unlockMissedEntries() {
  for (Object entry : entriesMissedInCache) {
    try {
      delegate.removeObject(entry);
    } catch (Exception e) {
      log.warn("Unexpected exception while notifiying a rollback to the cache adapter."
          + "Consider upgrading your cache adapter to the latest version.  Cause: " + e);
    }
  }
}

}

我們存儲(chǔ)二級(jí)緩存的時(shí)候是放入到TransactionalCache.entriesToAddOnCommit這個(gè)map中,但是每次查詢的時(shí)候是從delegate查詢的,所以這個(gè)二級(jí)緩存查詢數(shù)據(jù)庫(kù)后,緩存是沒(méi)有立刻生效的。只有當(dāng)執(zhí)行了sqlSession的commit或close方法后,它會(huì)調(diào)用到tcm的commit,在調(diào)用到transactionlCache的commit,刷新緩存到delegate了。

 

總結(jié):

二級(jí)緩存的設(shè)計(jì)上,大量運(yùn)用了裝飾器模式,如SynchronizedCache、LoggingCache。

二級(jí)緩存實(shí)現(xiàn)了Sqlsession之間的緩存數(shù)據(jù)共享,屬于namespace級(jí)別

二級(jí)緩存的實(shí)現(xiàn)由CachingExecutor和一個(gè)事務(wù)型預(yù)緩存TransactionlCache完成。

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!

原文鏈接:https://www.cnblogs.com/javammc/p/15497530.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 一本大道伊人久久综合 | 日韩欧美在线观看一区二区 | 天天干天天操天天射 | 人人99精 | 午夜视频国产 | 九九热在线视频 | 精品国产乱码久久久久久久软件 | 五月婷婷视频 | 亚洲精品成人免费 | 高清在线一区 | 亚洲成人网一区 | 亚洲精品一区二区在线 | 91视视频在线观看入口直接观看 | 一区二区成人 | 欧美日韩国产精品一区二区 | 伊人黄| 中国一级黄色片子 | 国产视频精品免费 | 久久精品日韩 | 欧美一区二区三区婷婷月色 | 一级黄色毛片免费观看 | 日韩一区二区在线电影 | 91丁香婷婷综合久久欧美 | 国产一区二区三区在线观看免费 | av在线中文 | 国产精品99久久久久久宅男 | 国产精品亚洲第一 | 国产高清亚洲 | 精品久久久久一区二区国产 | 爱色av网址 | 日本久草 | 精品国产视频 | 色性视频 | 欧美自拍网| 先锋影音男人 | 一区二区三区入口 | 欧美日韩一区二区三区在线观看 | 成人久久久久久久久 | 欧美精品一区三区 | 精品久久久久久久久久久 | 国产精品一区二区三区四区 |