ddu-dao

GreenDao 介紹:
  greenDAO是一個(gè)對象關(guān)系映射(ORM)的框架,能夠提供一個(gè)接口通過操作對象的方式去操作關(guān)系型數(shù)據(jù)庫,它能夠讓你操作數(shù)據(jù)庫時(shí)更簡單、更方便。如下圖所示:


  官網(wǎng)地址:http://greenrobot.org/greendao/
  github:https://github.com/greenrobot/greenDAO
  GreenDao 優(yōu)點(diǎn):
  性能高,號(hào)稱Android最快的關(guān)系型數(shù)據(jù)庫
  內(nèi)存占用小
  庫文件比較小,小于100K,編譯時(shí)間低,而且可以避免65K方法限制
  支持?jǐn)?shù)據(jù)庫加密 greendao支持SQLCipher進(jìn)行數(shù)據(jù)庫加密 有關(guān)SQLCipher可以參考這篇博客 Android數(shù)據(jù)存儲(chǔ)之Sqlite采用SQLCipher數(shù)據(jù)庫加密實(shí)戰(zhàn)
  簡潔易用的API
  GreenDao 3.0改動(dòng):
  使用過GreenDao的同學(xué)都知道,3.0之前需要通過新建GreenDaoGenerator工程生成Java數(shù)據(jù)對象(實(shí)體)和DAO對象,非常的繁瑣而且也加大了使用成本。
  GreenDao 3.0最大的變化就是采用注解的方式通過編譯方式生成Java數(shù)據(jù)對象和DAO對象。
  GreenDao 3.0使用方式:
  1.)在build.gradle添加如下配置
  buildscript {
  repositories {
  mavenCentral()
  }
  dependencies {
  classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
  }
  }
  apply plugin: 'org.greenrobot.greendao'
  dependencies {
  compile 'org.greenrobot:greendao:3.0.1'
  }
  2.)新建實(shí)體
  @Entity
  public class User {
  @Id
  private long id;
  private String name;
  private int age;
  //下面省去了 setter/getter
  }
  此時(shí)編譯一下自動(dòng)生成DaoMaster 、DaoSession、Dao,如圖所示 默認(rèn)位置:

  3.) Gradle 插件配置
  比如上面想指定生成DaoMaster 、DaoSession、Dao位置
  greendao {
  targetGenDir 'src/main/java'
  }
  schemaVersion : 數(shù)據(jù)庫schema版本,也可以理解為數(shù)據(jù)庫版本號(hào)
  daoPackage :設(shè)置DaoMaster 、DaoSession、Dao包名
  targetGenDir :設(shè)置DaoMaster 、DaoSession、Dao目錄
  targetGenDirTest :設(shè)置生成單元測試目錄
  generateTests :設(shè)置自動(dòng)生成單元測試用例
  4.)實(shí)體 @Entity注解
  schema :告知GreenDao當(dāng)前實(shí)體屬于哪個(gè)schema
  active: 標(biāo)記一個(gè)實(shí)體處于活動(dòng)狀態(tài),活動(dòng)實(shí)體有更新、刪除和刷新方法
  nameInDb: 在數(shù)據(jù)中使用的別名,默認(rèn)使用的是實(shí)體的類名
  indexes: 定義索引,可以跨越多個(gè)列
  createInDb: 標(biāo)記創(chuàng)建數(shù)據(jù)庫表
  5.)基礎(chǔ)屬性注解
  @Id : 主鍵 long/Long型,可以通過@Id(autoincrement = true)設(shè)置自增長
  @Property: 設(shè)置一個(gè)非默認(rèn)關(guān)系映射所對應(yīng)的列名,默認(rèn)是的使用字段名 舉例:@Property (nameInDb="name")
  @NotNul: 設(shè)置數(shù)據(jù)庫表當(dāng)前列不能為空
  @Transient :添加次標(biāo)記之后不會(huì)生成數(shù)據(jù)庫表的列
  6.)索引注解
  @Index: 使用@Index作為一個(gè)屬性來創(chuàng)建一個(gè)索引,通過name設(shè)置索引別名,也可以通過unique給索引添加約束
  @Unique: 向數(shù)據(jù)庫列添加了一個(gè)唯一的約束
  7.)關(guān)系注解
  @ToOne: 定義與另一個(gè)實(shí)體(一個(gè)實(shí)體對象)的關(guān)系
  @ToMany: 定義與多個(gè)實(shí)體對象的關(guān)系
  GreenDao 3.0簡單實(shí)戰(zhàn):
  1.)通過上面使用方式我們可以獲取DaoMaster 、DaoSession、Dao類
  這里聲明一個(gè)數(shù)據(jù)庫管理者單例
  public class DBManager {
  private final static String dbName = "test_db";
  private static DBManager mInstance;
  private DaoMaster.DevOpenHelper openHelper;
  private Context context;
  public DBManager(Context context) {
  this.context = context;
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  /**
  * 獲取單例引用
  *
  * @param context
  * @return
  /
  public static DBManager getInstance(Context context) {
  if (mInstance == null) {
  synchronized (DBManager.class) {
  if (mInstance == null) {
  mInstance = new DBManager(context);
  }
  }
  }
  return mInstance;
  }
  }
  2.)獲取可讀可寫數(shù)據(jù)庫
  可讀數(shù)據(jù)庫
  /
*
  * 獲取可讀數(shù)據(jù)庫
  /
  private SQLiteDatabase getReadableDatabase() {
  if (openHelper == null) {
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  SQLiteDatabase db = openHelper.getReadableDatabase();
  return db;
  }
  可寫數(shù)據(jù)庫
  /
*
  * 獲取可寫數(shù)據(jù)庫
  /
  private SQLiteDatabase getWritableDatabase() {
  if (openHelper == null) {
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  SQLiteDatabase db = openHelper.getWritableDatabase();
  return db;
  }
  3.)插入數(shù)據(jù)
  /
*
  * 插入一條記錄
  *
  * @param user
  /
  public void insertUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.insert(user);
  }
  /
*
  * 插入用戶集合
  *
  * @param users
  /
  public void insertUserList(List users) {
  if (users == null || users.isEmpty()) {
  return;
  }
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.insertInTx(users);
  }
  4.)刪除數(shù)據(jù)
  /
*
  * 刪除一條記錄
  *
  * @param user
  /
  public void deleteUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.delete(user);
  }
  5.)更新數(shù)據(jù)
  /
*
  * 更新一條記錄
  *
  * @param user
  /
  public void updateUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.update(user);
  }
  6.)查詢數(shù)據(jù)
  /
*
  * 查詢用戶列表
  /
  public List queryUserList() {
  DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  QueryBuilder qb = userDao.queryBuilder();
  List list = qb.list();
  return list;
  }
  /
*
  * 查詢用戶列表
  */
  public List queryUserList(int age) {
  DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  QueryBuilder qb = userDao.queryBuilder();
  qb.where(UserDao.Properties.Age.gt(age)).orderAsc(UserDao.Properties.Age);
  List list = qb.list();
  return list;
  }
  7.)測試程序
  DBManager dbManager = DBManager.getInstance(this);
  for (int i = 0; i < 5; i++) {
  User user = new User();
  user.setId(i);
  user.setAge(i * 3);
  user.setName("第" + i + "人");
  dbManager.insertUser(user);
  }
  List userList = dbManager.queryUserList();
  for (User user : userList) {
  Log.e("TAG", "queryUserList--before-->" + user.getId() + "--" + user.getName() +"--"+user.getAge());
  if (user.getId() == 0) {
  dbManager.deleteUser(user);
  }
  if (user.getId() == 3) {
  user.setAge(10);
  dbManager.updateUser(user);
  }
  }
  userList = dbManager.queryUserList();
  for (User user : userList) {
  Log.e("TAG", "queryUserList--after--->" + user.getId() + "---" + user.getName()+"--"+user.getAge());
  }

-----------------------------------3.0-----------------
GreenDao 3.X之注解已經(jīng)了解到GreenDao 3.0的改動(dòng)及注解。對于數(shù)據(jù)庫的操作,無異于增刪改查等四個(gè)操作。下面我們將了解GreenDao 3.X如何使用?
AbstractDao
所有的自動(dòng)生成的XXDao都是繼承于AbstractDao,此類中基本上封裝了所有的增刪改操作,包括數(shù)據(jù)庫的事務(wù)操作。常用的API如下:

void attachEntity(T entity):

long count():獲取數(shù)據(jù)庫中數(shù)據(jù)的數(shù)量

// 數(shù)據(jù)刪除相關(guān)
void delete(T entity):從數(shù)據(jù)庫中刪除給定的實(shí)體
void deleteAll() :刪除數(shù)據(jù)庫中全部數(shù)據(jù)
void deleteByKey(K key):從數(shù)據(jù)庫中刪除給定Key所對應(yīng)的實(shí)體
void deleteByKeyInTx(java.lang.Iterable<K> keys):使用事務(wù)操作刪除數(shù)據(jù)庫中給定的所有key所對應(yīng)的實(shí)體
void deleteByKeyInTx(K... keys):使用事務(wù)操作刪除數(shù)據(jù)庫中給定的所有key所對應(yīng)的實(shí)體
void deleteInTx(java.lang.Iterable<T> entities):使用事務(wù)操作刪除數(shù)據(jù)庫中給定實(shí)體集合中的實(shí)體
void deleteInTx(T... entities):使用事務(wù)操作刪除數(shù)據(jù)庫中給定的實(shí)體

// 數(shù)據(jù)插入相關(guān)
long insert(T entity):將給定的實(shí)體插入數(shù)據(jù)庫
void insertInTx(java.lang.Iterable<T> entities):使用事務(wù)操作,將給定的實(shí)體集合插入數(shù)據(jù)庫
void insertInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事務(wù)操作,將給定的實(shí)體集合插入數(shù)據(jù)庫,
并設(shè)置是否設(shè)定主鍵
void insertInTx(T... entities):將給定的實(shí)體插入數(shù)據(jù)庫
long insertOrReplace(T entity):將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則覆蓋
void insertOrReplaceInTx(java.lang.Iterable<T> entities):使用事務(wù)操作,將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則覆蓋
void insertOrReplaceInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事務(wù)操作,將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則覆蓋
并設(shè)置是否設(shè)定主鍵
void insertOrReplaceInTx(T... entities):使用事務(wù)操作,將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則覆蓋
long insertWithoutSettingPk(T entity):將給定的實(shí)體插入數(shù)據(jù)庫,但不設(shè)定主鍵

// 新增數(shù)據(jù)插入相關(guān)API
void save(T entity):將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則更新
void saveInTx(java.lang.Iterable<T> entities):將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則更新
void saveInTx(T... entities):使用事務(wù)操作,將給定的實(shí)體插入數(shù)據(jù)庫,若此實(shí)體類存在,則更新

// 加載相關(guān)
T load(K key):加載給定主鍵的實(shí)體
java.util.List<T> loadAll():加載數(shù)據(jù)庫中所有的實(shí)體
protected java.util.List<T> loadAllAndCloseCursor(android.database.Cursor cursor) :從cursor中讀取、返回實(shí)體的列表,并關(guān)閉該cursor
protected java.util.List<T> loadAllFromCursor(android.database.Cursor cursor):從cursor中讀取、返回實(shí)體的列表
T loadByRowId(long rowId) :加載某一行并返回該行的實(shí)體
protected T loadUnique(android.database.Cursor cursor) :從cursor中讀取、返回唯一實(shí)體
protected T loadUniqueAndCloseCursor(android.database.Cursor cursor) :從cursor中讀取、返回唯一實(shí)體,并關(guān)閉該cursor

//更新數(shù)據(jù)
void update(T entity) :更新給定的實(shí)體
protected void updateInsideSynchronized(T entity, DatabaseStatement stmt, boolean lock)
protected void updateInsideSynchronized(T entity, android.database.sqlite.SQLiteStatement stmt, boolean lock)
void updateInTx(java.lang.Iterable<T> entities) :使用事務(wù)操作,更新給定的實(shí)體
void updateInTx(T... entities):使用事務(wù)操作,更新給定的實(shí)體

QueryBuilder、Query
基本查詢
GreenDao中,使用QueryBuilder自定義查詢實(shí)體,而不是再寫繁瑣的SQL語句,避免了SQL語句的出錯(cuò)率。大家都知道寫SQL語句時(shí),非常容易出錯(cuò),出錯(cuò)后又十分的難查。QueryBuilder真是幫忙解決了一個(gè)大麻煩。具體該如何使用呢?

List joes = userDao.queryBuilder()
// 查詢的條件
.where(Properties.FirstName.eq("Joe"))
// 返回實(shí)體集合升序排列
.orderAsc(Properties.LastName)
.list();
QueryBuilder qb = userDao.queryBuilder();
// 查詢的條件
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list(); </span>

    上面是官方給出的兩個(gè)列子,不僅滿足了查詢語句的易寫,同時(shí)使用了流式寫法,提高了代碼的可閱讀性。

Limit、Offset、Pagination
在實(shí)際開發(fā)過程中,大家肯定碰到這樣的問題,當(dāng)數(shù)據(jù)過多在一頁顯示不出來的時(shí)候,要么選擇前面十條顯示,要么分頁顯示,但是數(shù)據(jù)總是獲取全部的。其實(shí),剛接觸GreenDao的時(shí)候,也是這么干,獲取全部的實(shí)體集合,然后再根據(jù)實(shí)際情況截取。看了API以后,豁然開朗,大神們已經(jīng)幫我們解決了這件事。此時(shí)不得不說,QueryBuilder中的Limit(限制)、Offset(偏移),limit(int)和offset(int)協(xié)同設(shè)置,可以完美解決分頁顯示。

limit(int):限制查詢返回結(jié)果的數(shù)目
offset(int):設(shè)置查詢結(jié)果的偏移量,此查詢需與limit(int)結(jié)合使用,而不能夠脫離limit(int)單獨(dú)使用

Query
當(dāng)執(zhí)行多次查詢時(shí),實(shí)際是QueryBuilder多次調(diào)用Query類。如果執(zhí)行多次相同的查詢,應(yīng)使用QueryBuilder的build()方法來創(chuàng)建Query,而不是直接使用Query類。如果查詢返回的結(jié)果是唯一性的,可以使用操作符方法,如果不希望此唯一性不返回 null,此時(shí)可調(diào)用uniqOrThrow()方法。如果查詢返回的結(jié)果是多個(gè),可以使返回的結(jié)果是一個(gè)集合,有如下方法:

list():所有實(shí)體加載至內(nèi)存,結(jié)果通常是一個(gè)ArrayList
listLazy():實(shí)體在需要時(shí),加載至內(nèi)存,表中的第一個(gè)元素被第一次訪問時(shí)會(huì)被緩存,下次訪問時(shí),使用緩存
listLazyUncached():任何對列表實(shí)體的訪問懂事從數(shù)據(jù)庫中加載
listIterator():以按需加載的方式來遍歷結(jié)果,數(shù)據(jù)沒有被緩存

     一旦使用QueryBuilder創(chuàng)建了一個(gè)query,那么這個(gè)Query對象就可以就可以被復(fù)用來執(zhí)行查詢顯然這種方式逼重新創(chuàng)建一次Query效率要高。        

如果Query的參數(shù)沒有變更,你只需要再次調(diào)用List/unuque方法即可
如果參數(shù)發(fā)生了變化,那么就需要通過setParameter方法來處理每一個(gè)發(fā)生改變的參數(shù)

Query query = userDao.queryBuilder().where(Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)).build();
List joesOf1970 = query.list();

