最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Boot?配置?Hikari?數(shù)據(jù)庫連接池的操作代碼

 更新時間:2023年09月04日 10:56:34   作者:杜小舟  
數(shù)據(jù)庫連接池是一個提高程序與數(shù)據(jù)庫的連接的優(yōu)化,連接池它主要作用是提高性能、節(jié)省資源、控制連接數(shù)、連接管理等操作,這篇文章主要介紹了SpringBoot配置Hikari數(shù)據(jù)庫連接池,需要的朋友可以參考下

Spring Boot 配置 Hikari 數(shù)據(jù)庫連接池

前言

數(shù)據(jù)庫連接池是一個提高程序與數(shù)據(jù)庫的連接的優(yōu)化,連接池它主要作用是提高性能、節(jié)省資源、控制連接數(shù)、連接管理等操作;
程序中的線程池與之同理,都是為了優(yōu)化、提高性能。

配置

spring:
  datasource:
    hikari:
      # 設置是否自動提交事務,默認為true
      auto-commit: true
      # 設置用于測試連接的SQL查詢語句
      connection-test-query: SELECT 1
      # 設置獲取數(shù)據(jù)庫連接的超時時間,默認為30秒,單位是秒
      connection-timeout: 30000
      # 設置連接在連接池中保持空閑的最長時間,默認為10分鐘,單位是秒
      idle-timeout: 30000
      # 設置連接在連接池中允許存在的最長時間,默認為30分鐘,單位是秒
      max-lifetime: 1800000
      # 設置連接池中允許的最大連接數(shù),默認為10
      maximum-pool-size: 15
      # 設置連接池中保持的最小空閑連接數(shù),默認為10
      minimum-idle: 5
      # 設置連接池的名稱,默認為"HikariPool-1"
      pool-name: agriculture
      # 設置連接驗證的超時時間,默認為5秒,單位是秒
      validation-timeout: 10

補充:SpringBoot 2.0 中 HikariCP 數(shù)據(jù)庫連接池原理解析

作為后臺服務開發(fā),在日常工作中我們天天都在跟數(shù)據(jù)庫打交道,一直在進行各種CRUD操作,都會使用到數(shù)據(jù)庫連接池。按照發(fā)展歷程,業(yè)界知名的數(shù)據(jù)庫連接池有以下幾種:c3p0、DBCP、Tomcat JDBC Connection Pool、Druid 等,不過最近最火的是 HiKariCP。

HiKariCP 號稱是業(yè)界跑得最快的數(shù)據(jù)庫連接池,自從 SpringBoot 2.0 將其作為默認數(shù)據(jù)庫連接池后,其發(fā)展勢頭銳不可當。那它為什么那么快呢?今天咱們就重點聊聊其中的原因。

一、什么是數(shù)據(jù)庫連接池

在講解HiKariCP之前,我們先簡單介紹下什么是數(shù)據(jù)庫連接池(Database Connection Pooling),以及為什么要有數(shù)據(jù)庫連接池。

從根本上而言,數(shù)據(jù)庫連接池和我們常用的線程池一樣,都屬于池化資源,它在程序初始化時創(chuàng)建一定數(shù)量的數(shù)據(jù)庫連接對象并將其保存在一塊內存區(qū)中。它允許應用程序重復使用一個現(xiàn)有的數(shù)據(jù)庫連接,當需要執(zhí)行 SQL 時,我們是直接從連接池中獲取一個連接,而不是重新建立一個數(shù)據(jù)庫連接,當 SQL 執(zhí)行完,也并不是將數(shù)據(jù)庫連接真的關掉,而是將其歸還到數(shù)據(jù)庫連接池中。我們可以通過配置連接池的參數(shù)來控制連接池中的初始連接數(shù)、最小連接、最大連接、最大空閑時間等參數(shù),來保證訪問數(shù)據(jù)庫的數(shù)量在一定可控制的范圍類,防止系統(tǒng)崩潰,同時保證用戶良好的體驗。數(shù)據(jù)庫連接池示意圖如下所示:

