Mysql学习笔记

第一次亲密接触

一、数据库相关概念:

①、数据库的好处:

1、持久化数据到本地
2、使用数据库管理软件进行结构化查询

②、数据库常见概念

1、DB:数据库,存储数据的容器
2、DBMS:数据库管理系统(数据库软件、数据库产品)
3、SQL:结构化数据查询语言,不是某个数据库特有的查询语言,而是几乎所有的结构化数据库通用的语言。

③、数据库存储数据的特点

1、数据存放到表中,表再放到库中
2、一个库可以有多张表。每个表拥有唯一表名来标识自己
3、一张表中有多个列(COLUMN),又称为字段,相当于python中的属性
4、表中的每一行数据相当于python中的对象

④、常见的数据库管理系统

Mysql、Oracal、db2,sqlserver

二、Mysql的介绍

①、Mysql背景

mysql AB 》sun 》oracal

②、mysql的优点

1、开源、免费、成本低
2、性能高、移植性也好
3、体积小、便于安装

③、mysql的安装

版本

④、mysql服务的启动和停止

方式一:通过命令行
net start mysql
net stop mysql
方式二:计算机——右击——管理——服务

⑤mysql服务的登录和退出

登录:mysql 【-h主机名 -P端口号】 -u用户名 -p密码
-p密码间不能有空格

退出:exit或ctrl+C

DQL语言

一、基础查询

1、语法

select 查询列表
from 表名

2、特点
  • 查询列表可以是字段、常量、表达式、函数,也可以是多个的组合
  • 查询结果是一个虚拟表
3、示例
  • 查询单个字段
    select 字段名 from 表名
  • 查询多个字段
    select 字段名,字段名 from 表名
  • 查询所有字段
    select * from 表名
  • 查询常量
    select 常量值;
    注意:字符型和日期型的常量必须用单引号引起来,数值型不需要
    -查询函数
    select 函数名(实参列表)
  • 查询表达式
    select 100/200;
  • 起别名
    ①as
    ②空格
  • 去重
    select distinct 字段名 from 表名
  • 加号(做加法运算)
    select 数值+数值:直接运算
    select 字符+数值:先试图将字符转化为数值,如果转化成功,则进行运算,如不能转化,则将字符转化为0再进行运算
    select null+值 结果为null
  • concat(拼接字符串)
    select concat(字符1,字符2,...)
  • ifnull 函数
    判断某字段或表达式是否为null,如果为null返回指定的值,如果不为null,返回原本的值
    select ifnull(commission_pct,0) from employees
  • isnull 函数
    判断字段的值是否为null,如果为null,返回1,否则返回0
    select isnull(commission_pct) from employees

二、条件查询

1、语法

select 查询列表 ③
from 表名 ①
where 筛选条件 ②

2、筛选条件的分类

