hiberante3-day3

一、Hibernate 檢索

  1. hibernate 提供5種檢索數據的方式
    導航對象圖檢索方式: 根據已經加載的對象導航到其他對象
    Customer c = (Customer)session.get(Customer.class, 1); // 持久態對象
    c.getOrders().size(); // c 對象關聯 order 集合 ,hibernate 會自動檢索 order數據

OID 檢索方式: 按照對象的 OID 來檢索對象
session.get / session.load

HQL 檢索方式: 使用面向對象的 HQL 查詢語言
session.createQuery(hql)

QBC 檢索方式: 使用 QBC(Query By Criteria) API 來檢索對象. 這種 API 封裝了基于字符串形式的查詢語句, 提供了更加面向對象的查詢接口.
session.createCriteria(Xxx.class);

本地 SQL 檢索方式: 使用本地數據庫的 SQL 查詢語句
session.createSQLQuery(sql)

2、 HQL 是 Hibernate 最常用檢索方式
支持 所有 SQL支持檢索方式

步驟 :
1) 獲得Session
2) 編寫HQL
3) 通過 session.createQuery(hql) 創建Query對象
4) 為Query對象 設置條件參數
5) 執行查詢 list() ---- 返回一個集合列表 、 uniqueResult();--- 返回一個查詢結果

  • Qurey 接口支持方法鏈編程風格 , 將上面所有步驟寫入一句程序代碼中

3、 編寫測試用例,創建初始數據
創建4個Customer , 每個Customer 創建 10個 Order

4、 簡單查詢, hibernate 企業開發主流查詢 HQL 和 QBC

  • 查詢所有數據
    // HQL
    String hql = "from Customer";
    Query query = session.createQuery(hql);
    List<Customer> list = query.list();
    System.out.println(list);

     // QBC
     Criteria criteria = session.createCriteria(Customer.class);
     List<Customer> list2 = criteria.list();
     System.out.println(list2);
    
  • HQL 和 QBC 都支持鏈式編程寫法
    List<Customer> list3 = session.createQuery("from Customer").list();

5、 本地SQL 檢索
* 編寫及其復雜的查詢,企業內部大多使用 SQL 語句
// 內連接 寫法一 : select * from A inner join B on A.id = B.A_id;
// 內連接 寫法二 (隱式): select * from A,B where A.id = B.A_id ;
String sql = "select * from customers , orders where customers.id = orders.customer_id and customers.name = ?";
SQLQuery sqlQuery = session.createSQLQuery(sql);
// 設置參數
sqlQuery.setParameter(0, "mary");
List list = sqlQuery.list();
System.out.println(list);
* 當返回很多列時,默認將每條記錄保存在 Object[]中, 返回 List<Object[]>
* 將返回結果 與實體類 綁定,將每條數據 轉換實體類對象
String sql = "select orders.* from customers , orders where customers.id = orders.customer_id and customers.name = ?";
sqlQuery.addEntity(Order.class);

6、 編寫HQL時,通過as關鍵字 為類 起別名
from Customer as c where c.name=:custname
原來寫法: from Customer where name=:custname
使用別名時 ,as可以省略 from Customer c where c.name=:custname

  • 別名主要使用 關聯復雜查詢時

7、 多態查詢
hibernate 檢索一個類 對應數據時, 將類所有子類(PO類) 對應數據表記錄返回
session.createQuery("from java.lang.Object").list();

  • 將Object 所有子類 對應數據表的 數據查詢返回

from 關鍵字后面,如果PO類,省略包名, 如果不是PO類,必須寫完整包名類名

8、 查詢結果排序
// HQL
String hql = "from Customer order by name asc";
List list = session.createQuery(hql).list();
System.out.println(list);
// QBC
List list2 = session.createCriteria(Customer.class).addOrder(org.hibernate.criterion.Order.asc("name")).list();
System.out.println(list2);

9、 分頁查詢
Query 接口 和 Criteria 接口 都提供 setFirstResult 、setMaxResults 兩個方法,用于分頁查詢
* setFirstResult 起始記錄索引,第一條數據 索引 0
* setMaxResults 查詢返回記錄條數
案例:
// 分頁查詢,返回 25-34條訂單
// HQL
String hql = "from Order";
Query query = session.createQuery(hql);
// 設置分頁參數
query.setFirstResult(24); // 索引 是 起始記錄 -1
query.setMaxResults(10);

