SQLite數(shù)據(jù)庫精煉詳解

一、前期基礎(chǔ)知識(shí)儲(chǔ)備

Android本地化存儲(chǔ)三種方式:
①文件存儲(chǔ)吗讶,存儲(chǔ)簡單二進(jìn)制數(shù)據(jù)和文本數(shù)據(jù)袖裕;
②SharedPreference存儲(chǔ)曹抬,鍵值對(duì)存儲(chǔ),存儲(chǔ)數(shù)據(jù)類型多樣急鳄,存儲(chǔ)方式單一谤民;
③SQLite數(shù)據(jù)庫存儲(chǔ),Android內(nèi)置數(shù)據(jù)庫疾宏,存儲(chǔ)復(fù)雜關(guān)系型數(shù)據(jù)张足,質(zhì)的飛躍。

20181104130707322.png

SQLite正式發(fā)布于2000年灾锯,現(xiàn)在Android內(nèi)置的是SQLite3.0兢榨。占用幾百KB資源,但運(yùn)算速度飛快顺饮,非常適合在移動(dòng)設(shè)備上使用。SQLite數(shù)據(jù)庫使用時(shí)會(huì)涉及到三個(gè)類:
①SQLiteOpenHelper:Android系統(tǒng)提供的操作SQLite數(shù)據(jù)庫的方式凌那。工具類 抽象類兼雄,我們通過繼承該類,然后重寫數(shù)據(jù)庫創(chuàng)建以及更新的方法帽蝶,我們還可以通過該類的對(duì)象獲得數(shù)據(jù)庫實(shí)例或者關(guān)閉數(shù)據(jù)庫赦肋。
②SQliteDatabase:平常數(shù)據(jù)庫操作方式使用的類,數(shù)據(jù)庫訪問類——我們可以通過該類的對(duì)象來直接使用操作數(shù)據(jù)庫的方式對(duì)數(shù)據(jù)庫做增刪改查的操作。(見用于佃乘,熟悉數(shù)據(jù)庫語法的大牛)
③Cursot:游標(biāo)囱井,有點(diǎn)類似于JDBC里的resultset,結(jié)果集趣避!可以簡單理解為指向數(shù)據(jù)庫中某一記錄的指針庞呕。使用可以同平常數(shù)據(jù)庫一樣,也可以使用Android系統(tǒng)提供的操作方式程帕。
本篇博客住练,主要分析Android系統(tǒng)內(nèi)置的操作數(shù)據(jù)庫的方式,所以打交道的類只有兩個(gè):SQLiteOpenHelper和Cursot愁拭。

二讲逛、上代碼,具體分析

1)使用SQLiteOpenHelper創(chuàng)建數(shù)據(jù)庫

①SQLiteOpenHelper 是一個(gè)抽象類岭埠,如果需要使用它的話盏混,就需要?jiǎng)?chuàng)建一個(gè)幫助類去繼承它;
②抽象父類SQLiteOpenHelper 中有兩個(gè)抽象方法:onCreate()onUpdate()惜论,需要在子類里重寫這兩個(gè)方法括饶,然后分別在這兩個(gè)方法中去實(shí)現(xiàn)創(chuàng)建和升級(jí)數(shù)據(jù)庫的邏輯;
新建 MyDatabaseHelper 類繼承自 SQLiteOpenHelper来涨,代碼如下:

public class MyDatabaseHelper extends SQLiteOpenHelper {
    public static final String CREATE_BOOK = "CREATE TABLE book ("
            + "id  integer PRIMARY KEY Autoincrement ,"
            + "author text ,"
            + "price real ,"
            + "pages integer,"
            + "name text )";
    /**
     * integer:整形
     * real:浮點(diǎn)型
     * text:文本類型
     * blob:二進(jìn)制類型
     * PRIMARY KEY將id列設(shè)置為主鍵
     * AutoIncrement關(guān)鍵字表示id列是自動(dòng)增長的
     */

