JDBC掰读、連接池和DBUtil

1.jdbc簡(jiǎn)介(本文使用的數(shù)據(jù)庫(kù)為MySQL)

? ? 1.1)JDBC(Java DataBase Connectivity,java數(shù)據(jù)庫(kù)連接)是一種用于執(zhí)行SQL語(yǔ)句的Java API磷支,可以為多種數(shù)據(jù)庫(kù)提供統(tǒng)一的訪問(wèn)(支持多種數(shù)據(jù)庫(kù))。即:用Java語(yǔ)言來(lái)操作數(shù)據(jù)庫(kù)廓潜,JDBC是sun公司提供的的一套規(guī)范(mysql善榛,sql server移盆,oracle都需要遵循)

? ? 2.1)jdbc原理

? ? 應(yīng)用程序? ? >JDBC? ? >數(shù)據(jù)庫(kù)驅(qū)動(dòng)? ? >數(shù)據(jù)庫(kù)


? ? JDBC是接口,而JDBC驅(qū)動(dòng)才是接口的實(shí)現(xiàn)据途,沒(méi)有驅(qū)動(dòng)就無(wú)法完成數(shù)據(jù)庫(kù)連接,每個(gè)數(shù)據(jù)庫(kù)廠商都使用自己的驅(qū)動(dòng) 用來(lái)連接自己的驅(qū)動(dòng)


????3.1)jdbc核心類(接口)

? ? JDBC中的核心類有:DriverManager位衩、Connection熔萧、Statement佛致,和ResultSet!使用時(shí)記得導(dǎo)入MySQL驅(qū)動(dòng)包? ??

? ? 1.1)DriverManager:驅(qū)動(dòng)管理

? ? 注冊(cè)驅(qū)動(dòng):可以讓JDBC知道要使用的是那個(gè)驅(qū)動(dòng)

Class.forName(“com.mysql.jdbc.Driver”);


????1.2)Connection:數(shù)據(jù)庫(kù)連接感昼,數(shù)據(jù)庫(kù)操作基于此對(duì)象罐脊,通過(guò)方法獲取Statement對(duì)象

????獲取Connection:可以獲取到Connection爹殊,如果能獲取Connection說(shuō)明數(shù)據(jù)庫(kù)連接成功

String url ="jdbc:mysql://127.0.0.1:3306/數(shù)據(jù)庫(kù)名稱?useUnicode=true&characterEncoding=utf8";

String username="root";

String password="123";

conn = DriverManager.getConnection(url,username,password);


? ? 1.3)Statement:向數(shù)據(jù)庫(kù)發(fā)送sql語(yǔ)句奸绷,在實(shí)際開(kāi)發(fā)中使用的是PreparedStatement(預(yù)編譯聲明)

Statement stmt = con.createStatement();

????executeUpdate():更新操作(增号醉,刪,改)

????executeQuery():查詢操作


? ? 1.4)ResultSet:查詢結(jié)果集铅碍,只有在sql語(yǔ)句執(zhí)行后才會(huì)產(chǎn)生結(jié)果集线椰,結(jié)果集是一個(gè)二位表格憨愉,有行有列


? ? next():使“行光標(biāo)”移動(dòng)到下一行,并返回移動(dòng)后是否有數(shù)據(jù)配紫,遍歷結(jié)果集

? ? getInt(index):獲取第index行的數(shù)據(jù)


? ? 1.5)close:與io流一樣使用后需要關(guān)閉躺孝,先創(chuàng)建的后關(guān)閉底桂,后創(chuàng)建的先關(guān)閉

rs.close();

stmt.close();

con.close();


? ? 1.6)一個(gè)用戶登陸JDBC方法實(shí)例

