IOS 中使用 SQLite

12-(掌握)代碼實(shí)現(xiàn)SQLite-DDL

    1. 創(chuàng)建一個Swift項(xiàng)目
    2. 導(dǎo)入系統(tǒng)框架 sqlite3.tbd(sqlite3.dylib)
      在Xcode->build Phases->Link Binary With Libraries
    3. 建立橋接文件, 導(dǎo)入頭文件sqlite3.h
      1. 新建一個.h 頭文件
      2. 設(shè)置為橋接文件
  • 4.代碼實(shí)現(xiàn)
    1. 打開數(shù)據(jù)庫
// 1. 打開數(shù)據(jù)庫
        let docDir: String! = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).first
        // SQlite3數(shù)據(jù)庫文件的擴(kuò)展名沒有一個標(biāo)準(zhǔn)定義涕癣,比較流行的選擇是.sqlite3唱逢、.db哈误、.db3
        let fileName: String = docDir + "/demo.sqlite"
        /**
         *  sqlite3_open 使用這個函數(shù)打開一個數(shù)據(jù)庫
         *  參數(shù)一: 需要打開的數(shù)據(jù)庫文件路徑
         *  參數(shù)二: 一個指向SQlite3數(shù)據(jù)結(jié)構(gòu)的指針, 到時候操作數(shù)據(jù)庫都需要使用這個對象
         *  功能作用: 如果需要打開數(shù)據(jù)庫文件路徑不存在, 就會創(chuàng)建該文件;如果存在, 就直接打開; 可通過返回值, 查看是否打開成功
         */
        if sqlite3_open(fileName, &db) != SQLITE_OK {
            print("打開數(shù)據(jù)庫失敗")
        }else {
            print("打開數(shù)據(jù)庫成功")
        }
  1. 使用打開的數(shù)據(jù)庫, 執(zhí)行DDL語句, 創(chuàng)建一個數(shù)據(jù)庫表
// 創(chuàng)建SQL語句
        let sql = "CREATE TABLE IF NOT EXISTS t_student (name TEXT, age INTEGER, score text, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)"
        // 執(zhí)行SQL語句
        // 參數(shù)一: 數(shù)據(jù)庫
        // 參數(shù)二: 需要執(zhí)行的SQL語句
        // 參數(shù)三: 回調(diào)結(jié)果, 執(zhí)行完畢之后的回調(diào)函數(shù), 如果不需要置為NULL
        // 參數(shù)四: 參數(shù)三的第一個參數(shù), 刻意通過這個傳值給回調(diào)函數(shù) 如果不需要置為NULL
        // 參數(shù)五: 錯誤信息, 通過傳遞一個地址, 賦值給外界, 如果不需要置為NULL
        if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK
        {
            print("創(chuàng)建表失敗")
        }else
        {
            print("創(chuàng)建表成功")
        }

4.3. 使用打開的數(shù)據(jù)庫, 執(zhí)行DDL語句, 刪除一個數(shù)據(jù)庫表

let sql = "DROP TABLE IF EXISTS t_student2"
        if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK
        {
            print("刪除表失敗")
        }else
        {
            print("刪除表成功")
        }

4.4. 將數(shù)據(jù)庫操作封裝成一個工具類

class SqliteTool: NSObject {
    static let shareTool = SqliteTool()
    var db : OpaquePointer? = nil
    override init() {
        super.init()        
        let path = "/Users/luosu/Downloads/11資料/09實(shí)用技術(shù)學(xué)習(xí)/練習(xí)/sql/demo.sqlite"
        if sqlite3_open(path, &db) == SQLITE_OK
        {
            print("執(zhí)行成功")
        }
        else
        {
            print("執(zhí)行失敗")
        }
    }
    func createTable(){
        let sql = "create table if not exists t_stu (id integer primary key autoincrement, name text not null, age integer, score real default 60)"
        if execute(sql: sql) {
            print("yes")
        }
    }
    func dropTable()
    {
        let sql = "drop table if exists t_stu"
        if execute(sql: sql) {
            print("yes")
        }
    }
    func execute(sql:String) -> Bool {
        return (sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK)
    }
}

