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

MySQ中出現(xiàn)幻讀問(wèn)題的解決過(guò)程

 更新時(shí)間:2025年08月15日 15:12:59   作者:你是橙子那我是誰(shuí)  
文章解析MySQL InnoDB通過(guò)MVCC與間隙鎖機(jī)制在可重復(fù)讀隔離級(jí)別下解決幻讀,確保事務(wù)一致性,同時(shí)指出性能影響及樂(lè)觀鎖等替代方案,幫助開(kāi)發(fā)者優(yōu)化數(shù)據(jù)庫(kù)應(yīng)用

想象一下這樣的場(chǎng)景:

你在電商平臺(tái)購(gòu)物時(shí),看到某商品顯示"庫(kù)存僅剩3件"。當(dāng)你準(zhǔn)備下單時(shí),系統(tǒng)突然提示"庫(kù)存不足"。檢查后發(fā)現(xiàn),在你查看頁(yè)面和點(diǎn)擊購(gòu)買(mǎi)之間的短暫瞬間,其他用戶已經(jīng)買(mǎi)走了所有庫(kù)存。

這種"明明看到有貨卻買(mǎi)不到"的現(xiàn)象,在數(shù)據(jù)庫(kù)中就被稱為"幻讀"(Phantom Read)。

今天,我們將從底層原理到實(shí)際應(yīng)用,全面解析MySQL InnoDB引擎如何解決這一棘手問(wèn)題。

一、幻讀的準(zhǔn)確定義與核心特征

幻讀(Phantom Read)是指在一個(gè)事務(wù)內(nèi),連續(xù)執(zhí)行兩次相同的查詢,第二次查詢看到了第一次查詢沒(méi)有看到的"幻影行"(Phantom Rows)。這種現(xiàn)象特指其他事務(wù)插入了新記錄導(dǎo)致的問(wèn)題。

要深入理解幻讀,我們需要明確幾個(gè)關(guān)鍵特征:

  1. 行級(jí)變化:幻讀關(guān)注的是新行的出現(xiàn),而不是已有行的修改(那是不可重復(fù)讀的問(wèn)題)
  2. 范圍查詢:通常發(fā)生在范圍查詢(如WHERE id > 100)而非精確匹配查詢
  3. 寫(xiě)操作影響:幻讀會(huì)對(duì)UPDATE、DELETE等操作產(chǎn)生影響,可能導(dǎo)致數(shù)據(jù)不一致

這個(gè)流程圖展示了一個(gè)典型的幻讀導(dǎo)致業(yè)務(wù)問(wèn)題的場(chǎng)景:事務(wù)A基于初始查詢結(jié)果執(zhí)行UPDATE操作時(shí),意外影響了事務(wù)B插入的新記錄,導(dǎo)致數(shù)據(jù)不一致。

幻讀 vs 不可重復(fù)讀

很多開(kāi)發(fā)者容易混淆幻讀和不可重復(fù)讀,讓我們通過(guò)表格明確它們的區(qū)別:

特征不可重復(fù)讀幻讀
關(guān)注點(diǎn)同一行數(shù)據(jù)的值變化新行的出現(xiàn)或消失
操作類型UPDATE操作導(dǎo)致INSERT/DELETE操作導(dǎo)致
查詢方式精確匹配查詢范圍查詢
解決方案行鎖或MVCC間隙鎖或串行化

二、MySQL隔離級(jí)別深度解析

理解了幻讀現(xiàn)象后,我們需要全面了解MySQL的隔離級(jí)別機(jī)制,這是解決并發(fā)問(wèn)題的基石。

值得注意的是,在標(biāo)準(zhǔn)SQL規(guī)范中,可重復(fù)讀隔離級(jí)別是不保證解決幻讀問(wèn)題的。但MySQL的InnoDB引擎通過(guò)獨(dú)特的實(shí)現(xiàn),在可重復(fù)讀級(jí)別下也解決了幻讀問(wèn)題,這是MySQL的一個(gè)重要特性。