    private Context myContent;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        myContent = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建數(shù)據(jù)庫的同時(shí)創(chuàng)建Book表
        db.execSQL(CREATE_BOOK);
        //提示數(shù)據(jù)庫創(chuàng)建成功
        Toast.makeText(myContent, "數(shù)據(jù)庫創(chuàng)建成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

③SQLiteOpenHelper 中另外兩個(gè)非常重要的實(shí)例方法图焰,getReadableDatabase() (查)和 getWritableDatabase()(增刪改)。這兩種方法都可以創(chuàng)建或打開一個(gè)現(xiàn)有的數(shù)據(jù)庫(如果數(shù)據(jù)庫已存在則直接打開蹦掐,否則創(chuàng)建一個(gè)新的數(shù)據(jù)庫)技羔,并返回一個(gè)可對(duì)數(shù)據(jù)庫進(jìn)行增刪改查操作的對(duì)象;
④子類需要重寫父類SQLiteOpenHelper 的兩個(gè)構(gòu)造方法卧抗,第二個(gè)構(gòu)造方法接收四個(gè)參數(shù)藤滥,第一個(gè)參數(shù)是 Context,必須要有Context對(duì)象才能對(duì)數(shù)據(jù)庫進(jìn)行操作社裆。第二個(gè)參數(shù)是數(shù)據(jù)庫名拙绊,創(chuàng)建數(shù)據(jù)庫時(shí)使用的就是這里指定的名稱。第三個(gè)參數(shù)允許在查詢數(shù)據(jù)庫的時(shí)候返回一個(gè)自定義的 Cursor泳秀,一般傳入null标沪。第四個(gè)參數(shù)表示當(dāng)前數(shù)據(jù)庫的版本號(hào),可用于對(duì)數(shù)據(jù)庫進(jìn)行升級(jí)操作嗜傅。

構(gòu)建出 SQLiteOpenHelper 的實(shí)例之后金句,再調(diào)用它的 getReadableDatabase() 或 getWritableDatabase() 方法就能夠創(chuàng)建數(shù)據(jù)庫了,數(shù)據(jù)庫文件會(huì)存放在 /data/data/<包名>/database/ 目錄下吕嘀。利用Android Studio右下角工具可直接查看违寞。

在 MainActivity 中進(jìn)行測(cè)試贞瞒,代碼如下:

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //構(gòu)建一個(gè) MyDatabaseHelper 對(duì)象,通過構(gòu)造函數(shù)將數(shù)據(jù)庫名指定為 BookStore.db
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabase = (Button)findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 *調(diào)用getWritableDatabase() 方法
                 * 自動(dòng)檢測(cè)當(dāng)前程序中 BookStore.db 這個(gè)數(shù)據(jù)庫
                 * 如果不存在則創(chuàng)建該數(shù)據(jù)庫并調(diào)用 onCreate() 方法
                 * 同時(shí)Book表也會(huì)被創(chuàng)建
                 */
                dbHelper.getWritableDatabase();
            }
        });
    }
}

點(diǎn)擊按鈕 BookStore.db 數(shù)據(jù)庫和 Book 表就已經(jīng)創(chuàng)建成功了趁曼,再次點(diǎn)擊不會(huì)再有Toast彈出军浆。

2)使用SQLiteOpenHelper升級(jí)數(shù)據(jù)庫

onUpdate() 方法是用于對(duì)數(shù)據(jù)庫進(jìn)行升級(jí)的,它在整個(gè)數(shù)據(jù)庫的管理工作中擔(dān)當(dāng)著非常重要的作用挡闰。
目前 BookStore.db 中已經(jīng)有一張 Book 表用于存放書的各種詳細(xì)數(shù)據(jù)乒融,接下來再添加一張 Category 表用于記錄書籍的分類。將建表語句添加到 MyDatabaseHelper 中尿这,代碼如下:

    public static final String CREATE_CATEGORY = "CREATE TABLE category ("
            + "id integer PRIMARY KEY Autoincrement , "
            + "category_name text , "
            + "category_code integer )";