因此使用數(shù)據(jù)庫連接池的核心作用,就是避免數(shù)據(jù)庫連接頻繁創(chuàng)建和銷毀,節(jié)省系統(tǒng)開銷。因為數(shù)據(jù)庫連接是有限且代價昂貴,創(chuàng)建和釋放數(shù)據(jù)庫連接都非常耗時,頻繁地進行這樣的操作將占用大量的性能開銷,進而導致網(wǎng)站的響應速度下降,甚至引起服務器崩潰。

二、常見數(shù)據(jù)庫連接池對比分析

這里詳細總結了常見數(shù)據(jù)庫連接池的各項功能比較,我們重點分析下當前主流的阿里巴巴Druid與HikariCP,HikariCP在性能上是完全優(yōu)于Druid連接池的。而Druid的性能稍微差點是由于鎖機制的不同,并且Druid提供更豐富的功能,包括監(jiān)控、sql攔截與解析等功能,兩者的側重點不一樣,HikariCP追求極致的高性能。

下面是官網(wǎng)提供的性能對比圖,在性能上面這五種數(shù)據(jù)庫連接池的排序如下:HikariCP>druid>tomcat-jdbc>dbcp>c3p0:

三、HikariCP 數(shù)據(jù)庫連接池簡介

HikariCP 號稱是史上性能最好的數(shù)據(jù)庫連接池,SpringBoot 2.0將它設置為默認的數(shù)據(jù)源連接池。Hikari相比起其它連接池的性能高了非常多,那么,這是怎么做到的呢?通過查看HikariCP官網(wǎng)介紹,對于HikariCP所做優(yōu)化總結如下:

1. 字節(jié)碼精簡 :優(yōu)化代碼,編譯后的字節(jié)碼量極少,使得CPU緩存可以加載更多的程序代碼;

HikariCP在優(yōu)化并精簡字節(jié)碼上也下了功夫,使用第三方的Java字節(jié)碼修改類庫Javassist來生成委托實現(xiàn)動態(tài)代理.動態(tài)代理的實現(xiàn)在ProxyFactory類,速度更快,相比于JDK Proxy生成的字節(jié)碼更少,精簡了很多不必要的字節(jié)碼。

2. 優(yōu)化代理和攔截器:減少代碼,例如HikariCP的Statement proxy只有100行代碼,只有BoneCP的十分之一;

3. 自定義數(shù)組類型(FastStatementList)代替ArrayList:避免ArrayList每次get()都要進行range check,避免調用remove()時的從頭到尾的掃描(由于連接的特點是后獲取連接的先釋放);

4. 自定義集合類型(ConcurrentBag):提高并發(fā)讀寫的效率;

5. 其他針對BoneCP缺陷的優(yōu)化,比如對于耗時超過一個CPU時間片的方法調用的研究。

當然作為一個數(shù)據(jù)庫連接池,不能說快就會被消費者所推崇,它還具有非常好的健壯性及穩(wěn)定性。HikariCP從15年推出以來,已經(jīng)經(jīng)受了廣大應用市場的考驗,并且成功地被SpringBoot2.0作為默認數(shù)據(jù)庫連接池進行推廣,在可靠性上面是值得信任的。其次借助于其代碼量少,占用cpu和內存量小的優(yōu)點,使得它的執(zhí)行率非常高。最后,Spring配置HikariCP和druid基本沒什么區(qū)別,遷移過來非常方便,這些都是為什么HikariCP目前如此受歡迎的原因。

字節(jié)碼精簡、優(yōu)化代理和攔截器、自定義數(shù)組類型。

四、HikariCP 核心源碼解析

4.1 FastList 是如何優(yōu)化性能問題的 首先我們來看一下執(zhí)行數(shù)據(jù)庫操作規(guī)范化的操作步驟:

  • 通過數(shù)據(jù)源獲取一個數(shù)據(jù)庫連接;
  • 創(chuàng)建 Statement;
  • 執(zhí)行 SQL;
  • 通過 ResultSet 獲取 SQL 執(zhí)行結果;
  • 釋放 ResultSet;
  • 釋放 Statement;
  • 釋放數(shù)據(jù)庫連接。