各隔離級(jí)別的實(shí)現(xiàn)差異

重要說(shuō)明:不同數(shù)據(jù)庫(kù)對(duì)隔離級(jí)別的實(shí)現(xiàn)存在差異。例如Oracle默認(rèn)使用讀已提交隔離級(jí)別,而MySQL默認(rèn)使用可重復(fù)讀。PostgreSQL的可重復(fù)讀級(jí)別不解決幻讀問(wèn)題,這與MySQL不同。

讓我們通過(guò)一個(gè)實(shí)際的例子來(lái)觀察不同隔離級(jí)別的行為差異:

-- 測(cè)試表結(jié)構(gòu)
CREATE TABLE account (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    balance DECIMAL(10,2),
    INDEX idx_balance (balance)
);

-- 測(cè)試數(shù)據(jù)
INSERT INTO account VALUES 
(1, 'Alice', 1000.00),
(2, 'Bob', 2000.00),
(3, 'Charlie', 3000.00);

在不同隔離級(jí)別下執(zhí)行以下操作序列:

讀已提交隔離級(jí)別下,事務(wù)A的兩次查詢結(jié)果不同,出現(xiàn)了幻讀。而在可重復(fù)讀級(jí)別下,兩次查詢結(jié)果會(huì)保持一致。

三、InnoDB解決幻讀的雙重機(jī)制

現(xiàn)在我們來(lái)深入探討InnoDB引擎解決幻讀的核心機(jī)制,這是理解MySQL并發(fā)控制的關(guān)鍵。

1. 多版本并發(fā)控制(MVCC)詳解

MVCC(Multi-Version Concurrency Control)是InnoDB實(shí)現(xiàn)高并發(fā)的核心機(jī)制。它通過(guò)在每行數(shù)據(jù)后保存多個(gè)版本,使讀操作不需要等待鎖釋放,寫(xiě)操作也不需要阻塞讀操作。

InnoDB的MVCC實(shí)現(xiàn)依賴于三個(gè)關(guān)鍵字段:

  1. DB_TRX_ID:6字節(jié),記錄最后修改該行的事務(wù)ID
  2. DB_ROLL_PTR:7字節(jié),指向該行回滾段的指針(即指向歷史版本)
  3. DB_ROW_ID:6字節(jié),隱藏的自增行ID(當(dāng)沒(méi)有主鍵時(shí)使用)

這個(gè)類圖展示了InnoDB行數(shù)據(jù)的結(jié)構(gòu)。每次更新操作都會(huì)創(chuàng)建一個(gè)新版本,舊版本通過(guò)DB_ROLL_PTR形成版本鏈。讀操作會(huì)根據(jù)事務(wù)的ReadView決定能看到哪個(gè)版本。

ReadView的工作原理

每個(gè)事務(wù)在第一次執(zhí)行SELECT時(shí)會(huì)生成一個(gè)ReadView,包含:

  • m_ids:當(dāng)前活躍的事務(wù)ID列表
  • min_trx_id:m_ids中的最小值
  • max_trx_id:系統(tǒng)將分配給下一個(gè)事務(wù)的ID
  • creator_trx_id:創(chuàng)建該ReadView的事務(wù)ID

判斷行版本可見(jiàn)性的規(guī)則:

if (trx_id == creator_trx_id) {
    // 本事務(wù)修改的,可見(jiàn)
    return true;
} else if (trx_id < min_trx_id) {
    // 事務(wù)已提交,可見(jiàn)
    return true;
} else if (trx_id >= max_trx_id) {
    // 事務(wù)還未開(kāi)始,不可見(jiàn)
    return false;
} else if (trx_id in m_ids) {
    // 事務(wù)未提交,不可見(jiàn)
    return false;
} else {
    // 事務(wù)已提交,可見(jiàn)
    return true;
}

這個(gè)偽代碼展示了InnoDB如何判斷一個(gè)行版本對(duì)當(dāng)前事務(wù)是否可見(jiàn)。正是這種機(jī)制保證了可重復(fù)讀隔離級(jí)別下不會(huì)看到其他事務(wù)新插入的行。