query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();

    由此可見,Query在執(zhí)行一次build之后會(huì)將查詢結(jié)果進(jìn)行緩存,方便下次繼續(xù)使用。

執(zhí)行原生SQL語句
兩種方法:

Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();

如果這里的QueryBuilder沒有提供你想要的特性,可以使用原始的queryRaw或queryRawCreate方法。
Query query = userDao.queryRawCreate( ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");

    注:寫SQL語句時(shí)推薦定義常量來表示表名或者表項(xiàng),這樣可以防止出錯(cuò),因?yàn)榫幾g器會(huì)檢查

基本使用
創(chuàng)建實(shí)體類

@Entity(generateConstructors = false)
public class Student {
@Id
private Long id;
private String name;
private int age;

public Student() {  
}  

@Keep  
public Student(String name, int age) {  
    this.name = name;  
    this.age = age;  
}  


public Student(Long id, String name, int age) {  
    this.id = id;  
    this.name = name;  
    this.age = age;  
}  

@Keep  
public Long getId() {  
    return id;  
}  

@Keep  
public void setId(Long id) {  
    this.id = id;  
}  

@Keep  
public String getName() {  
    return name;  
}  

@Keep  
public void setName(String name) {  
    this.name = name;  
}  

@Keep  
public int getAge() {  
    return age;  
}  

@Keep  
public void setAge(int age) {  
    this.age = age;  
}  

@Keep  
@Override  
public boolean equals(Object o) {  
    if (this == o) return true;  
    if (!(o instanceof Student)) return false;  

    Student student = (Student) o;  

    return name.equals(student.name);  

}  

@Keep  
@Override  
public int hashCode() {  
    return (int) (id ^ (id >>> 32));  
}  

@Keep  
@Override  
public String toString() {  
    return "Student{" +  
            "id=" + id +  
            ", name='" + name + '\'' +  
            ", age=" + age +  
            '}';  
}  

}