當前所有數(shù)據(jù)庫連接池都是嚴格地根據(jù)這個順序來進行數(shù)據(jù)庫操作的,為了防止最后的釋放操作,各類數(shù)據(jù)庫連接池都會把創(chuàng)建的 Statement 保存在數(shù)組 ArrayList 里,來保證當關閉連接的時候,可以依次將數(shù)組中的所有 Statement 關閉。HiKariCP 在處理這一步驟中,認為 ArrayList 的某些方法操作存在優(yōu)化空間,因此對List接口的精簡實現(xiàn),針對List接口中核心的幾個方法進行優(yōu)化,其他部分與ArrayList基本一致 。

首先是get()方法,ArrayList每次調用get()方法時都會進行rangeCheck檢查索引是否越界,F(xiàn)astList的實現(xiàn)中去除了這一檢查,是因為數(shù)據(jù)庫連接池滿足索引的合法性,能保證不會越界,此時rangeCheck就屬于無效的計算開銷,所以不用每次都進行越界檢查。省去頻繁的無效操作,可以明顯地減少性能消耗。

FastList get()操作

public T get(int index)
{
   // ArrayList 在此多了范圍檢測 rangeCheck(index);
   return elementData[index];
}

其次是remove方法,當通過 conn.createStatement() 創(chuàng)建一個 Statement 時,需要調用 ArrayList 的 add() 方法加入到 ArrayList 中,這個是沒有問題的;但是當通過 stmt.close() 關閉 Statement 的時候,需要調用 ArrayList 的 remove() 方法來將其從 ArrayList 中刪除,而ArrayList的remove(Object)方法是從頭開始遍歷數(shù)組,而FastList是從數(shù)組的尾部開始遍歷,因此更為高效。假設一個 Connection 依次創(chuàng)建 6 個 Statement,分別是 S1、S2、S3、S4、S5、S6,而關閉 Statement 的順序一般都是逆序的,從S6 到 S1,而 ArrayList 的 remove(Object o) 方法是順序遍歷查找,逆序刪除而順序查找,這樣的查找效率就太慢了。因此FastList對其進行優(yōu)化,改成了逆序查找。如下代碼為FastList 實現(xiàn)的數(shù)據(jù)移除操作,相比于ArrayList的 remove()代碼, FastList 去除了檢查范圍 和 從頭到尾遍歷檢查元素的步驟,其性能更快。

public boolean remove(Object element)
{
   // 刪除操作使用逆序查找
   for (int index = size - 1; index >= 0; index--) {
      if (element == elementData[index]) {
         final int numMoved = size - index - 1;
         // 如果角標不是最后一個,復制一個新的數(shù)組結構
         if (numMoved > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
         }
         //如果角標是最后面的 直接初始化為null
         elementData[--size] = null;
         return true;
      }
   }
   return false;
}

通過上述源碼分析,F(xiàn)astList 的優(yōu)化點還是很簡單的。相比ArrayList僅僅是去掉了rage檢查,擴容優(yōu)化等細節(jié)處,刪除時數(shù)組從后往前遍歷查找元素等微小的調整,從而追求性能極致。當然FastList 對于 ArrayList 的優(yōu)化,我們不能說ArrayList不好。所謂定位不同、追求不同,ArrayList作為通用容器,更追求安全、穩(wěn)定,操作前rangeCheck檢查,對非法請求直接拋出異常,更符合 fail-fast(快速失敗)機制,而FastList追求的是性能極致。

下面我們再來聊聊 HiKariCP 中的另外一個數(shù)據(jù)結構 ConcurrentBag,看看它又是如何提升性能的。

4.2 ConcurrentBag 實現(xiàn)原理分析