①、简单条件运算符
`> < = <> != >= <= <=>
②、逻辑运算符
&& and
|| or
! not
③、模糊查询

  • like:一般搭配通配符来匹配字符型数据,但也可查询数值型
    select *
    from employees
    where department_id like '1__'
    通配符:%匹配任意多个字符,_匹配单个字符
  • between and
  • in
  • is null/is not null:用于判断null值

is null PK <=>

普通类型数值 null值 可读性
is null X
<=> X

普通类型数值

三、排序查询

1、语法

select 查询列表
from 表
where 筛选条件
order by 排序列表 【asc|desc】

2、特点

①、后缀
asc:升序
desc:降序
②、排序列表支持单个字段、多个字段、函数、表达式、别名
③、order by位置一般放在查询语句的最后,如果有limit,则为倒数第二

四、常见函数

1、概述

功能:类似python中的方法
好处:提高重用性和隐藏实现细节
调用: select 函数名(实参列表);

2、单行函数
①字符函数

concat:连接
substr:截取字串
upper:变大写
lower:变小写
replace:替换
length:获取字节长度
trim:去前后空格
lpad:左填充
rpad:右填充
instr:获取第一次出现的索引

②数字函数

ceil:向上取整
floor:向下取整
round:四舍五入
mod:取模
truncate:截断
rand:获取随机数,返回0-1的小数(取不到一,可以无限接近)

③、日期函数

nov:返回当前日期加时间
year:返回年
month:返回月
day:返回日
hour:小时
minute:分钟
second:秒
date_formate:将日期转化为字符
str_to_date:将字符转化为时间
curdate:返回当前日期
curtime:返回当前时间
monthname:以英文返回月
datediff:返回两个日期相差的天数

④、其他函数

version:当前数据库服务器版本
database:当前打开的数据库
user:当前用户
password("字符"):对字符加密
md5("字符"):返回字符的md5加密形式

⑤、流程控制函数:
  • if(条件表达式,表达式1,表达式2)
    如果条件表达式成立,返回表达式1,否则返回表达式2
  • case情况1
    case 变量或表达式或字段
    when 常量1 then 值1
    when 常量2 then 值2
    ...
    else 值n
    end
  • case情况2
    when 条件1 then 值1
    when 条件2 then 值2
    ...
    else 值n
    end
3、分组函数
①、分类

max 最大值
min 最小值
sum 和
avg 平均值
count 计算个数

②、特点
语法

select max(字段) from 表名;

支持的类型

sum和avg一般用于处理数值型
max、min、count可以处理任何类型

以上分组函数都忽略null值
都可以搭配distinct使用,实现去重的统计

select sum(distinct 字段) from 表

count函数

count(字段):统计该字段为空值的函数
count(*):统计结果的函数
count(1):也可统计行数

案例:查询每个部门员工数
1 xx 10
2 aa 20
3 bb 20
4 aa 40
5 hh 40

select count(*)
from employee
group by department_id
order by department_id

效率上:

  • MyISAM存储引擎,count(*)效率最高
  • InnoDB存储引擎,count(*)和count(1)效率>count(字段)

五、分组查询

1、语法

select 分组函数,分组后的字段 ⑤
from 表 ①
【where 筛选条件】 ②
group by 分许的字段 ③
【having 分组后的筛选】 ④
【order by 排序列表】 ⑥
注意:having 和 group by一般不起别名(oracal不支持,为了通用性,移植性等事宜一般在mysql也不用)

2、特点
--- 使用关键字 筛选后的表 位置
分组前筛选 where 原始表 group by前面
分组后筛选 having group by之后的表 group by后面

六、连接查询

1、含义

当查询中涉及到多个表中的字段,使用多表连接查询
select 字段1,字段2
from 表1,表2,...;

  • 笛卡尔乘积:当查询多个表时,没有添加有效的连接条件,导致多个表所有行实现完全连接。
  • 如何解决:添加有效的连接条件
2、分类

按年代分:

sql92:(一般认为只支持内连接)
  • 等值
    select 查询列表
    from 表1 别名1,表2,别名2
    where 表1.key1 = 表2.key2
    【and】
    【group by 分组字段】
    【having 分组后的筛选】
    【order by 排序字段】

特点:
一般为表起别名
多表的顺序可以调换
n表连接至少需要n-1个连接条件
等值连接的结果为多表的交集部分

  • 非等值
    select 查询列表
    from 表1 别名1,表2,别名2
    where 非等值连接条件
    【and】
    【group by 分组字段】
    【having 分组后的筛选】
    【order by 排序字段】
  • 自连接
    select 查询列表
    from 表 别名1,表,别名2
    where 别名1.key1 = 别名2.key2
    【and】
    【group by 分组字段】
    【having 分组后的筛选】
    【order by 排序字段】

其实也支持一部分外连接(在oracal、sqlserver中)但是表现不好,mysql中不支持。

sql99
内连接
  • 语法:
    select 查询列表
    from 表1 别名
    【inner】 join 表2 别名 on 连接条件
    where 筛选条件
    group by 分组列表
    having 分组后筛选
    order by 排序列表
    limit 子句

  • 特点:
    ①表的顺序可以调换
    ②内连接的结果 = 多表的一个交集
    ③n表连接至少需要n-1个连接条件

  • 分类
    等值
    非等值
    自连接

外连接
  • 语法:
    select 查询列表
    from 表1 别名
    left|right|full【outer】 join 表2 别名 on 连接条件
    where 筛选条件
    group by 分组列表
    having 分组后筛选
    order by 排序列表
    limit 子句

  • 特点:
    ①查询的结果=主表中所有的行,其中从表会显示匹配行,如果不匹配显示null
    ②left join 左边为主表,right join 右边为主表,full join两边都是主表
    ③一般用于查询除交集部分的剩余不匹配行(匹配部分一般用内连就能做)

  • 分类:
    左外
    右外
    全外(mysql不支持)

交叉连结
  • 语法:
    select 查询条件
    from 表1 别名
    cross join 表2 别名;

类似笛卡尔乘积

七、子查询:

1、含义:

嵌套在其他语句内部的select语句称为子查询或内查询,外面的语句可以是insert、update、delete、select等,多放在selelct语句内

2、分类
①按出现位置
  • select后面:仅标量子查询
  • from后面:一般表子查询
  • where或having后面:
    标量子查询
    列子查询
    行子查询
  • exists后面
    标量子查询
    列子查询
    行子查询
    表子查询
②按结果集的行列
  • 标量子查询(单行子查询):结果集为一行一列
  • 列子查询:结果集为多行一列
  • 行子查询:结果集为多行多列
  • 表子查询:结果集为多行多列

三、示例
用得最多:
where或having后面:

  • 标量子查询
    查询最低工资员工的姓名和工资
    ①查询最低工资
    select min(salary) from employees
    ②查询最低工资员工的姓名和工资
    select last_name,salary from employees
    where salary=(
    select min(salary) from employees
    )
  • 列子查询
    查询所有是领导的员工姓名
    ①查询所有领导的id
    select distinct manaerger_id
    from employees
    ②查询所以领导的名字
    selelct last_name
    from employess where employee_id in (
    select distinct manaerger_id
    from employees
    )

八、分页查询

1、应用场景

当要查询的条目数太多,一页显示不全

2、语法

select 查询列表
from 表
limit 【offset,】size;

注意:
offset代表的是起始条目索引,默认从0开始
size代表的是显示的条目数

公式:
假如要显示的页数是page,每一页条目数为size
select 查询列表
from 表
limit (page-1)*size,size;

九、联合查询

1、含义

union:合并、联合,将多次查询结果合并成一个结果

2、语法

查询语句1
union 【all】
查询语句2
union 【all】
...

3、意义

①将一个复杂语句简化为简单语句
②在查询多个表时,查询的列基本是一致的

4、特点

①要求多条查询语句列数必须一致
②要求查询语句查询的各列类型、顺序最好一直
③Union和Union All的区别

  • Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
  • Union All:对两个结果集进行并集操作,包括重复行,不进行排序;

十、查询语句总结

1、语法

select 查询列表 ⑦
from 表1 别名 ①
连接类型 join 表2 别名 ②
on 连接条件 ③
where 筛选条件 ④
group by 分组 ⑤
having 筛选 ⑥
order by排序列表 ⑧
limit 起始条目索引,条目数;⑨

DML语言

一、插入

方式1
语法:

insert into 表名(字段名,...) values(值,...)

特点:

①要求值的类型和字段的类型要一致或兼容(“123”可转化为123但“join”不能转化为数值型)
②子段的个数不一定与原始表中的字段个数和顺序一致,但必须保证值和字段一一对应
③假如表中有可以为null的字段,可以通过以下两种方式插入null值:

  • 字段和值都省略
  • 字段写上,值写入null

④字段和值的个数必须一致
⑤字段名可以省略,这种情况下字段部分默认包含所有列

方式2
语法:

insert into 表名 set 字段=值,字段=值,...

两种方式的区别

  • 方式一支持一次插入多行
    insert into 表名(字段名,...) values(值,...),(值,...),...

  • 方式一支持子查询:
    insert into 表名
    查询语句

二、修改

1、修改单表的纪录

update 表名 set 字段=值,字段=值 【where 筛选条件】

2、修改多表记录

update 表名
left|right|inner join 表2 on 连接条件
set 字段=值,字段=值 【where 筛选条件】

四、删除

方式1:delete
删除单表记录

语法:
delete from 表名 【where 筛选条件】【limit 条目数】

删除多表记录(级联删除)

语法:
delete 别名1,别名2
from 表1 别名1
left|right|inner join 表2 别名2 on 连接条件
【where 筛选条件】

方式2:truncate

truncate table 表名

两种方式的区别(面试题):

1、delete删除后如果再插入,从断点开始
truncate(清空):删除后如果再插入,自增长列从1开始
2、delete可以添加删除条件
truncate不行
3、truncate效率较高
4、truncate没有返回值
delete会返回受影响的条数
5、truncate不可以回滚
delete可以回滚

DDL语言

一、库的管理
1、创建库

create database 【if not exists】 库名 【character set 字符集名】

2、修改库

alter database 库名 charecter set 字符集名

3、删除库

drop databse 【if exists】 库名

二、表的管理
1、创建表

create table 【if not exists】 表名 (
字段名 字段类型 【约束】,
字段名 字段类型 【约束】,
...
字段名 字段类型 【约束】
)

2、修改表
  • 添加列
    alter table 表名 add column 列名 类型 【约束】【first|after 列名】
  • 修改列的类型或约束
    alter table 表名 modify column 列名 新类型 【新约束】
  • 修改列名
    alter table 表名 change column 旧列名 新列名 新类型 【新约束】
  • 删除列
    alter table 表名 drop column 列名
  • 修改表名
    alter table 表名 rename 【to】新表名
3、删除表

drop table 【if exists】表名

4、复制表
  • 复制表结构
    create table 表名 like 旧表
  • 复制表结构和内容
    create table 表名
    select 查询列表 from 旧表 【where 筛选条件】
三、数据类型、
数值型
  • 整型
    tinyint、smallint、midiumint、int/integer、bigint
    分别占1、2、3、4、8字节
特点:
  • 都可设置有符号和无符号,默认有符号,通过unsign可设置无符号
  • 如果超出范围,会报out or range异常,并插入临界值
  • 长度可以不指定,默认会有一个长度
长度代表显示的最大宽度,如果不够则左边用0填充,但需要搭配zerofill,并且默认变为无符号整型
浮点型
  • 定点数:decimal(M,D)
  • 浮点数:
    float(M,D)
    double(M,D)
特点:
  • M代表整数部分+小数部分的长度,D代表小数部分的长度
  • 如果超出范围,会报out or range异常,并插入临界值
  • M和D都可以省略,但对于定点数,M默认为10,D默认为0
  • 如果精度要求高,优先使用定点数
字符型

char、varchar、binary、varbinary、enum、set、text、blob

  • char:固定长度字符,写法为char(M),最大长度不超过M,其中M可以省略,默认为1
  • varchar:可变长度字符,写法为varchar(M),最大长度不超过M,其中M不可以省略
日期型
  • year 年
  • date 日期
  • time 时间
  • datetime
    日期+时间 8字节 可保存时间范围大
  • timestamp
    日期+时间 4字节 可保存时间范围小-2038 易受时区等的影响,但更能反映真实时区的时间
四、约束
1、常见的约束
  • NOT NULL:非空:该字段值必填
  • UNIQUE:唯一,该字段值不可重复
  • DEFAULT:默认,该字段不动手动插入,有默认值
  • CHECK:检查,mysql不支持
  • PRIMARY KEY:主键,该字段的值不可重复且非空
  • FOREIGN KEY:外键,该字段的值引用了另外的表的字段
主键和唯一
  • 区别:
    ①一个表至多有一个主键,但可以有多个唯一建
    ②主键不允许为空,唯一可为空
  • 相同点:
    ①都具有唯一性
    ②都支持组合键,但不推荐(不稳定)
外键
  • 增加外键
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREGIN KY (majorid) REFERENCE major(id)
可以通过下列方式删除主表的记录

1、用于限制两个表的关系,从表的字段值引用了主表的某字段值
2、外键列额主表的被引用列要求类型一致,意义相同,名称无要求
3、主表的被引用列要求是一个key,一般为主键
4、插入数据,先插入主表
5、删除数据,先删除从表

  • 设置级联删除(删除主表中数据会级联删除从表中数据)
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREGIN KY (majorid) REFERENCE major(id) ON DELETE CASCADE
  • 设置级联置空(删除主表中数据会级联将从表中数据置空)
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREGIN KY (majorid) REFERENCE major(id) ON DELETE SET NULL
2、创建表时添加约束

create 表名(
字段名 字段类型 not null,#非空
字段名 字段类型 unique,#唯一
字段名 字段类型 primary key,#主键
字段名 字段类型 default 值,#默认
constraint 约束名 foreign key(字段名) reference 主表(被引用字段)

注意:
支持类型 可以起约束名
列级约束 除了外键 不可以
表级约束 除了非空和默认 可以,但对主键无效

列级约束可以在一个字段上添加多个,中间用空格隔开,没有顺序要求

3、修改表时添加或删除约束

1、非空

  • 添加非空
    alter table 表名 modify column 字段名 字段类型 not null
  • 删除非空
    alter table 表名 modify column 字段名 字段类型
    2、默认
  • 添加默认
    alter table 表名 modify column 字段名 字段类型 default 值
  • 删除默认
    alter table 表名 modify column 字段名 字段类型
    3、主键
  • 添加主键
    alter table 表名 add primary key(字段名)
  • 删除主键
    alter table 表名drop primary key(字段名)
    4、唯一
  • 添加唯一
    alter table 表名 add 【constraint 约束名】unique key(字段名)
  • 删除唯一
    alter table 表名drop inddex 索引名
    5、外键
  • 添加外键
    alter table 表名 add 【constraint 约束名】foreign key(字段名) references 主表(被引用表)
  • 删除唯一
    alter table 表名drop foreign key 约束名
4、自增长列

特点:
①、不用手动插入值,可以自动提供序列值,默认1开始,步长为1

  • 如果要更改起始值:手动输入值

  • 如果要更改步长:更改系统变量值
    ②、一个表至多有一个自增长列
    ③、自增长列值能为数值型
    ④、自增长列必须为一个key

  • 创建表时设置自增长列
    create table(
    字段名 字段类型 约束 auto_increment

  • 修改表时设置自增长列
    alter table 表 modify column 字段名 字段类型 约束 auto_increment

  • 删除自增长列
    alter table 表 modify column 字段名 字段类型 约束

TCL语言

事务
1、含义:

一条或多条sql语句组成的一个执行单位,一组sql语句要么都执行要么都不执行

2、特点:ACID
  • A 原子性:
    一个事务是一个不可再分割的整体,要么都执行要么都不执行
  • C 一致性:
    一个事务使数据从一个一致性状态到另一个一致性状态
  • I 隔离性:
    一个事务不受其他事务的干扰,多个事务相互隔离
    D 持久性:
    一个事务一旦提交了,则永久性保存到本地
3、事物的使用步骤:

了解:

  • 隐式(自动)事务:没有明显的开启和结束,可以自动提交,比如insert、update、delete
  • 显示事务:具有明显的开始和结束

使用显示事务:

  • ①开启事务
    set autocommit=0
    start transaction 可以省略
  • ②编写一组逻辑sql语句
    注意:事务中的sql语句支持的是insert、update、delete这些语句,select也算(不会影响数据库)
  • ③【设置回滚点】
    savepoint 回滚点名
  • ③结束事务
    提交 commit
    回滚 rollback 【to 回滚点名】
4、并发事物
  • ①事务并发问题是如何发生的?
    多个事务同时操作同一个数据库时
  • ②并发问题有哪些?
脏读:

一个事务读取了另一个事务还没有提交的数据,另一事务回滚后发生脏读

不可重复的:

一个事务在另一事务开始前和提交后分别读取,结果不一样(另一事务更新数据)

幻读:

一个事务在另一事务开始前和提交后分别读取,行数不一样(另一事务插入数据)

  • ③如何解决并发问题?
    通过设置隔离级别
  • ④隔离级别
脏读 不可重复读 幻读
read uncommited:读未提交
read commited:读已提交 x
repeatable read:可重复读 x x
serializable:串行化 x x x
视图
1、含义
  • mysql5.1出现的新特性
  • 本身是一个虚拟表,是通过原始表中的数据动态生成的
  • 好处:
    ①简化了sql语句
    ②提高了重用性
    ③保护了基表数据,提高了安全性
2、创建

create view 视图名
as
查询语句;

3、修改
  • 方式一:
    create or replace view 视图名
    as
    查询语句;
  • 方式二:
    alter view 视图名
    as
    查询语句;
4、删除

drop view 视图1,视图2,...

5、查看

desc 视图名
show create view 视图名

6、使用
  • 插入 insert
  • 修改 update
  • 删除 delete
  • 查看 select
  • 注意:视图一般用于查询,而不是更新的,所以具备以下特点的视图都不允许更新
    ①包含分组函数、group by、distinct、having、union
    ②join
    ③常量视图
    ④where中的子查询用到了from中的表
    ⑤用到了不可更新的视图(视图来源于视图的时候)
7、视图和表的对比
关键字 是否占用内存 使用
视图 view 占用较小,只保存sql逻辑 一般用于查询
table 保存实际数据 增删改查
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,030评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,198评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,995评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,973评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,869评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,766评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,967评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,599评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,886评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,901评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,728评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,504评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,967评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,128评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,445评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,018评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,224评论 2 339