public void login1(String username, String password) throws ClassNotFoundException, SQLException {

// 1.注冊(cè)驅(qū)動(dòng)

Class.forName("com.mysql.jdbc.Driver");

// 2.獲取連接

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web08", "root", "123");

// 3.編寫(xiě)sql語(yǔ)句

String sql = "select * from tbl_user where uname=? and upassword=?";

// 4.創(chuàng)建預(yù)處理對(duì)象

PreparedStatement pstmt = conn.prepareStatement(sql);

// 5.設(shè)置參數(shù)(給占位符)

pstmt.setString(1, username);

pstmt.setString(2, password);

// 6.執(zhí)行查詢操作

ResultSet rs = pstmt.executeQuery();

// 7.對(duì)結(jié)果集進(jìn)行處理

if (rs.next()) {

System.out.println("恭喜您籽懦," + username + ",登錄成功!");

System.out.println(sql);

} else {

System.out.println("賬號(hào)或密碼錯(cuò)誤!");

}

if (rs != null)

rs.close();

if (pstmt != null)

pstmt.close();

if (conn != null)

conn.close();

}



? ? 1.7)JDBC工具類封裝

public class JDBCUtil {

private static String driver;

private static String url;

private static String username;

private static String password;

/**

* 靜態(tài)代碼塊加載配置文件信息

*/

static {

try {

// 1.通過(guò)當(dāng)前類獲取類加載器

ClassLoader classLoader = JDBCUtil.class.getClassLoader();

// 2.通過(guò)類加載器的方法獲得一個(gè)輸入流

InputStream is = classLoader.getResourceAsStream("db.properties");

// 3.創(chuàng)建一個(gè)properties對(duì)象

Properties props = new Properties();

// 4.加載輸入流

props.load(is);

// 5.獲取相關(guān)參數(shù)的值

driver = props.getProperty("driver");

url = props.getProperty("url");

username = props.getProperty("username");

password = props.getProperty("password");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 獲取連接方法

*

* @return

*/

public static Connection getConnection() {

Connection conn = null;

try {

Class.forName(driver);

conn = DriverManager.getConnection(url, username, password);

} catch (Exception e) {

e.printStackTrace();

}

return conn;

}

/**

* 釋放資源方法

*

* @param conn

* @param pstmt

* @param rs

*/

public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {

if (rs != null) {

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (pstmt != null) {

try {

pstmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

????db.properties

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/web08?useUnicode=true&characterEncoding=utf8

username=root

password=123456


2.連接池

? ? 包含:自定義連接池,c3p0連接池(大多數(shù)使用)拖云,dcbp連接池(少數(shù)使用)应又!使用時(shí)需要導(dǎo)入相應(yīng)到j(luò)ar包,自定義不用

???連接池:用池來(lái)管理Connection尤筐,這樣可以重復(fù)使用Connection洞就。連接池會(huì)自己創(chuàng)建Connection旬蟋,使用時(shí)通過(guò)池來(lái)獲取Connection對(duì)象,當(dāng)使用完后再將Connection歸還到池中去冕碟。池就可以再利用這個(gè)Connection


????2.1)自定義連接池(通過(guò)JDBCUtil獲取的連接)

? ? 自定義類(implements DataSource)? ? >定義一個(gè)容器用于儲(chǔ)存Connection對(duì)象? ? >創(chuàng)建5個(gè)連接對(duì)象放到容器中去? ? >獲取連接的方法? ? >歸還連接方法

/*

* 連接池類

*/

public class MyDataSource implements DataSource{

//1.定義一個(gè)容器用于儲(chǔ)存Connection對(duì)象匆浙,list集合中LinkedList 比較適合插入和刪除首尼,ArrayList適合數(shù)據(jù)查詢和更新

private static LinkedList<Connection> pool = new LinkedList<Connection>();

//2.創(chuàng)建5個(gè)連接對(duì)象放到容器中去

static{

for (int i = 0; i < 5; i++) {

Connection conn = JDBCUtil.getConnection();

pool.add(conn);

}

}

//重寫(xiě)獲取連接的方法

@Override

public Connection getConnection() throws SQLException {

Connection conn = null;

//3.先判斷一下,conn里面是否有連接挠羔,沒(méi)有就創(chuàng)建埋嵌,有就直接使用

if(pool==null){

for (int i = 0; i < 5; i++) {

conn = JDBCUtil.getConnection();//使用的時(shí)1.7)JDBCUtil獲取連接

pool.add(conn);

}

}

//4.從池子中取出連接

conn = pool.remove(0);

return conn;

}

//歸還連接到連接池中的方法(類似于close方法)

public void backClose(Connection conn){

pool.add(conn);

}


? ? 2.2)c3p0連接池:通過(guò)?c3p0-config.xml配置文件獲取連接

????是一個(gè)免費(fèi)開(kāi)源的連接池雹嗦!使用的開(kāi)源項(xiàng)目有:Spring合是,Hibernate等

? ? 導(dǎo)入jar包(c3p0-0.9.1.2.jar)? ? >c3p0-config.xml(必須此文件名)? ? >編寫(xiě)工具類? ? >使用


????c3p0-config.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>

<!-- 默認(rèn)執(zhí)行 -->

? <default-config>

? ? <property name="driverClass">com.mysql.jdbc.Driver</property>

<property name="jdbcUrl">jdbc:mysql:///web08</property>

<property name="user">root</property>

<property name="password">123456</property>

<property name="initialPoolSize">5</property>

<property name="maxPoolSize">20</property>

? </default-config>


? <!-- 指定名稱執(zhí)行 -->

? <named-config name="imwj">

? ? <property name="driverClass">com.mysql.jdbc.Driver</property>

<property name="jdbcUrl">jdbc:mysql:///web08</property>

<property name="user">root</property>

<property name="password">123456</property>

? </named-config>

</c3p0-config>

<!-- 此文件的名稱必須是 c3p0-config.xml-->


????編寫(xiě)工具類


package com.imwj.jdbc.utils;

import java.sql.Connection;

import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/*

* c3p0工具類

*/

public class C3p0Util {

//此處如果不寫(xiě)imwj就會(huì)執(zhí)行默認(rèn)的配置文件

private static ComboPooledDataSource dataSource = new ComboPooledDataSource("imwj");

//返回一個(gè)DataSource連接

public static ComboPooledDataSource getDataSource(){

return dataSource;

}

//返回一個(gè)Connection連接

public static Connection getConnection() throws SQLException{

return dataSource.getConnection();

}

}


? ? 使用

package com.imwj.jdbc.test;

import java.sql.Connection;

import java.sql.PreparedStatement;

import org.junit.Test;

import com.imwj.jdbc.utils.C3p0Util;

import com.imwj.jdbc.utils.JDBCUtil;

public class testC3p0 {

@Test

public void testC3p0Util(){

Connection conn =null;

PreparedStatement pstmt = null;

try{

String sql = "insert into tbl_user values(null,?,?)";

conn = C3p0Util.getConnection();

pstmt = conn.prepareStatement(sql);

pstmt.setString(1, "admin5");

pstmt.setString(2, "12345");

int rows = pstmt.executeUpdate();

if(rows!=0){

System.out.println("數(shù)據(jù)添加成功");

}else{

System.out.println("數(shù)據(jù)添加失敗");

}

}catch(Exception e){

throw new RuntimeException(e);

}finally{

JDBCUtil.release(conn, pstmt, null);

}

}

}


? ? 2.3)dcbp連接池:通過(guò)db.properties配置文件獲取連接

????也是一個(gè)開(kāi)源連接池,是Apache Common成員之一难礼,tomcat內(nèi)置連接池

? ? 導(dǎo)入jar包(commons-dbcp-1.4.jar玫锋,commons-pool-1.5.6.jar)? ? >配置文件? ? >編寫(xiě)工具類? ? >使用


????db.properties配置文件

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/web08?useUnicode=true&characterEncoding=utf8

username=root

password=123456


? ? 編寫(xiě)工具類

package com.imwj.jdbc.utils;

import java.io.InputStream;

import java.sql.Connection;

import java.sql.SQLException;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class dbcpUtil {

private static DataSource dataSource;

static{

try {

//1.加載db.properties文件輸入流

InputStream in = dbcpUtil.class.getClassLoader().getResourceAsStream("db.properties");

//2.讀取輸入流

Properties props = new Properties();

props.load(in);

//3.創(chuàng)建數(shù)據(jù)源

dataSource = BasicDataSourceFactory.createDataSource(props);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public static DataSource getDataSource(){

return dataSource;

}

public static Connection getConnection() throws SQLException{

return dataSource.getConnection();

}

}


? ? 使用

package com.imwj.jdbc.test;

import java.sql.Connection;

import java.sql.PreparedStatement;

import org.junit.Test;

import com.imwj.jdbc.utils.JDBCUtil;

import com.imwj.jdbc.utils.dbcpUtil;

public class testDbcp {

@Test

public void testC3p0Util(){

Connection conn =null;

PreparedStatement pstmt = null;

try{

String sql = "insert into tbl_user values(null,?,?)";

conn = dbcpUtil.getConnection();

pstmt = conn.prepareStatement(sql);

pstmt.setString(1, "admin5");

pstmt.setString(2, "12345");

int rows = pstmt.executeUpdate();

if(rows!=0){

System.out.println("數(shù)據(jù)添加成功");

}else{

System.out.println("數(shù)據(jù)添加失敗");

}

}catch(Exception e){

throw new RuntimeException(e);

}finally{

JDBCUtil.release(conn, pstmt, null);

}

}

}

3.DBUtil(劃重點(diǎn))

? ?如果只是使用JDBC開(kāi)發(fā)谦炬,冗余代碼過(guò)多,為了簡(jiǎn)化開(kāi)發(fā)便使用DButil节沦,也是Apache Common成員之一键思。DBUtil是用了連接池,SQL語(yǔ)句并沒(méi)有減少

? ? 導(dǎo)入jar包(commons-dbutils-1.4.jar)? ? >編寫(xiě)JavaBean? ? >創(chuàng)建QueryRunner對(duì)象(并傳入dataSource)? ? >執(zhí)行SQL語(yǔ)句后ResultSetHandler結(jié)果集接收

? ? 3.1)JavaBean:數(shù)據(jù)庫(kù)表的映射

? ? 要求:JavaBean寫(xiě)在domian目錄下甫贯;屬性是私有字段:private吼鳞;有g(shù)et/set方法;?提供無(wú)參構(gòu)造方法

package com.imwj.domain;

public class User {

private int uid;

private String uname;

private String upassword;

public User() {

super();

// TODO Auto-generated constructor stub

}

public int getUid() {

return uid;

}

public void setUid(int uid) {

this.uid = uid;

}

public String getUname() {

return uname;

}

public void setUname(String uname) {

this.uname = uname;

}

public String getUpassword() {

return upassword;

}

public void setUpassword(String upassword) {

this.upassword = upassword;

}

}


? ? 3.2)QueryRunner對(duì)象:通過(guò)c3p0獲取數(shù)據(jù)源

????QueryRunner(DataSource ds):提供數(shù)據(jù)源(連接池)

//1.創(chuàng)建QueryRunner對(duì)象叫搁,并傳入dataSource

QueryRunner qr = new QueryRunner(C3p0Util.getDataSource());

? ? update(String sql,Object parmas):執(zhí)行增赖条、刪常熙、改操作,parmas是一個(gè)數(shù)組碱茁,即占位符的內(nèi)容

//2.編寫(xiě)sql語(yǔ)句

String sql = "insert into tbl_user values(null,?,?)";

//3.占位符數(shù)組

Object params[] = {"admin6","123456"};

//4.執(zhí)行sql語(yǔ)句

int rows = qr.update(sql, params);//此處需拋出異常

? ? query(String sql,ResultSetHandler<T> rsh,Object parmas):執(zhí)行查詢類操作

List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));


? ? 3.3)ResultSetHandler對(duì)象


? ? BeanHandler:將結(jié)果集中的第一條記錄封裝到一個(gè)指定的JavaBean中裸卫,查詢單條數(shù)據(jù)時(shí)使用

User user = qr.query(sql, new BeanHandler<User>(User.class), params);//查詢單個(gè)用戶select * from tbl_user where uid=?

? ? BeanListHandler:將結(jié)果集中的每一條記錄封裝到指定的JavaBean中,再將JavaBean封裝到List中纽竣,查詢多條或所有數(shù)據(jù)時(shí)使用

List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));//查詢所有用戶select * from tbl_user