當前主流數(shù)據(jù)庫連接池實現(xiàn)方式,大都用兩個阻塞隊列來實現(xiàn)。一個用于保存空閑數(shù)據(jù)庫連接的隊列 idle,另一個用于保存忙碌數(shù)據(jù)庫連接的隊列 busy;獲取連接時將空閑的數(shù)據(jù)庫連接從 idle 隊列移動到 busy 隊列,而關閉連接時將數(shù)據(jù)庫連接從 busy 移動到 idle。這種方案將并發(fā)問題委托給了阻塞隊列,實現(xiàn)簡單,但是性能并不是很理想。因為 Java SDK 中的阻塞隊列是用鎖實現(xiàn)的,而高并發(fā)場景下鎖的爭用對性能影響很大。

HiKariCP 并沒有使用 Java SDK 中的阻塞隊列,而是自己實現(xiàn)了一個叫做 ConcurrentBag 的并發(fā)容器,在連接池(多線程數(shù)據(jù)交互)的實現(xiàn)上具有比LinkedBlockingQueue和LinkedTransferQueue更優(yōu)越的性能。

ConcurrentBag 中最關鍵的屬性有 4 個,分別是:用于存儲所有的數(shù)據(jù)庫連接的共享隊列 sharedList、線程本地存儲 threadList、等待數(shù)據(jù)庫連接的線程數(shù) waiters 以及分配數(shù)據(jù)庫連接的工具 handoffQueue。其中,handoffQueue 用的是 Java SDK 提供的 SynchronousQueue,SynchronousQueue 主要用于線程之間傳遞數(shù)據(jù)。

ConcurrentBag 中的關鍵屬性

// 存放共享元素,用于存儲所有的數(shù)據(jù)庫連接
private final CopyOnWriteArrayList<T> sharedList;
// 在 ThreadLocal 緩存線程本地的數(shù)據(jù)庫連接,避免線程爭用
private final ThreadLocal<List<Object>> threadList;
// 等待數(shù)據(jù)庫連接的線程數(shù)
private final AtomicInteger waiters;
// 接力隊列,用來分配數(shù)據(jù)庫連接
private final SynchronousQueue<T> handoffQueue;

ConcurrentBag 保證了全部的資源均只能通過 add() 方法進行添加,當線程池創(chuàng)建了一個數(shù)據(jù)庫連接時,通過調用 ConcurrentBag 的 add() 方法加入到 ConcurrentBag 中,并通過 remove() 方法進行移出。下面是 add() 方法和 remove() 方法的具體實現(xiàn),添加時實現(xiàn)了將這個連接加入到共享隊列 sharedList 中,如果此時有線程在等待數(shù)據(jù)庫連接,那么就通過 handoffQueue 將這個連接分配給等待的線程。

public void add(final T bagEntry)
{
   if (closed) {
      LOGGER.info("ConcurrentBag has been closed, ignoring add()");
      throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()");
   }
   // 新添加的資源優(yōu)先放入sharedList
   sharedList.add(bagEntry);
   // 當有等待資源的線程時,將資源交到等待線程 handoffQueue 后才返回
   while (waiters.get() > 0 && bagEntry.getState() == STATE_NOT_IN_USE && !handoffQueue.offer(bagEntry)) {
      yield();
   }
}
public boolean remove(final T bagEntry)
{
   // 如果資源正在使用且無法進行狀態(tài)切換,則返回失敗
   if (!bagEntry.compareAndSet(STATE_IN_USE, STATE_REMOVED) && !bagEntry.compareAndSet(STATE_RESERVED, STATE_REMOVED) && !closed) {
      LOGGER.warn("Attempt to remove an object from the bag that was not borrowed or reserved: {}", bagEntry);
      return false;
   }
   // 從sharedList中移出
   final boolean removed = sharedList.remove(bagEntry);
   if (!removed && !closed) {
      LOGGER.warn("Attempt to remove an object from the bag that does not exist: {}", bagEntry);
   }
   return removed;
}

同時ConcurrentBag通過提供的 borrow() 方法來獲取一個空閑的數(shù)據(jù)庫連接,并通過requite()方法進行資源回收,borrow() 的主要邏輯是:

查看線程本地存儲 threadList 中是否有空閑連接,如果有,則返回一個空閑的連接;如果線程本地存儲中無空閑連接,則從共享隊列 sharedList 中獲取;如果共享隊列中也沒有空閑的連接,則請求線程需要等待。ConcurrentBag 的 borrow() 與 requite() 方法