并在 onCreate()方法中添加:db.execSQL( CREATE_CATEGORY); 這條語句簇抵,運(yùn)行程序,并不會(huì)彈出創(chuàng)建成功的提示射众。因?yàn)榇藭r(shí) BookStore.db 數(shù)據(jù)庫已經(jīng)存在了碟摆,之后不論怎樣點(diǎn)擊創(chuàng)建按鈕,MyDatabaseHelper 中的 onCreate() 方法都不會(huì)再次執(zhí)行叨橱,因此新添加的表也就無法得到創(chuàng)建了典蜕。
只需要巧妙的運(yùn)用 SQLiteOpenHelper 的升級(jí)功能就可以很輕松的解決這個(gè)問題。
修改 MyDatabaseHelper 中的代碼罗洗,如下所示:

 @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建Book表和Category表
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        //提示數(shù)據(jù)庫創(chuàng)建成功
        Toast.makeText(myContent, "數(shù)據(jù)庫創(chuàng)建成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        /**
         * 如果發(fā)現(xiàn)數(shù)據(jù)庫中已經(jīng)存在 Book 表或 Category 表
         * 就將這兩張表刪除掉愉舔,然后調(diào)用 onCreate() 方法重新創(chuàng)建
         * 如果在創(chuàng)建表時(shí)發(fā)現(xiàn)表已經(jīng)存在,就會(huì)直接報(bào)錯(cuò)
         */
        db.execSQL("DROP TABLE IF EXISTS Book");
        db.execSQL("DROP TABLE IF EXISTS Category");
        onCreate(db);
    }

接下來的問題就是如何讓 onUpgrade() 方法能夠得到執(zhí)行了伙菜,還記得 SQLiteOpenHelper 的構(gòu)造方法里接受的第四個(gè)參數(shù)嗎轩缤?它表示當(dāng)前數(shù)據(jù)庫的版本號(hào),之前我們傳入的是1贩绕,現(xiàn)在只要傳入一個(gè)比1大的數(shù)火的,就可以讓 onUpgrade() 方法得到執(zhí)行了,修改MainActivity 中的代碼:

dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);

這里將數(shù)據(jù)庫版本號(hào)指定為2淑倾,表示我們對(duì)數(shù)據(jù)庫進(jìn)行升級(jí)了馏鹤。重新運(yùn)行程序,并點(diǎn)擊創(chuàng)建數(shù)據(jù)庫按鈕娇哆,這時(shí)就會(huì)再次彈出創(chuàng)建成功的提示湃累。
升級(jí)數(shù)據(jù)庫的最佳方式:
粗暴的刪除當(dāng)前所有的表來達(dá)到更新的效果,對(duì)于用戶來說是非常糟糕的碍讨,因?yàn)橐郧俺绦蛑写鎯?chǔ)的本地?cái)?shù)據(jù)全部丟失了治力。其實(shí)只需進(jìn)行一些合理的控制,就可以保證升級(jí)數(shù)據(jù)庫的時(shí)候數(shù)據(jù)并不會(huì)丟失了垄开。

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
            case 1:
                db.execSQL(CREATE_CATEGORY);
            default:
        }
    }

每一個(gè)數(shù)據(jù)庫版本都會(huì)對(duì)應(yīng)一個(gè)版本號(hào)琴许,當(dāng)指定的數(shù)據(jù)庫版本號(hào)大于當(dāng)前數(shù)據(jù)庫版本號(hào)的時(shí)候,就會(huì)進(jìn)入到 onUpgrade()方法中去執(zhí)行更新操作溉躲。這里需要為每一個(gè)版本號(hào)賦予它各自改變的內(nèi)容榜田,然后在 onUpgrade()方法中對(duì)當(dāng)前數(shù)據(jù)庫的版本進(jìn)行判斷,再執(zhí)行相應(yīng)的改變就可以了锻梳。
注意箭券,switch 中每一個(gè) case 的最后都是沒有使用 break 的,這是為了保證跨版本升級(jí)的時(shí)候疑枯,每一次的數(shù)據(jù)庫修改都能被全部執(zhí)行辩块。使用這種方式來維護(hù)數(shù)據(jù)庫的升級(jí),不管版本怎樣更新荆永,都可以保證數(shù)據(jù)庫的表結(jié)構(gòu)是最新的废亭,而且表中的數(shù)據(jù)也完全不會(huì)丟失。

3)使用SQLiteOpenHelper升級(jí)數(shù)據(jù)庫