10、 檢索單一對象 query.uniqueResult() 、 criteria.uniqueResult()

  • 該方法主要用于,只有1條數據結果

  • 什么情況只有一條結果 : 用戶登錄、使用聚集函數 sum、count、avg、max、min
    // 查詢mary的信息
    Customer customer = (Customer) session.createQuery("from Customer where name = 'mary'").uniqueResult();
    System.out.println(customer);

    // 使用聚集函數 -- 查詢客戶最大年齡
    Integer age = (Integer) session.createQuery("select max(age) from Customer").uniqueResult();
    System.out.println(age);

如果查詢結果 只有一條記錄 或者 無記錄,使用uniqueResult 是沒問題的, 但是如果查詢結果大于 一條記錄,報錯
org.hibernate.NonUniqueResultException: query did not return a unique result: 4

===============================================================================================================================
11、 帶有參數條件的查詢
1) 單表條件查詢
HQL寫法:
Customer customer1 = (Customer) session.createQuery("from Customer where name = ?").setParameter(0, "tom").uniqueResult();
Customer customer2 = (Customer) session.createQuery("from Customer where name = :cname").setParameter("cname", "tom").uniqueResult();

QBC寫法:
Customer customer3 = (Customer) session.createCriteria(Customer.class).add(Restrictions.eq("name", "tom")).uniqueResult();
* Restrictions 用來添加查詢條件 ,面向對象條件查詢

將參數綁定到一個持久化對象
Customer customer = new Customer();
customer.setId(1);
List list2 = session.createQuery("from Order where customer = ?").setEntity(0, customer).list(); // 通過customer_id 查詢

  • 簡化為 List list = session.createQuery("from Order where customer.id = ?").setParameter(0, 1).list();
  • setEntity 關聯對象 ,必須要有OID ,否則會報錯

使用QBC 為參數綁定 持久化對象
List list3 = session.createCriteria(Order.class).add(Restrictions.eq("customer", customer)).list(); // 通過customer_id 查詢

2) 多表條件查詢
hibernate HQL 支持7種 連接寫法
* (SQL標準)內連接 inner join 可以省略 inner,直接 join
* 迫切內連接 inner join fetch ------ 不是SQL寫法,是hibernate 提供
* 隱式內連接 不寫任何關鍵字,完成表關聯

* (SQL標準)左外連接 left outer join ,可以省略 outer ,直接 left join
* 迫切左外連接 left outer join fetch ----- 不是SQL語法
* (SQL標準)右外連接 right outer join

* (SQL標準)交叉連接 (笛卡爾積 ) ---------- 不講

問題: 區分內連接和迫切內連接, 左外連接和迫切左外連接
* 左外連接 List list = session.createQuery( "from Customer c left outer join c.orders").list(); 返回 List<Object[]>
每個數組兩個元素 ,一個Customer 一個Order
* 迫切左外連接 List list = session.createQuery("select distinct c from Customer c left outer join fetch c.orders").list();
返回 List<Customer> 保存所有Customer對象,需要distinct 排重重復

問題:多表關聯條件查詢,隱式內連接 和 QBC方式
// 隱式內連接 o.customer 當做Customer類數據表
List<Order> list = session.createQuery("from Order o where o.customer.name = ?").setParameter(0, "mary").list();

// QBC 連接查詢,必須使用 criteria.createAlias()
Criteria criteria = session.createCriteria(Order.class);
criteria.createAlias("customer", "c"); // 為訂單關聯Customer屬性起了別名
criteria.add(Restrictions.eq("c.name", "mary"));
List list2 = criteria.list();
*  在 createAlias 默認使用 inner join 內連接
    criteria.createAlias("customer", "c", Criteria.LEFT_JOIN); 在關聯時使用左外連接