// 該方法會從連接池中獲取連接, 如果沒有連接可用, 會一直等待timeout超時
public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException
{
   // 首先查看線程本地資源threadList是否有空閑連接
   final List<Object> list = threadList.get();
   // 從后往前反向遍歷是有好處的, 因為最后一次使用的連接, 空閑的可能性比較大, 之前的連接可能會被其他線程提前借走了
   for (int i = list.size() - 1; i >= 0; i--) {
      final Object entry = list.remove(i);
      @SuppressWarnings("unchecked")
      final T bagEntry = weakThreadLocals ? ((WeakReference<T>) entry).get() : (T) entry;
      // 線程本地存儲中的連接也可以被竊取, 所以需要用CAS方法防止重復分配
      if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
         return bagEntry;
      }
   }
   // 當無可用本地化資源時,遍歷全部資源,查看可用資源,并用CAS方法防止資源被重復分配
   final int waiting = waiters.incrementAndGet();
   try {
      for (T bagEntry : sharedList) {
         if (bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
            // 因為可能“搶走”了其他線程的資源,因此提醒包裹進行資源添加
            if (waiting > 1) {
               listener.addBagItem(waiting - 1);
            }
            return bagEntry;
         }
      }
      listener.addBagItem(waiting);
      timeout = timeUnit.toNanos(timeout);
      do {
         final long start = currentTime();
         // 當現(xiàn)有全部資源都在使用中時,等待一個被釋放的資源或者一個新資源
         final T bagEntry = handoffQueue.poll(timeout, NANOSECONDS);
         if (bagEntry == null || bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
            return bagEntry;
         }
         timeout -= elapsedNanos(start);
      } while (timeout > 10_000);
      return null;
   }
   finally {
      waiters.decrementAndGet();
   }
}
public void requite(final T bagEntry)
{
   // 將資源狀態(tài)轉為未在使用
   bagEntry.setState(STATE_NOT_IN_USE);
   // 判斷是否存在等待線程,若存在,則直接轉手資源
   for (int i = 0; waiters.get() > 0; i++) {
      if (bagEntry.getState() != STATE_NOT_IN_USE || handoffQueue.offer(bagEntry)) {
         return;
      }
      else if ((i & 0xff) == 0xff) {
         parkNanos(MICROSECONDS.toNanos(10));
      }
      else {
         yield();
      }
   }
   // 否則,進行資源本地化處理
   final List<Object> threadLocalList = threadList.get();
   if (threadLocalList.size() < 50) {
      threadLocalList.add(weakThreadLocals ? new WeakReference<>(bagEntry) : bagEntry);
   }
}

borrow() 方法可以說是整個 HikariCP 中最核心的方法,它是我們從連接池中獲取連接的時候最終會調用到的方法。需要注意的是 borrow() 方法只提供對象引用,不移除對象,因此使用時必須通過 requite() 方法進行放回,否則容易導致內存泄露。requite() 方法首先將數(shù)據(jù)庫連接狀態(tài)改為未使用,之后查看是否存在等待線程,如果有則分配給等待線程;否則將該數(shù)據(jù)庫連接保存到線程本地存儲里。

ConcurrentBag 實現(xiàn)采用了queue-stealing的機制獲取元素:首先嘗試從ThreadLocal中獲取屬于當前線程的元素來避免鎖競爭,如果沒有可用元素則再次從共享的CopyOnWriteArrayList中獲取。此外,ThreadLocal和CopyOnWriteArrayList在ConcurrentBag中都是成員變量,線程間不共享,避免了偽共享(false sharing)的發(fā)生。同時因為線程本地存儲中的連接是可以被其他線程竊取的,在共享隊列中獲取空閑連接,所以需要用 CAS 方法防止重復分配。 

五、總結

Hikari 作為 SpringBoot2.0默認的連接池,目前在行業(yè)內使用范圍非常廣,對于大部分業(yè)務來說,都可以實現(xiàn)快速接入使用,做到高效連接。

參考資料 