注:這里使用的Android內(nèi)置的一系列輔助方法具钥,即使用SQLiteOpenHelper操作數(shù)據(jù)庫豆村,并不是使用SQliteDatabase直接操作數(shù)據(jù)表。
①添加數(shù)據(jù)-insert()
SQLiteDatabase 中提供了一個(gè) insert() 方法骂删,用于添加數(shù)據(jù)掌动。
insert() 方法接收三個(gè)參數(shù),第一個(gè)參數(shù)是表名宁玫,我們希望向哪張表里添加數(shù)據(jù)粗恢,這里就傳入該表的名字。第二個(gè)參數(shù)用于在未指定添加數(shù)據(jù)的情況下給某些可為空的列自動(dòng)賦值NULL欧瘪,一般用不到這個(gè)功能眷射,直接傳入 null 即可。第三個(gè)參數(shù)是一個(gè) ContentValues 對(duì)象佛掖,它提供了一系列的 put() 方法重載妖碉,用于向 ContentValues 中添加數(shù)據(jù),只需要將表中的每個(gè)列名及相對(duì)應(yīng)的待添加數(shù)據(jù)傳入即可苦囱。
MainActivity中代碼如下:

            public void onClick(View v) {
                //獲取 SQLiteDatabase 對(duì)象
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                //使用ContentValues 對(duì)數(shù)據(jù)進(jìn)行組裝
                ContentValues values = new ContentValues();
                //開始組裝第一條數(shù)據(jù)
                values.put("name", "The Da Vinci Code");
                values.put("author", "Dan Brown");
                values.put("pages", 454);
                values.put("price", 16.96);
                //插入第一條數(shù)據(jù)
                db.insert("Book", null, values);
                values.clear();
                //開始組裝第二條數(shù)據(jù)
                values.put("name", "The Lost Symbol");
                values.put("author", "Dan Brown");
                values.put("pages", 510);
                values.put("price", 19.95);
                //插入第二條數(shù)據(jù)
                db.insert("Book", null, values);
            }

這里只對(duì)Book表里其中四列的數(shù)據(jù)進(jìn)行了組裝嗅绸,id并沒有賦值。因?yàn)閯?chuàng)建表的時(shí)候就將 id 列設(shè)置為自動(dòng)增長了撕彤,它的值會(huì)在入庫的時(shí)候自動(dòng)生成鱼鸠,不需要手動(dòng)賦值。
②更新數(shù)據(jù)-update()
SQLiteDatabase 中提供了一個(gè)非常好用的 update() 方法用于對(duì)數(shù)據(jù)進(jìn)行更新羹铅,這個(gè)方法接收四個(gè)參數(shù)蚀狰,第一個(gè)參數(shù)和 insert()方法一樣,也是表名职员,在這里指定去更新哪張表里的數(shù)據(jù)麻蹋。第二個(gè)參數(shù)是 ContentValues 對(duì)象,把要更新的數(shù)據(jù)在這里組裝進(jìn)去焊切。第三扮授、第四個(gè)參數(shù)用于去約束更新某一行的數(shù)據(jù)芳室,不指定的話默認(rèn)就是更新所有行。
MainActivity中代碼如下:

            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 10.99);
                //?是一個(gè)占位符刹勃,通過字符串?dāng)?shù)組為每個(gè)占位符指定相應(yīng)的內(nèi)容
                db.update("Book", values, "name = ?", new String[]{"The Da Vinci Code"});
            }

③刪除數(shù)據(jù)-delete()
SQLiteDatabase 中提供了一個(gè) delete()方法專門用于刪除數(shù)據(jù)堪侯,這個(gè)方法接收三個(gè)參數(shù),第一個(gè)參數(shù)仍然是表名荔仁,第二伍宦、第三個(gè)參數(shù)用于約束刪除某一行或某幾行的數(shù)據(jù),不指定的話默認(rèn)就是刪除所有行乏梁。
MainActivity中代碼如下:

            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages > ?", new String[]{"500"});
            }

④查詢數(shù)據(jù)-query()次洼,會(huì)使用到第三個(gè)類Cursor游標(biāo)類
SQLiteDatabase 中提供了一個(gè) query() 方法用于對(duì)數(shù)據(jù)進(jìn)行查詢。這個(gè)方法的參數(shù)非常復(fù)雜遇骑,最短的一個(gè)方法重載也需要傳入七個(gè)參數(shù)卖毁。
query()方法參數(shù)及對(duì)應(yīng)SQL:

table:指定查詢的表名,對(duì)應(yīng) from table_name
columns:指定查詢的列名质蕉,對(duì)應(yīng) select column1,column2 ...
selection:指定 where 的約束條件势篡,where column = value
selectionArgs:為 where 中的占位符提供具體的值
groupBy:指定需要分組的列,group by column
having:對(duì)分組后的結(jié)果進(jìn)一步約束模暗,having column = value
orderBy:指定查詢結(jié)果的排序方式禁悠,order by column

雖然 query()方法的參數(shù)非常多,但是不必每條查詢語句都指定上所有的參數(shù)兑宇,多數(shù)情況下只需傳入少數(shù)幾個(gè)參數(shù)就可以完成查詢操作了碍侦。
調(diào)用 query()方法后會(huì)返回一個(gè) Cursor 對(duì)象,查詢到的所有數(shù)據(jù)都將從這個(gè)對(duì)象中取出隶糕。
MainActivity中代碼如下:

            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                //查詢Book表中的所有數(shù)據(jù)
                Cursor cursor = db.query("Book", null, null, null, null, null, null, null);
                //遍歷Curosr對(duì)象瓷产,取出數(shù)據(jù)并打印
                while (cursor.moveToNext()) {
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    String author = cursor.getString(cursor.getColumnIndex("author"));
                    int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                    double price = cursor.getDouble(cursor.getColumnIndex("price"));
                    Log.d("woider", "Book Name:" + name + " Author:" 
                            + author + " Pages:" + pages + " Price:" + price);
                }
                //關(guān)閉Cursor
                cursor.close();
            }

執(zhí)行 query()方法之后會(huì)得到一個(gè) Cursor對(duì)象,然后通過 Cursor 對(duì)象的 moveToNext()方法去遍歷查詢到的每一行數(shù)據(jù)枚驻。在這個(gè)循環(huán)中可以通過 Cursor 的 getColumnIndex() 方法獲取到某一列在表中對(duì)應(yīng)位置的索引濒旦,然后將這個(gè)索引傳入到相應(yīng)的取值方法中,就可以得到從數(shù)據(jù)庫中讀取到的數(shù)據(jù)了再登。
最后別忘了調(diào)用 close()方法來關(guān)閉 Cursor尔邓。(不關(guān)閉Cursor會(huì)造成內(nèi)存泄漏)
游標(biāo)Cursor的相關(guān)操作:
遍歷游標(biāo):

        while(c.moveToNext()){
              int id=c.getInt(c.getColumnName(列名ID));
              String name=c.getString(c.getColumnIndex(字段名NAME));
        }

常用方法:

(1)move(int offset);將指針上下移動(dòng)offset個(gè)記錄。若offset值為正數(shù)則向下移動(dòng)锉矢,若為負(fù)數(shù)則向上移動(dòng)梯嗽。
(2)boolean moveToFirst();指針移至結(jié)果集的第一個(gè)記錄。若移動(dòng)成功則返回true,否則返回false沽损。
(3)boolean moveToLast();指針移至結(jié)果集的最后一個(gè)記錄灯节。若移動(dòng)成功則返回true,否則返回false。
(4)boolean moveToNext();指針向后移動(dòng)一條記錄,若移動(dòng)成功則返回true,否則返回false炎疆。
(5)boolean moveToPrevious();指針向前移動(dòng)一條記錄卡骂,若移動(dòng)成功則返回true,否則返回false磷雇。
(6)isLast();若指針在Cursor結(jié)果集的最后一條記錄偿警,則返回true躏救,否則返回false唯笙。
(7)isAfterLast();若指針在Cursor結(jié)果集最后一條記錄之后,則返回true盒使,否則返回false崩掘。
(8)isFirst();若指針在Cursor結(jié)果集的第一條記錄,則返回true少办,否則返回false苞慢。
(9)isBeforeFirst();若指針在Cursor結(jié)果集的第一條記錄之前,則返回true英妓,否則返回false挽放。
(10)isClose();Cursot對(duì)象是否關(guān)閉,若關(guān)閉則返回true蔓纠,否則返回false辑畦。
(11)int getColumnIndex(String columnName);獲得指定列的索引值。
(12)String getString(int columnIndex);按列的索引獲取字符串類型的數(shù)據(jù)腿倚。