? ? ScalarHandler:用于單數(shù)據(jù)墓贿,栗子:select count(*) from tbl_user 時(shí)使用

Long count = (Long) qr.query(sql, new ScalarHandler());//查詢數(shù)據(jù)總行數(shù)select count(*) from tbl_user

? ? 以下幾個(gè)作了解:

? ? ArrayHandler:將結(jié)果集的第一條數(shù)據(jù)封裝到一個(gè)Object[]數(shù)組中,數(shù)組中的每一個(gè)元素就是這條記錄的一個(gè)值

????ArrayListHandler:將結(jié)果集的每一條數(shù)據(jù)都封裝到一個(gè)Object[]數(shù)組中蜓氨,再將數(shù)組封裝到List集合中

? ? ColumnListHandler:指定查詢列名聋袋,再將結(jié)果封裝到一個(gè)List集合中

? ? MapHandler:將結(jié)果集的第一條數(shù)據(jù)封裝到Map<String,Object>,key就是字段名稱穴吹,value就是字段的值

? ? MapListHandler:將結(jié)果集的每一條都數(shù)據(jù)封裝到Map<String,Object>幽勒,再將Map封裝到List集合中


????3.4)DBUtil栗子:

//查詢所有用戶,BeanListHandler

@Test

public void selectAllUser(){

try {

//1.創(chuàng)建QueryRunner對(duì)象港令,并傳入dataSource

QueryRunner qr = new QueryRunner(C3p0Util.getDataSource());

//2.編寫(xiě)sql語(yǔ)句

String sql = "select * from tbl_user";//省略了3.占位符數(shù)組

//4.執(zhí)行sql語(yǔ)句

List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));