2. 間隙鎖(Gap Lock)深度解析

**間隙鎖(Gap Lock)**是InnoDB特有的一種鎖機(jī)制,它鎖定索引記錄之間的間隙,防止其他事務(wù)在這些間隙中插入新記錄,從而解決幻讀問(wèn)題。

間隙鎖的工作范圍:

InnoDB默認(rèn)使用Next-Key鎖,它是記錄鎖和間隙鎖的組合。例如:

-- 表中存在記錄id=10,20,30
-- 事務(wù)A執(zhí)行:
SELECT * FROM table WHERE id > 15 FOR UPDATE;

-- 鎖定的范圍包括:
-- (10,20)間隙鎖
-- 20記錄鎖
-- (20,30)間隙鎖
-- 30記錄鎖
-- (30,+∞)間隙鎖

這種鎖定方式確保了在事務(wù)A執(zhí)行期間,其他事務(wù)無(wú)法在id>15的范圍內(nèi)插入任何新記錄。

間隙鎖的觸發(fā)條件

間隙鎖主要在以下情況下觸發(fā):

  1. 使用SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE
  2. UPDATE/DELETE語(yǔ)句使用索引進(jìn)行范圍條件查詢
  3. 事務(wù)隔離級(jí)別為可重復(fù)讀或串行化

性能注意:間隙鎖雖然解決了幻讀問(wèn)題,但會(huì)顯著降低并發(fā)性能。特別是在范圍較大的查詢時(shí),會(huì)鎖定大量間隙,導(dǎo)致其他事務(wù)長(zhǎng)時(shí)間等待。

四、完整實(shí)戰(zhàn):Java應(yīng)用中的幻讀解決方案

理解了理論后,我們通過(guò)一個(gè)完整的Java應(yīng)用示例來(lái)演示如何在實(shí)際開(kāi)發(fā)中處理幻讀問(wèn)題。