13-(掌握)代碼實(shí)現(xiàn)DML語句-Insert

  • 13.1. 創(chuàng)建一個Student類
    屬性
    name
    age
    構(gòu)造方法
    init(name: String, age: Int)
class Student: NSObject {
    var name : String = ""
    var age :Int = 0
    var score: Float = 0.0
    init(name:String, age: Int, score:Float) {
        super.init()
        self.name = name
        self.age = age
        self.score = score
    }
    ///添加學(xué)生
    class func inertStudent(stu: Student)  {
        let sql = "insert into t_stu(name, age, score) values('\(stu.name)', \(stu.age), \(stu.score))"
        if SqliteTool.shareTool.execute(sql: sql)
        {
            print("添加學(xué)生成功")
        }
    }
    ///刪除學(xué)生
    static func deleteStudent(name:String)
    {
        let sql = "delete from t_stu where name = '\(name)'"
        if SqliteTool.shareTool.execute(sql: sql)
        {
            print("刪除學(xué)生成功")
        }
        
    }
    class func alterStudent(newStu:Student)
    {
        let sql = "update t_stu set name= '\(newStu.name)' , age= \(newStu.age), score = \(newStu.score) where name = '\(newStu.name)'"
        if SqliteTool.shareTool.execute(sql: sql)
        {
            print("修改學(xué)生成功")
        }   
    }
}
  • 13.2. 創(chuàng)建數(shù)據(jù)庫操作方法
    數(shù)據(jù)庫中, 對Student對象的操作封裝
    insertStudent()

14-(了解)代碼實(shí)現(xiàn)DML語句-Insert綁定參數(shù)

  • 準(zhǔn)備語句(prepared statement)對象
    準(zhǔn)備語句(prepared statement)對象一個代表一個簡單SQL語句對象的實(shí)例烤镐,這個對象通常被稱為“準(zhǔn)備語句”或者“編譯好的SQL語句”或者就直接稱為“語句”洁闰。
  • 操作歷程
  1. 使用sqlite3_prepare_v2或相關(guān)的函數(shù)創(chuàng)建這個對象
    如果執(zhí)行成功筐付,則返回SQLITE_OK辩尊,否則返回一個錯誤碼
  2. 使用sqlite3_bind_*()給宿主參數(shù)(host parameters)綁定值
    sqlite3_bind_text()
    參數(shù)1: 準(zhǔn)備語句
    參數(shù)2: 綁定的參數(shù)索引 (從1開始)
    參數(shù)3: 綁定的參數(shù)內(nèi)容
    參數(shù)4: 綁定的參數(shù)長度 (-1代表自動計(jì)算長度)
    參數(shù)5:參數(shù)的處理方式
    SQLITE_TRANSIENT 會對字符串做一個 copy只锻,SQLite 選擇合適的機(jī)會釋放
    SQLITE_STATIC / nil 把它當(dāng)做全局靜態(tài)變量, 不會字符串做任何處理,如果字符串被釋放樱溉,保存到數(shù)據(jù)庫的內(nèi)容可能不正確挣输!
    注意: swift中沒有宏的概念
    // 替換 sqlite3.h 中的宏
    private let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
  3. 通過調(diào)用sqlite3_step()一次或多次來執(zhí)行這個sql
    對于DML語句, 如果執(zhí)行成功, 返回SQLITE_DONE
    對于DQL語句, 通過多次執(zhí)行獲取結(jié)果集, 繼續(xù)執(zhí)行的條件是返回值 SQLITE_ROW
  4. 使用sqlite3_reset()重置這個語句,然后回到第2步福贞,這個過程做0次或多次
  5. 使用sqlite3_finalize()銷毀這個對象, 防止內(nèi)存泄露

    class func binInserStudent(){
        let sql = "insert into t_stu(name, age, score) values(?, ?, ?)"
        //1.使用sqlite3_prepare_v2或相關(guān)的函數(shù)創(chuàng)建這個對象
        //參數(shù)3去除字符串的長度
        //參數(shù)4 預(yù)處理的語句
        //參數(shù)5撩嚼,參數(shù)3取出之后剩余的參數(shù)
        var stmt :OpaquePointer? = nil
        if sqlite3_prepare_v2(SqliteTool.shareTool.db, sql, -1, &stmt, nil) != SQLITE_OK
        {
            print("創(chuàng)建準(zhǔn)備語句失敗")
        }
        
        //2.使用sqlite3_bind_*()給宿主參數(shù)(host parameters)綁定值
        //參數(shù)1 準(zhǔn)備語句
        //參數(shù)2 綁定值的索引
        //參數(shù)3,需要綁定的值
        sqlite3_bind_int(stmt, 2, 33)
        sqlite3_bind_double(stmt, 3, 67.5)
        let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
        sqlite3_bind_text(stmt, 1, "lilei", -1, SQLITE_TRANSIENT)
        //3.通過調(diào)用`sqlite3_step() `一次或多次來執(zhí)行這個sql
        if sqlite3_step(stmt) == SQLITE_DONE {
            print("執(zhí)行成功")
        }
        //4.使用sqlite3_reset()重置這個語句挖帘,然后回到第2步
        sqlite3_reset(stmt)
        //5.使用sqlite3_finalize()銷毀這個對象, 防止內(nèi)存泄露
        sqlite3_finalize(stmt)
    }    