12 、投影查詢
查詢結果僅包含實體的部分屬性
* 查詢Customer的所有 name,age 屬性
HQL方式
session.createQuery("select name,age from Customer"); 返回 List<Object[]>
* 將結果保存Customer對象中,提供name和age 構造方法
session.createQuery("select new Customer(name,age) from Customer"); 返回 List<Customer>
可以將查詢結果 保存List 或者 Map集合
* select new list(name,age) from Customer
* select new map(name,age) from Customer

QBC方式 (開發中不用,非常麻煩)
List list3 = session
.createCriteria(Customer.class)
.setProjection(
Projections.projectionList()
.add(Property.forName("name"))
.add(Property.forName("age"))).list();

13、 分組統計查詢
count sum avg max min
* Long count = (Long) session.createQuery("select count() from Order").uniqueResult();
* List list2 = session.createQuery("select count(
) from Order group by customer").list();

14、 命名查詢語句
在開發中 hql語句 寫到代碼中,不方便維護, 將HQL定義到配置文件中 ------------ 命名查詢語句

在hbm映射文件 (也可以用注解配置)



<query name="findCustomerByName">
<![CDATA[from Customer where name = ?]]>
</query>

  • 為hql語句 起了一個名字

程序代碼
Query query = session.getNamedQuery("findCustomerByName");
query.setParameter(0, "tom");
Customer customer = (Customer) query.uniqueResult();

15、 離線Criteria對象 --- DetachedCriteria
* 主要用于javaee分層開發,可以在web層封裝查詢條件,傳遞數據層 關聯Session進行查詢
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.eq("name", "kitty"));

// 傳遞數據層
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();

// 將離線查詢對象 關聯到Session
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
Customer customer = (Customer) criteria.uniqueResult();

HQL和QBC比較: 兩種查詢功能類似, 簡單查詢建議編寫HQL,對于復雜查詢,多條件組合查詢 建議編寫 QBC方式

============================================================================================================================
二、 hibernate 在進行數據檢索時,抓取策略 (Hibernate 優化環節)
1、 準備初始數據
4條Customer數據, 39條Order 數據

2、 區分立即檢索和延遲檢索

  • 理解 為什么要使用 延遲檢索
    get方法,采用策略 立即檢索
    load方法,采用策略 延遲檢索

延遲加載在開發中,主要好處,延緩數據加載,在使用時才進行加載 (縮短數據在內存中時間)

3、 load方法 返回代理對象 (目標類 子類對象 )

  • hibernate 返回代理對象 由 javassist-3.12.0.GA.jar 提供工具類 負責創建
    Javassist是一個開源的分析、編輯和創建Java字節碼的類庫。

4、 延遲代理對象的數據初始化
方式一: 訪問代理對象 內部 除了 id屬性外 其它屬性 (導致延遲對象自動初始化 )
方式二: 調用 Hibernate.initialize(代理對象);

===========================================================
5、 區分類級別檢索和關聯級別的檢索
類級別檢索,通過session直接檢索 某一個類 對應數據表數據
session.load(Customer.class , 1) ; 類級別
session.createQuery("from Order"); 類級別
關聯級別檢索,程序內部已經獲得持久對象,通過對象引用關系,進行數據檢索
Customer c = session.load(Customer.class , 1) ; 類級別
c.getOrders().size() ; 關聯級別檢索
order.getCustomer().getName() ; 關聯級別檢索

6、 類級別檢索策略(抓取策略)
* 類級別可選的檢索策略包括立即檢索和延遲檢索, 默認為延遲檢索 (針對load方法 )
* 類級別的檢索策略可以通過 <class> 元素的 lazy 屬性進行設置

類級別檢索 get 、Query 默認使用立即檢索策略
load 默認使用延遲檢索, 在hbm文件 <class> 配置 lazy=false 使類級別檢索變為立即檢索

  • lazy=false 后 load方法效果 和 get方法相同,使用 立即檢索

7、 關聯級別的檢索策略
c.getOrders().size() ; order.getCustomer().getName(); 屬于關聯級別的檢索

1) 多對多 和 一對多 情況下 <set> 元素中配置 抓取策略  ---- 關聯集合
   <set> 元素提供 fetch 和 lazy 兩個屬性 決定檢索策略
   * fetch 屬性 (select、subselect、join) ,主要決定SQL語句生成格式
   * lazy 屬性 (false、true、extra)主要決定集合被初始化的時機