創(chuàng)建完實(shí)體類后,Rebuild Project生成DaoMaster、DaoSession。DaoMaster、DaoSession位于在Gradle設(shè)置的目錄及文件夾里。
[圖片上傳中。。。(21)]

[圖片上傳中。。。(22)]
創(chuàng)建Database管理類

public class DbManager {

// 是否加密  
public static final boolean ENCRYPTED = true;  

private static final String DB_NAME = "tea.db";  
private static DbManager mDbManager;  
private static DaoMaster.DevOpenHelper mDevOpenHelper;  
private static DaoMaster mDaoMaster;  
private static DaoSession mDaoSession;  

private Context mContext;  

private DbManager(Context context) {  
    this.mContext = context;  
    // 初始化數(shù)據(jù)庫信息  
    mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);  
    getDaoMaster(context);  
    getDaoSession(context);  
}  

public static DbManager getInstance(Context context) {  
    if (null == mDbManager) {  
        synchronized (DbManager.class) {  
            if (null == mDbManager) {  
                mDbManager = new DbManager(context);  
            }  
        }  
    }  
    return mDbManager;  
}  

/** 
 * @desc 獲取可讀數(shù)據(jù)庫 
 **/  
public static SQLiteDatabase getReadableDatabase(Context context) {  
    if (null == mDevOpenHelper) {  
        getInstance(context);  
    }  
    return mDevOpenHelper.getReadableDatabase();  
}  