上面這種方式比原始的效率更高完丽,但是把第一步和第五步分解出來,循環(huán)中間的3步

優(yōu)化方案拇舀,如果使用的是sqlite3_exec或者是sqlite3——step這種方式執(zhí)行語句逻族,他會自動開啟一個事務(wù),然后自動提交這個事務(wù)
解決方案:我們要手動開始和關(guān)閉事務(wù)骄崩,這時候函數(shù)內(nèi)部就不會自動開始和提交事務(wù)
經(jīng)過計(jì)算可得 普通的插入1000條數(shù)據(jù)大概16是聘鳞,bind虛幻2、3要拂、4步大概4秒抠璃,而手動開啟和關(guān)閉事務(wù)之需要0.02秒


    class func binInserStudent(){
        let sql = "insert into t_stu(name, age, score) values(?, ?, ?)"
        //1.使用sqlite3_prepare_v2或相關(guān)的函數(shù)創(chuàng)建這個對象
        //參數(shù)3去除字符串的長度
        //參數(shù)4 預(yù)處理的語句
        //參數(shù)5,參數(shù)3取出之后剩余的參數(shù)
        var stmt :OpaquePointer? = nil
        if sqlite3_prepare_v2(SqliteTool.shareTool.db, sql, -1, &stmt, nil) != SQLITE_OK
        {
            print("創(chuàng)建準(zhǔn)備語句失敗")
        }
        SqliteTool.shareTool.beginTransaction()
        for _ in 0..<1000
        {
            //2.使用sqlite3_bind_*()給宿主參數(shù)(host parameters)綁定值
            //參數(shù)1 準(zhǔn)備語句
            //參數(shù)2 綁定值的索引
            //參數(shù)3脱惰,需要綁定的值
            sqlite3_bind_int(stmt, 2, 33)
            sqlite3_bind_double(stmt, 3, 67.5)
            let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
            sqlite3_bind_text(stmt, 1, "lilei", -1, SQLITE_TRANSIENT)
            //3.通過調(diào)用sqlite3_step() 一次或多次來執(zhí)行這個sql
            if sqlite3_step(stmt) == SQLITE_DONE {
                print("執(zhí)行成功")
            }
            //4.使用sqlite3_reset()重置這個語句搏嗡,然后回到第2步
            sqlite3_reset(stmt)
        }
        SqliteTool.shareTool.commitTransaction()
        //5.使用sqlite3_finalize()銷毀這個對象, 防止內(nèi)存泄露
        sqlite3_finalize(stmt)
    }