fetch 和 lazy 共有9種組合
    fetch 屬性為 join, lazy屬性會被忽略, 生成SQL將采用迫切左外連接查詢 (left outer join fetch )
        * SQL語句 左外連接,采用 立即檢索
    fetch 屬性為 select ,將生成多條簡單SQL查詢
        lazy = false 立即檢索
        lazy = true  延遲檢索
        lazy = extra 加強延遲檢索 (及其懶惰,比延遲更加延遲)
    fetch 屬性為 subselect ,將生成子查詢的SQL語句
        lazy = false 立即檢索
        lazy = true  延遲檢索
        lazy = extra 加強延遲檢索 (及其懶惰,比延遲更加延遲)

**** lazy=false 立即檢索,檢索類級別數據時,關聯級別數據也進行檢索
lazy=true 延遲檢索,檢索類級別數據時,不會檢索關聯級別的數據,用到了再進行檢索
lazy="extra" 及其懶惰,當程序第一次訪問 order 屬性的 size(), contains() 和 isEmpty() 方法時, Hibernate 不會初始化 orders 集合類的實例 ,例如 查詢size時,生成select count(*)

**** 因為fetch=join , session.get... 生成迫切左外連接查詢
使用Query對象查詢數據時,需要自己編寫hql語句, fetch=join 無效果,關聯集合將根據lazy 設置進行 加載

結論 : session.load/ session.get , fetch=join 生成迫切左外連接, lazy被忽略
session.createQuery(hql).list() 將忽略 fetch=join, lazy 將重新產生效果

2) 多對一 和 一對一 情況下 <many-to-one> 或者 <one-to-one> 配置抓取策略  ---- 關聯單一對象
<many-to-one> 元素也有一個 lazy 屬性和 fetch 屬性
    fetch 決定SQL語句格式, lazy決定數據加載時間
    fetch取值 join、 select
    lazy取值 false、 proxy、no-proxy(不講解)
fetch 和 lazy 共有4種組合
    fetch 屬性為 join, lazy屬性會被忽略, 生成SQL將采用迫切左外連接查詢 (left outer join fetch )
    fetch 屬性為 select, 產生多條SQL
        lazy=false  立即檢索
        lazy=proxy  有關聯對象類級別檢索策略決定立即檢索 或者 延遲檢索
        * 由Customer.hbm.xml  <class name="cn.itcast.domain.Customer" lazy="??"> lazy決定立即檢索 還是 延遲檢索

**** Query的list 會忽略 fetch="join", lazy重新起作用

結論: 開發中能延遲都延遲,必須立即的 才立即的

=======================================================================================================================
8、 批量檢索的使用
批量檢索 可以解決 N+1 查詢問題
1) Customer 一方設置批量檢索
<set> 元素有一個 batch-size 屬性 ,設置批量檢索數量
N+1問題:查詢每個客戶訂單數,一次查詢所有客戶, 每個客戶訂單數產生單獨SQL查詢,如果有n個客戶,產生n條SQL
解決: Customer.hbm.xml 設置<set>元素 batch-size 一次查詢多個用戶訂單數
* <set name="orders" batch-size="3">
2) Order多方 設置批量檢索
查詢訂單和客戶,產生多余SQL
配置批量檢索,一次多查詢幾個客戶數據
解決: Customer.hbm.xml 在 <class name="cn.itcast.domain.Customer" batch-size="3">

三、 Hibernate 注解應用 (常用注解)
* hibernate 注解 簡化hbm 文件的配置
* 單表注解配置、 一對多、多對多注解配置

hibernate3.6 注解開發和xml開發 導入jar包 和 配置文件 是一樣的

1、 使用注解配置 PO對象
@Entity 實體類
@Table 生成目標表
@Id 主鍵
@GeneratedValue 主鍵生成策略
@Column 定義生成列

注解開發優先使用 javax.persistence.*