//5.遍歷結(jié)果集

for (User user : users) {

System.out.println(user.getUname()+":"+user.getUpassword());

}

} catch (SQLException e1) {

// TODO Auto-generated catch block

throw new RuntimeException(e);

}

}

? ? 在不使用框架的前提下啥容,絕大多數(shù)都是使用DBUtil工具開(kāi)發(fā)锈颗,這樣會(huì)極大的節(jié)省系統(tǒng)資源,提高開(kāi)發(fā)效率_浠荨(重點(diǎn))

---------------------

作者:langao_

來(lái)源:CSDN

原文:https://blog.csdn.net/langao_q/article/details/81052042

版權(quán)聲明:本文為博主原創(chuàng)文章击吱,轉(zhuǎn)載請(qǐng)附上博文鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遥昧,一起剝皮案震驚了整個(gè)濱河市覆醇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炭臭,老刑警劉巖永脓,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異徽缚,居然都是意外死亡憨奸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)凿试,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)排宰,“玉大人,你說(shuō)我怎么就攤上這事那婉“甯剩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵详炬,是天一觀的道長(zhǎng)盐类。 經(jīng)常有香客問(wèn)我,道長(zhǎng)呛谜,這世上最難降的妖魔是什么在跳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮隐岛,結(jié)果婚禮上猫妙,老公的妹妹穿的比我還像新娘。我一直安慰自己聚凹,他們只是感情好割坠,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著妒牙,像睡著了一般彼哼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上湘今,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天敢朱,我揣著相機(jī)與錄音,去河邊找鬼。 笑死蔫饰,一個(gè)胖子當(dāng)著我的面吹牛琅豆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播篓吁,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茫因,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杖剪?” 一聲冷哼從身側(cè)響起冻押,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盛嘿,沒(méi)想到半個(gè)月后洛巢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡次兆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年稿茉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芥炭。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漓库,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出园蝠,到底是詐尸還是另有隱情渺蒿,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布彪薛,位于F島的核電站茂装,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏善延。R本人自食惡果不足惜少态,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望易遣。 院中可真熱鬧况增,春花似錦、人聲如沸训挡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)澜薄。三九已至,卻和暖如春摊册,著一層夾襖步出監(jiān)牢的瞬間肤京,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忘分,地道東北人棋枕。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像妒峦,于是被迫代替她去往敵國(guó)和親重斑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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