15-(掌握代碼實(shí)現(xiàn))DML語句-Insert插入數(shù)據(jù)優(yōu)化

  • 測試方式
    循環(huán)插入10000條數(shù)據(jù), 查看耗時
  • 測試步驟
    sqlite_exec 直接執(zhí)行
    未拆解"準(zhǔn)備語句" 執(zhí)行
    拆解后的"準(zhǔn)備語句" 執(zhí)行
  • 手動開啟事務(wù)后:
    sqlite_exec 直接執(zhí)行
    拆解后的"準(zhǔn)備語句" 執(zhí)行
    CFAbsoluteTimeGetCurrent()獲取當(dāng)前時間對應(yīng)的秒數(shù)
  • 測試結(jié)果
    1. 插入10000條數(shù)據(jù), sqlite_exec 直接執(zhí)行, 未拆解"準(zhǔn)備語句" 執(zhí)行, 拆解后的"準(zhǔn)備語句" 執(zhí)行, 分別耗時
    sqlite_exec 直接執(zhí)行:5.8080689907074
    未拆解"準(zhǔn)備語句" 執(zhí)行:5.93309998512268
    拆解后的"準(zhǔn)備語句" 執(zhí)行:4.91254101991653
  • 結(jié)果分析
    sqlite_exec 直接執(zhí)行 和 未拆解"準(zhǔn)備語句" 執(zhí)行 執(zhí)行時間平均差不多
    sqlite_exec 函數(shù)是對"準(zhǔn)備語句"的封裝 (預(yù)處理語句->綁定參數(shù)->執(zhí)行語句->重置語句->釋放語句)
    拆解后的"準(zhǔn)備語句" 執(zhí)行, 效率明顯高了一些
    主要原因是真正遵循了"準(zhǔn)備語句"的操作流程
    雖然按步驟使用"準(zhǔn)備語句", 但是執(zhí)行效率,依然非常低, 達(dá)到了5秒左右, 不可原諒
  • 原因分析
    每當(dāng)SQL調(diào)用執(zhí)行方法執(zhí)行一個語句時, 都會開啟一個叫做"事務(wù)"的東西, 執(zhí)行完畢之后再提交"事務(wù)";
    也就是說, 如果執(zhí)行了10000次SQL語句, 就打開和提交了10000次"事務(wù)", 所以造成耗時嚴(yán)重
  • 解決方案
    只要在執(zhí)行多個SQL語句之前, 手動開啟事務(wù), 在執(zhí)行完畢之后, 手動提交事務(wù), 這樣 再調(diào)用SQL方法執(zhí)行語句時, 就不會再自動開啟和提交事務(wù)
  • 優(yōu)化后結(jié)果
    插入10000條數(shù)據(jù), 大概耗時0.07秒
  • 得出結(jié)論
  1. 如果插入大量數(shù)據(jù), 請務(wù)必手動開啟/提交事務(wù)
  2. 根據(jù)不同情況, 選擇使用sqlite3_exec或者 "準(zhǔn)備語句"
    單條語句, 前者, 因?yàn)槭褂煤唵?br> 大批量插入, 選擇后者

16-(掌握)代碼實(shí)現(xiàn)-事務(wù)

  • 概念
    事務(wù)(Transaction)是并發(fā)控制的單位,是用戶定義的一個操作序列。這些操作要么都做采盒,要么都不做旧乞,是一個不可分割的工作單位。通過事務(wù)纽甘,可以將邏輯相關(guān)的一組操作綁定在一起良蛮,保持?jǐn)?shù)據(jù)的完整性。
    事務(wù)通常是以BEGIN TRANSACTION開始悍赢,以COMMIT TRANSACTIONROLLBACK TRANSACTION結(jié)束决瞳。
    COMMIT表示提交,即提交事務(wù)的所有操作左权。具體地說就是將事務(wù)中所有對數(shù)據(jù)庫的更新寫回到磁盤上的物理數(shù)據(jù)庫中去皮胡,事務(wù)正常結(jié)束。
    ROLLBACK表示回滾赏迟,即在事務(wù)運(yùn)行的過程中發(fā)生了某種故障屡贺,事務(wù)不能繼續(xù)進(jìn)行,系統(tǒng)將事務(wù)中對數(shù)據(jù)庫的所有以完成的操作全部撤消锌杀,滾回到事務(wù)開始的狀態(tài)甩栈。
  • 測試
    修改兩條記錄, 一個成功, 一個失敗測試
             XMGSQLTool.shareInstance.beginTransaction()
                   let result1 = Student.updateStudent("score = score - 10", condition: "name = 'zs'")
                   let result2 = Student.updateStudent("score1 = score + 10", condition: "name = 'wex'")
                    // 如果都執(zhí)行成功再提交, 如果都不成功, 那就回滾
                    if result1 && result2
                    {
            XMGSQLTool.shareInstance.commitTransaction()
                    }else
                    {
            XMGSQLTool.shareInstance.rollBackTransaction()
                    }