https://github.com/brettwooldridge/HikariCP

https://github.com/alibaba/druid

到此這篇關于Spring Boot 配置 Hikari 數(shù)據(jù)庫連接池的文章就介紹到這了,更多相關Spring Boot 配置 Hikari 連接池內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java中數(shù)組的定義和使用教程(二)

    Java中數(shù)組的定義和使用教程(二)

    這篇文章主要給大家介紹了關于Java中數(shù)組的定義和使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • 淺析Java中的 new 關鍵字

    淺析Java中的 new 關鍵字

    java中的new關鍵字是實例化對象,接下來本文通過一個案例給大家講解Java中的 new 關鍵字,感興趣的朋友可以參考下
    2016-08-08
  • 詳解SpringIOC容器中bean的作用范圍和生命周期

    詳解SpringIOC容器中bean的作用范圍和生命周期

    這篇文章主要介紹了SpringIOC容器中bean的作用范圍和生命周期,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Java遞歸尋路實現(xiàn),你真的理解了嗎

    Java遞歸尋路實現(xiàn),你真的理解了嗎

    遞歸就是一個過程或函數(shù)在其定義或說明中有直接或間接調用自身的一種方法,它通常把一個大型復雜的問題層層轉化為一個與原問題相似的規(guī)模較小的問題來求解,需要的朋友可以參考下
    2021-08-08
  • Java current并發(fā)包超詳細分析

    Java current并發(fā)包超詳細分析

    current并發(fā)包、在JDK1.5之前Java并沒有提供線程安全的一些工具類去操作多線程,需要開發(fā)人員自行編寫實現(xiàn)線程安全,但仍然無法完全避免低性能、死鎖、資源管理等問題。在JDK1.5時新增了java.util.current并發(fā)包,其中提供了許多供我們使用的并發(fā)編程工具類
    2023-02-02
  • 通過Java創(chuàng)建Socket連接到服務器方式

    通過Java創(chuàng)建Socket連接到服務器方式

    這篇文章主要介紹了通過Java創(chuàng)建Socket連接到服務器方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Spring?Data?JPA系列QueryByExampleExecutor使用詳解

    Spring?Data?JPA系列QueryByExampleExecutor使用詳解

    這篇文章主要為大家介紹了Spring?Data?JPA系列QueryByExampleExecutor使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • SpringCloudGateway 網(wǎng)關登錄校驗實現(xiàn)思路

    SpringCloudGateway 網(wǎng)關登錄校驗實現(xiàn)思路

    文章介紹了在微服務架構中使用Spring Cloud Gateway進行登錄校驗的方法,通過在網(wǎng)關層面進行登錄校驗,并將用戶信息通過請求頭傳遞給下游微服務,解決了每個微服務都需要獨立進行登錄校驗的問題,此外,還討論了如何在微服務之間傳遞用戶信息
    2024-11-11
  • 詳解Spring學習之聲明式事務管理

    詳解Spring學習之聲明式事務管理

    這篇文章主要介紹了詳解Spring學習之聲明式事務管理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • SpringBoot controller接收txt文本文件實現(xiàn)方式

    SpringBoot controller接收txt文本文件實現(xiàn)方式

    文章介紹在Spring Boot Controller中接收文本文件的方法,需使用MultipartFile類并通過@RequestParam注解獲取,重點說明了獲取文件名、內容及保存文件的常用方法,并強調MultipartFile為接口,需通過注解實例化
    2025-09-09

最新評論

黄梅县| 昌吉市| 洛隆县| 鸡东县| 五莲县| 江北区| 沾化县| 乌拉特后旗| 高邮市| 岳池县| 社旗县| 汤原县| 新和县| 罗田县| 施秉县| 涟水县| 稻城县| 乌苏市| 蒙城县| 乌拉特中旗| 巩留县| 虎林市| 临沭县| 广安市| 乌审旗| 商河县| 东兴市| 平谷区| 扎鲁特旗| 阳新县| 万安县| 德州市| 吉安市| 凤城市| 沿河| 始兴县| 肥城市| 合川市| 永丰县| 容城县| 麻江县|