// Book 是一個實體類
@Entity
// 配置@Table 注解 ,設置生成表名
@Table(name = "book")
public class Book {
// 主鍵 @Id
@Id
// 生成策略 @GeneratedValue
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

// 普通屬性@Column 注解修飾
// 如果不寫@Column 列名就是 屬性名
@Column(name = "bookname", length = 20, unique = true, nullable = false)
private String name;
private Double price;

}

  • @Id、@GeneratedValue(strategy = GenerationType.IDENTITY)、@Column(name = "bookname", length = 20, unique = true, nullable = false)
    可以修改屬性,也可以放到屬性get方法上

在hibernate.cfg.xml 配置注解類
<mapping class="cn.itcast.domain.Book"/>

2、 主鍵生成策略
@GeneratedValue(strategy = GenerationType.IDENTITY) --- 只支持四種策略
編寫UUID 主鍵生成策略 Person
@Entity
@Table(name = "person")
public class Person {
@Id
@GenericGenerator(name = "myuuidgenerator", strategy = "uuid")
@GeneratedValue(generator = "myuuidgenerator")
private String id; // UUID
private String name;
}

3、 其它屬性
@Temporal 生成日期類型
@Transient 控制不生成

日期類型java.util.Date 對于MySQL 生成 datetime類,日期和時間都包括
* @Temporal(TemporalType.DATE) 數據表只保存日期
* @Temporal(TemporalType.TIME) 數據表只保存時間
* @Temporal(TemporalType.TIMESTAMP) 日期時間都保存

Hibernate 實體類中,所有get方法 屬性, 都會在數據表 自動生成列
* 有時屬性不想 生成列 @Transient 注解

=====================================================================================
4、 一對多
@OneToMany @ManyToOne

@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;

// targetEntity 類似 <one-to-many class="">
// mappedBy 作用 inverse=true
@OneToMany(targetEntity = Order.class, mappedBy = "customer")
@Cascade(value = { CascadeType.SAVE_UPDATE })
private Set<Order> orders = new HashSet<Order>();

}

@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String address;

@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "customer_id")
// 添加外鍵列
private Customer customer;

}

jar沖突錯誤 java.lang.NoSuchMethodError: javax.persistence.OneToMany.orphanRemoval()Z
* javaee.jar(myeclipse提供) 和 jpa的jar 沖突
* 解決 : 刪除javaee.jar 中 javax.persistence 包

  • 級聯操作 @Cascade(value = { CascadeType.級別 })
    DELETE_ORPHAN 已經過時 ,推薦使用 @OneToMany(orphanRemoval=true)
    所有級聯級別
    @OneToMany(targetEntity = Order.class, mappedBy = "customer", orphanRemoval = true)
    @Cascade(value = { CascadeType.ALL })
    private Set<Order> orders = new HashSet<Order>();

5、 多對多
@ManyToMany

  • 注解配置多對多時,只需要一端配置中間表,另一端 mappedBy 放棄外鍵維護權

@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String sname;

@ManyToMany(targetEntity = Course.class)
// 配置中間表
// joinColumns 當前類在中間表 外鍵列名
// inverseJoinColumns 對方類 在中間表 外鍵列名
@JoinTable(name = "student_course", joinColumns = { @JoinColumn(name = "student_id") }, inverseJoinColumns = { @JoinColumn(name = "course_id") })
private Set<Course> courses = new HashSet<Course>();

}

@Entity
@Table(name = "courses")
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String cname;

@ManyToMany(targetEntity = Student.class, mappedBy = "courses")
// 放棄外鍵維護權
private Set<Student> students = new HashSet<Student>();

}

6、 抓取策略 (了解)
public class Customer {
// 抓取策略
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.TRUE)
private Set<Order> orders = new HashSet<Order>();
}

public class Order {
// 抓取策略
@Fetch(FetchMode.SELECT)
@LazyToOne(LazyToOneOption.FALSE)
private Customer customer;
}

關聯級別抓取,配置@Fetch等價fetch屬性, 關聯集合 @LazyCollection , 關聯單一對象 @LazyToOne

7、 NamedQuery 命名查詢
@NamedQueries(value = { @NamedQuery(name = "findCustomerByName", query = "from Customer where name= ?") })
public class Customer {
...
}

程序代碼:
Query query = session.getNamedQuery("findCustomerByName");
query.setParameter(0, "張三");
Customer customer = (Customer) query.uniqueResult();

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容