//tool
 func beginTransaction()
    {
        let sql = "begin transaction"
        if execute(sql: sql) {
            print("事務(wù)開起成功")
        }
    }
    func commitTransaction()
    {
      let sql = "commit transaction"
        if execute(sql: sql) {
            print("事務(wù)提交成功")
        }
    }
    func rollBackTransaction()
    {
        let sql = "rollback transaction"
        if execute(sql: sql) {
            print("事務(wù)回轉(zhuǎn)")
        }
    }
    

17-(掌握)代碼實(shí)現(xiàn)DQL語句

sql返回結(jié)果會產(chǎn)生一個集合,所有他會執(zhí)行返回代碼塊參數(shù)

  • 方式1: sqlite3_exec
    作用: 可以通過回調(diào)來獲取結(jié)果, 步驟相對來說簡單, 結(jié)果數(shù)據(jù)類型沒有特定類型(id)
    這里返回的數(shù)據(jù)沒有類型糕再,都是按照字符串來進(jìn)行輸出的
    參數(shù)說明
    // 參數(shù)1: 一個打開的數(shù)據(jù)庫
    // 參數(shù)2: 需要執(zhí)行的SQL語句
    // 參數(shù)3: 查詢結(jié)果回調(diào)(執(zhí)行0次或多次)
    參數(shù)1: 參數(shù)4的值
    參數(shù)2: 列的個數(shù)
    參數(shù)3: 結(jié)果值的數(shù)組
    參數(shù)4: 所有列的名稱數(shù)組
    返回值: 0代表繼續(xù)執(zhí)行一致到結(jié)束, 1代表執(zhí)行一次
    // 參數(shù)4: 回調(diào)函數(shù)的第一個值
    // 參數(shù)5: 錯誤信息
    demo
 class func queryAll()
    {
        let sql = "select * from t_stu"
        let db = SqliteTool.shareTool.db
        //參數(shù)1 要打開的數(shù)據(jù)庫
        //參數(shù)2 要執(zhí)行的語句
        //參數(shù)3量没,callback
              //參數(shù)1:傳遞過來的
             //參數(shù)2 :列的個數(shù)
             //參數(shù)3:值的數(shù)組
             //參數(shù)4:列名稱數(shù)組
       let result = sqlite3_exec(db, sql,{(firstValue, columnCount, values, columnNames)->Int32 in
            let count = Int(columnCount)
            for i in 0..<count {
                //列的名稱
                let columnName = columnNames![i]
                let columnNameStr = String(cString: columnName!)
                let columnStr = String(cString: columnName!, encoding: String.Encoding.utf8)
                let value = values![i]
                let valueStr = String(cString: value!)
                print(columnNameStr, valueStr)
            }
            
            return 0
        }, nil, nil)
        print(result)
        if result == SQLITE_OK {
            print("查詢學(xué)生信息成功")
        }
        else
        {
            print("查詢學(xué)生信息失敗")
        }
    }
  • 方式2: 通過"準(zhǔn)備語句"
    作用: 可以處理不同特定類型, 步驟相對來說復(fù)雜
  • 步驟:
    2.1. 預(yù)處理函數(shù) 獲取"準(zhǔn)備語句"
    sqlite3_prepare
    2.2. 不斷執(zhí)行"準(zhǔn)備語句", 直到無結(jié)果集
    while sqlite3_step(stmt) == SQLITE_ROW
    2.3. 獲取列的類型
    sqlite3_column_type
    2.4. 根據(jù)每列的類型取出不同的值
sqlite3_column_int64
SQLITE_INTEGER
sqlite3_column_double
SQLITE_FLOAT
sqlite3_column_text
SQLITE3_TEXT
需要轉(zhuǎn)換下字符串
let cText =  UnsafePointer<Int8>(sqlite3_column_text(stmt, col))
let text = String(CString: cText, encoding: NSUTF8StringEncoding)
NSNull()
SQLITE_NULL