import java.sql.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PhantomReadSolution {
    private static final String URL = "jdbc:mysql://localhost:3306/bank";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    
    public static void main(String[] args) {
        // 初始化測(cè)試數(shù)據(jù)
        initTestData();
        
        // 創(chuàng)建線程池模擬并發(fā)
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        // 事務(wù)A:檢查并更新高余額賬戶
        executor.execute(() -> {
            try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
                // 設(shè)置為可重復(fù)讀隔離級(jí)別
                conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
                conn.setAutoCommit(false);
                
                System.out.println("【事務(wù)A】開(kāi)始,隔離級(jí)別:REPEATABLE_READ");
                
                // 第一次查詢:獲取高余額賬戶
                System.out.println("【事務(wù)A】第一次查詢:余額>1500的賬戶");
                queryHighBalanceAccounts(conn);
                
                // 模擬處理時(shí)間
                Thread.sleep(2000);
                
                // 第二次查詢:再次檢查
                System.out.println("【事務(wù)A】第二次查詢:余額>1500的賬戶");
                queryHighBalanceAccounts(conn);
                
                // 執(zhí)行更新操作
                System.out.println("【事務(wù)A】執(zhí)行更新:將高余額賬戶的余額增加10%");
                updateHighBalanceAccounts(conn);
                
                conn.commit();
                System.out.println("【事務(wù)A】提交事務(wù)");
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        
        // 事務(wù)B:插入新賬戶
        executor.execute(() -> {
            try {
                // 讓事務(wù)A先開(kāi)始
                Thread.sleep(500);
                
                try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
                    conn.setAutoCommit(false);
                    System.out.println("【事務(wù)B】開(kāi)始");
                    
                    // 插入新賬戶
                    System.out.println("【事務(wù)B】插入新賬戶:David,余額1800");
                    PreparedStatement stmt = conn.prepareStatement(
                        "INSERT INTO account (name, balance) VALUES (?, ?)");
                    stmt.setString(1, "David");
                    stmt.setDouble(2, 1800.00);
                    stmt.executeUpdate();
                    
                    conn.commit();
                    System.out.println("【事務(wù)B】提交事務(wù)");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        
        executor.shutdown();
    }
    
    private static void initTestData() {
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) {
            Statement stmt = conn.createStatement();
            stmt.execute("DROP TABLE IF EXISTS account");
            stmt.execute("CREATE TABLE account (" +
                         "id INT AUTO_INCREMENT PRIMARY KEY," +
                         "name VARCHAR(50)," +
                         "balance DECIMAL(10,2)," +
                         "INDEX idx_balance (balance))");
            stmt.execute("INSERT INTO account (name, balance) VALUES " +
                         "('Alice', 1000.00), ('Bob', 2000.00), ('Charlie', 3000.00)");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    private static void queryHighBalanceAccounts(Connection conn) throws SQLException {
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(
            "SELECT id, name, balance FROM account WHERE balance > 1500");
        
        System.out.println("高余額賬戶列表:");
        while (rs.next()) {
            System.out.printf("id=%d, name=%s, balance=%.2f%n",
                rs.getInt("id"), rs.getString("name"), rs.getDouble("balance"));
        }
        rs.close();
        stmt.close();
    }
    
    private static void updateHighBalanceAccounts(Connection conn) throws SQLException {
        // 使用FOR UPDATE加鎖,防止幻讀影響更新操作
        Statement stmt = conn.createStatement();
        int count = stmt.executeUpdate(
            "UPDATE account SET balance = balance * 1.1 " +
            "WHERE balance > 1500");
        System.out.println("更新了 " + count + " 條記錄");
        stmt.close();
    }
}

這個(gè)示例展示了在實(shí)際應(yīng)用中如何處理幻讀問(wèn)題:

  1. 使用REPEATABLE_READ隔離級(jí)別保證一致性視圖
  2. 在更新操作前使用查詢鎖定相關(guān)記錄
  3. 通過(guò)適當(dāng)?shù)逆i機(jī)制確保更新操作不受幻讀影響

五、高級(jí)主題與最佳實(shí)踐

1. 何時(shí)會(huì)突破InnoDB的幻讀防護(hù)

雖然InnoDB的可重復(fù)讀隔離級(jí)別在大多數(shù)情況下解決了幻讀問(wèn)題,但在某些特殊場(chǎng)景下仍可能出現(xiàn)幻讀:

  1. 混合使用快照讀和當(dāng)前讀:同一個(gè)事務(wù)中交替使用普通SELECT和SELECT FOR UPDATE
  2. 使用READ COMMITTED隔離級(jí)別:此時(shí)MVCC不防止幻讀
  3. 沒(méi)有使用索引的查詢:會(huì)導(dǎo)致全表掃描和鎖定

特別注意:在同一個(gè)事務(wù)中混合使用快照讀和當(dāng)前讀可能導(dǎo)致邏輯上的不一致。例如:

START TRANSACTION;
-- 快照讀
SELECT * FROM account WHERE balance > 1500; -- 看到2條記錄

-- 其他事務(wù)插入新記錄并提交

-- 當(dāng)前讀
SELECT * FROM account WHERE balance > 1500 FOR UPDATE; -- 看到3條記錄
-- 此時(shí)事務(wù)內(nèi)看到了"幻影行"

2. 性能優(yōu)化建議

在保證數(shù)據(jù)一致性的同時(shí),我們需要考慮性能優(yōu)化:

  • 合理設(shè)計(jì)索引:間隙鎖基于索引工作,良好的索引設(shè)計(jì)可以減少鎖定范圍
  • 控制事務(wù)粒度:避免長(zhǎng)時(shí)間運(yùn)行的事務(wù),減少鎖持有時(shí)間
  • 慎用SELECT FOR UPDATE:只在必要時(shí)使用,考慮使用樂(lè)觀鎖替代
  • 監(jiān)控鎖等待:定期檢查SHOW ENGINE INNODB STATUS中的鎖信息

3. 替代方案:樂(lè)觀鎖實(shí)現(xiàn)

在某些場(chǎng)景下,可以使用樂(lè)觀鎖替代間隙鎖來(lái)避免幻讀:

-- 添加版本號(hào)字段
ALTER TABLE account ADD COLUMN version INT DEFAULT 0;

-- 樂(lè)觀鎖更新
UPDATE account 
SET balance = balance * 1.1, version = version + 1
WHERE balance > 1500 AND version = #{oldVersion};

樂(lè)觀鎖通過(guò)版本號(hào)檢查實(shí)現(xiàn)并發(fā)控制,不會(huì)阻塞其他事務(wù),適合讀多寫(xiě)少的場(chǎng)景。

六、總結(jié)與知識(shí)體系

讓我們用思維導(dǎo)圖總結(jié)MySQL解決幻讀的完整知識(shí)體系:

關(guān)鍵要點(diǎn)回顧

  1. 幻讀是指在同一事務(wù)中看到新插入的行,是并發(fā)控制的核心問(wèn)題之一
  2. InnoDB通過(guò)MVCC和間隙鎖的組合,在REPEATABLE READ級(jí)別下解決了幻讀
  3. MVCC通過(guò)版本鏈和ReadView實(shí)現(xiàn)一致性讀,間隙鎖通過(guò)鎖定索引間隙防止新記錄插入
  4. 實(shí)際開(kāi)發(fā)中需要根據(jù)業(yè)務(wù)場(chǎng)景選擇合適的隔離級(jí)別和鎖策略
  5. 理解這些機(jī)制有助于設(shè)計(jì)高性能、高并發(fā)的數(shù)據(jù)庫(kù)應(yīng)用

總結(jié)

通過(guò)本文的深入探討,相信大家對(duì)MySQL如何解決幻讀問(wèn)題有了全面理解。在實(shí)際工作中,建議結(jié)合具體業(yè)務(wù)場(chǎng)景,權(quán)衡一致性和性能的需求,選擇最合適的解決方案。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • mysql如何將數(shù)據(jù)庫(kù)中的所有表結(jié)構(gòu)和數(shù)據(jù)導(dǎo)入到另一個(gè)庫(kù)

    mysql如何將數(shù)據(jù)庫(kù)中的所有表結(jié)構(gòu)和數(shù)據(jù)導(dǎo)入到另一個(gè)庫(kù)

    介紹了如何使用mysqldump命令備份和導(dǎo)入數(shù)據(jù)庫(kù),以及創(chuàng)建目標(biāo)數(shù)據(jù)庫(kù)的步驟,首先使用mysqldump備份源數(shù)據(jù)庫(kù),然后在目標(biāo)數(shù)據(jù)庫(kù)中創(chuàng)建數(shù)據(jù)庫(kù),并將備份文件導(dǎo)入到目標(biāo)數(shù)據(jù)庫(kù),確保數(shù)據(jù)結(jié)構(gòu)和內(nèi)容完整復(fù)制,提到了DataGrip、Navicat在導(dǎo)入導(dǎo)出過(guò)程中可能出現(xiàn)的問(wèn)題
    2024-10-10
  • MySQL數(shù)據(jù)庫(kù)聚合函數(shù)與分組查詢舉例詳解

    MySQL數(shù)據(jù)庫(kù)聚合函數(shù)與分組查詢舉例詳解

    在MySQL中聚合函數(shù)和分組查詢經(jīng)常一起使用,下面這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫(kù)聚合函數(shù)與分組查詢的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • MySQL超詳細(xì)實(shí)現(xiàn)用戶管理實(shí)例

    MySQL超詳細(xì)實(shí)現(xiàn)用戶管理實(shí)例

    MySQL 是一個(gè)多用戶數(shù)據(jù)庫(kù),具有功能強(qiáng)大的訪問(wèn)控制系統(tǒng),可以為不同用戶指定不同權(quán)限。在前面的章節(jié)中我們使用的是 root 用戶,該用戶是超級(jí)管理員,擁有所有權(quán)限,包括創(chuàng)建用戶、刪除用戶和修改用戶密碼等管理權(quán)限
    2022-06-06
  • 檢查并修復(fù)mysql數(shù)據(jù)庫(kù)表的具體方法

    檢查并修復(fù)mysql數(shù)據(jù)庫(kù)表的具體方法

    這篇文章介紹了檢查并修復(fù)mysql數(shù)據(jù)庫(kù)表的具體方法,有需要的朋友可以參考一下
    2013-09-09
  • MySQL數(shù)據(jù)類型詳解

    MySQL數(shù)據(jù)類型詳解

    本文詳細(xì)給大家介紹了MySQL數(shù)據(jù)類型的相關(guān)知識(shí),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-10-10
  • MySQL數(shù)據(jù)庫(kù)之索引詳解

    MySQL數(shù)據(jù)庫(kù)之索引詳解

    大家好,本篇文章主要講的是MySQL數(shù)據(jù)庫(kù)之索引詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • MySQL創(chuàng)建用戶以及用戶權(quán)限詳細(xì)圖文教程

    MySQL創(chuàng)建用戶以及用戶權(quán)限詳細(xì)圖文教程

    在MySQL中可以通過(guò)創(chuàng)建用戶來(lái)管理數(shù)據(jù)庫(kù)的訪問(wèn)權(quán)限,下面這篇文章主要給大家介紹了關(guān)于MySQL創(chuàng)建用戶以及用戶權(quán)限的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • MySQL中between and的基本用法詳解

    MySQL中between and的基本用法詳解

    文章介紹了MySQL中的BETWEEN AND操作符,它可以用于數(shù)值和日期類型的字段,包括邊界值,通過(guò)示例展示了如何使用BETWEEN AND進(jìn)行數(shù)值查詢和時(shí)間查詢,并強(qiáng)調(diào)了在處理datetime和timestamp類型時(shí)需要注意時(shí)間精度問(wèn)題,需要的朋友可以參考下
    2026-03-03
  • MySQL多表查詢的實(shí)現(xiàn)過(guò)程

    MySQL多表查詢的實(shí)現(xiàn)過(guò)程

    文章講解了SQL多表查詢的核心概念,包括笛卡爾積(交叉連接)、等值/非等值連接、自連接、內(nèi)/外連接分類,強(qiáng)調(diào)避免笛卡爾積需添加連接條件,區(qū)分列名并使用JOIN/ON語(yǔ)法,同時(shí)對(duì)比了UNION與UNION?ALL的區(qū)別,并提及MySQL中滿外連接的替代方法
    2025-10-10
  • Mariadb數(shù)據(jù)庫(kù)的備份與恢復(fù)過(guò)程詳細(xì)介紹

    Mariadb數(shù)據(jù)庫(kù)的備份與恢復(fù)過(guò)程詳細(xì)介紹

    MariaDB是一個(gè)流行的開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),備份與恢復(fù)數(shù)據(jù)是數(shù)據(jù)庫(kù)管理中非常重要的一個(gè)環(huán)節(jié),能夠保證數(shù)據(jù)的安全性和可靠性,這篇文章主要介紹了Mariadb數(shù)據(jù)庫(kù)的備份與恢復(fù)過(guò)程的相關(guān)資料,需要的朋友可以參考下
    2025-10-10

最新評(píng)論

全椒县| 武宁县| 达拉特旗| 龙口市| 汉中市| 华坪县| 天气| 玉屏| 呼伦贝尔市| 沂南县| 扎赉特旗| 巴林左旗| 三穗县| 潮安县| 大兴区| 平昌县| 手游| 深水埗区| 宁津县| 黄大仙区| 南部县| 霍林郭勒市| 江源县| 德兴市| 习水县| 抚宁县| 沙洋县| 阳朔县| 安化县| 平舆县| 虹口区| 海安县| 容城县| 塔城市| 来凤县| 扬州市| 法库县| 石嘴山市| 佛学| 当阳市| 巨鹿县|