/** 
 * @desc 獲取可寫數(shù)據(jù)庫 
 **/  
public static SQLiteDatabase getWritableDatabase(Context context) {  
    if (null == mDevOpenHelper) {  
        getInstance(context);  
    }  
    return mDevOpenHelper.getWritableDatabase();  
}  

/** 
 * @desc 獲取DaoMaster 
 **/  
public static DaoMaster getDaoMaster(Context context) {  
    if (null == mDaoMaster) {  
        synchronized (DbManager.class) {  
            if (null == mDaoMaster) {  
                mDaoMaster = new DaoMaster(getWritableDatabase(context));  
            }  
        }  
    }  
    return mDaoMaster;  
}  

/** 
 * @desc 獲取DaoSession 
 **/  
public static DaoSession getDaoSession(Context context) {  
    if (null == mDaoSession) {  
        synchronized (DbManager.class) {  
            mDaoSession = getDaoMaster(context).newSession();  
        }  
    }  

    return mDaoSession;  
}  

}

數(shù)據(jù)庫操作類

public class StudentDaoOpe {

/** 
 * @desc 添加數(shù)據(jù)至數(shù)據(jù)庫 
 **/  
public static void insertData(Context context, Student stu) {  

    DbManager.getDaoSession(context).getStudentDao().insert(stu);  
}  

/** 
 * @desc 將數(shù)據(jù)實(shí)體通過事務(wù)添加至數(shù)據(jù)庫 
 **/  
public static void insertData(Context context, List<Student> list) {  
    if (null == list || list.size() <= 0) {  
        return;  
    }  
    DbManager.getDaoSession(context).getStudentDao().insertInTx(list);  
}  


  @desc 添加數(shù)據(jù)至數(shù)據(jù)庫,如果存在,將原來的數(shù)據(jù)覆蓋 

public static void saveData(Context context, Student student) {  
    DbManager.getDaoSession(context).getStudentDao().save(student);  
}  

/** 
 * @desc 查詢所有數(shù)據(jù) 
 **/  
public static List<Student> queryAll(Context context) {  
    QueryBuilder<Student> builder = DbManager.getDaoSession(context).getStudentDao().queryBuilder();  

    return builder.build().list();  
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評論 2 380

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