2.5. 釋放資源
sqlite3_finalize`
demo

class func queryAllStmt(){
        //1.創(chuàng)建stmt語句
        let sql = "select * from t_stu"
        //參數(shù)1:查詢的數(shù)據(jù)哭
        //參數(shù)2:執(zhí)行的sql語句
        //參數(shù)3:對參數(shù)的處理-1默認(rèn)自定哦
        //參數(shù)4:生成stmt語句地址
        //參數(shù)5:參數(shù)3 設(shè)置完參數(shù)的剩余參數(shù)
        var stmt : OpaquePointer? = nil
        if sqlite3_prepare_v2(SqliteTool.shareTool.db, sql, -1, &stmt, nil) != SQLITE_OK
        {
            print("準(zhǔn)備語句失敗")
        }
        //2.綁定類型(如果用不到,可以不寫)
        //3. 執(zhí)行step
        while sqlite3_step(stmt) == SQLITE_ROW // 表示還有其他的行
        {
            //1.計(jì)算預(yù)處理語句里面獲取的結(jié)果一共列的數(shù)量
            let columnCount = sqlite3_column_count(stmt)
            for i in 0..<columnCount {
                // 2.取出列的名稱
                let columnName = sqlite3_column_name(stmt, i)
                let columnNameStr = String(cString: columnName!, encoding: .utf8)
                print(columnNameStr!)
                //3.取出列的值
                //不同的數(shù)據(jù)類型突想,需要執(zhí)行不同函數(shù)來獲取
                //3.1獲取每列的數(shù)據(jù)類型
                let columnType = sqlite3_column_type(stmt, i)
                //3.2 根據(jù)不同的數(shù)據(jù)類型殴蹄,使用不同的函數(shù),獲取結(jié)果
                if columnType == SQLITE_INTEGER
                {
                    let value = sqlite3_column_int(stmt, i)
                    print(value)
                }
                if columnType == SQLITE_FLOAT {
                    let value = sqlite3_column_double(stmt, i)
                    print(value)
                }
                if columnType == SQLITE_TEXT
                {
                    let value = sqlite3_column_text(stmt, i)
                    //let valueInt8 = UnsafePointer<CChar>(value)
                    let valueStr = String(cString: value!)
                    print(valueStr)
                }
                
            }
        }
        //4.重置語句
        sqlite3_reset(stmt)
        //5.釋放資源
        sqlite3_finalize(stmt)        
    }

使用預(yù)處理語句來操作可以方便拿到對應(yīng)列的類型猾担,比如插入的時候袭灯,我們可以綁定二進(jìn)制的數(shù)據(jù),但是如果是sql語句直接執(zhí)行绑嘹,無法綁定二進(jìn)制數(shù)據(jù)稽荧,因?yàn)樗J(rèn)會當(dāng)成字符串來處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末工腋,一起剝皮案震驚了整個濱河市姨丈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夷蚊,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件髓介,死亡現(xiàn)場離奇詭異惕鼓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)唐础,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門箱歧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矾飞,“玉大人,你說我怎么就攤上這事呀邢∪髀伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵价淌,是天一觀的道長申眼。 經(jīng)常有香客問我,道長蝉衣,這世上最難降的妖魔是什么括尸? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮病毡,結(jié)果婚禮上濒翻,老公的妹妹穿的比我還像新娘。我一直安慰自己啦膜,他們只是感情好有送,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僧家,像睡著了一般雀摘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上啸臀,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天届宠,我揣著相機(jī)與錄音,去河邊找鬼乘粒。 笑死豌注,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灯萍。 我是一名探鬼主播轧铁,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼旦棉!你這毒婦竟也來了齿风?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绑洛,失蹤者是張志新(化名)和其女友劉穎救斑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體真屯,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脸候,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运沦。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡泵额,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出携添,到底是詐尸還是另有隱情嫁盲,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布烈掠,位于F島的核電站羞秤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏向叉。R本人自食惡果不足惜锥腻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望母谎。 院中可真熱鬧瘦黑,春花似錦、人聲如沸奇唤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咬扇。三九已至甲葬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懈贺,已是汗流浹背经窖。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梭灿,地道東北人画侣。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像堡妒,于是被迫代替她去往敵國和親配乱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容