------------------------------------SQLiteOpenHelper分割線------------------------------------

4)SQLiteDatabase數(shù)據(jù)庫相關(guān)操作

上面的數(shù)據(jù)庫操作都是利用SQLiteOpenHelper進(jìn)行的纯出,有興趣的讀者也可嘗試下直接使用SQLite自帶的數(shù)據(jù)庫語言進(jìn)行數(shù)據(jù)庫的操作。
SQLiteDatabase數(shù)據(jù)庫類:提供了針對(duì)數(shù)據(jù)庫的增 刪 改 查的操作敷燎。
注:除了Cursor游標(biāo)對(duì)象暂筝、SQLiteDatabase數(shù)據(jù)庫對(duì)象也需要關(guān)閉。
SQLiteDatabase db=openOrCreateDatabase("students.db",MODE_PRIVATE,null);如果數(shù)據(jù)庫不存在則執(zhí)行創(chuàng)建操作硬贯,存在則執(zhí)行打開操作焕襟。
db.execSQL("create table if not exists student (_id integer primary key autoincrement,name varchar(20),age integer)");創(chuàng)建數(shù)據(jù)表,如果存在則不創(chuàng)建饭豹。
db.execSQL("insert into student(_id,name,age)values(null,?,?)",new Object[]{"張立冬",25});插入數(shù)據(jù)鸵赖;
db.execSQL("delete from student where name='張立冬'");刪除數(shù)據(jù);
db.execSQL("update student set name=?,age=?",new Object[]{"小明",18});修改數(shù)據(jù)墨状;

    Cursor c=db.rawQuery("select * from student",null);查詢數(shù)據(jù)——返回游標(biāo)(結(jié)果集)卫漫;
    while(c.moveToNext()){將游標(biāo)移到下一行,存在數(shù)據(jù)返回true肾砂,不存在數(shù)據(jù)返回false列赎;
         int id=c.getInt(c.getColumnIndex("_id"));獲得對(duì)應(yīng)列名中該行的整型數(shù)據(jù);
         String name=c.getString(c.getColumnIndex("name"));獲得對(duì)應(yīng)列名中該行的字符串?dāng)?shù)據(jù);
         int age=c.getInt(c.getColumnIndex("age"));獲得對(duì)應(yīng)列名中該行的整型數(shù)據(jù)
}

注意:增刪改使用的是execSQL()方法包吝,查詢用的是rawQuery()方法饼煞。

注:博主博客會(huì)同步發(fā)布到CSDN,歡迎讀者閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诗越,一起剝皮案震驚了整個(gè)濱河市砖瞧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嚷狞,老刑警劉巖块促,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異床未,居然都是意外死亡竭翠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門薇搁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斋扰,“玉大人,你說我怎么就攤上這事啃洋〈酰” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵宏娄,是天一觀的道長问裕。 經(jīng)常有香客問我,道長绝编,這世上最難降的妖魔是什么僻澎? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮十饥,結(jié)果婚禮上窟勃,老公的妹妹穿的比我還像新娘。我一直安慰自己逗堵,他們只是感情好秉氧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜒秤,像睡著了一般汁咏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上作媚,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天攘滩,我揣著相機(jī)與錄音,去河邊找鬼纸泡。 笑死漂问,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚤假,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼栏饮,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了磷仰?” 一聲冷哼從身側(cè)響起袍嬉,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灶平,沒想到半個(gè)月后伺通,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡民逼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年泵殴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拼苍。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖调缨,靈堂內(nèi)的尸體忽然破棺而出疮鲫,到底是詐尸還是另有隱情,我是刑警寧澤弦叶,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布俊犯,位于F島的核電站,受9級(jí)特大地震影響伤哺,放射性物質(zhì)發(fā)生泄漏燕侠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一立莉、第九天 我趴在偏房一處隱蔽的房頂上張望绢彤。 院中可真熱鬧,春花似錦蜓耻、人聲如沸茫舶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饶氏。三九已至,卻和暖如春有勾,著一層夾襖步出監(jiān)牢的瞬間疹启,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工蔼卡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喊崖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像贷祈,于是被迫代替她去往敵國和親趋急。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345