Oracle 数据库

一、前言

假设有一张用户表system_user,里面包含主键id、姓名name、年龄age的列属性,用户足迹表system_user_history,里面包含主键id、外键user_id、足迹name。

二、DataManipulitionLanguage 数据操作语言

insert 新增操作

insert into system_user values (1,'wjx',25); -> 默认全字段新增,按列属性顺序依次填入参数
insert into system_user (id,name) values (1,'wjx'); -> 显式指定需要新增的列属性
insert into system_user select id,name,age from system_user; -> 默认全字段新增,通过查询语句赋值
insert into system_user (id,name) select id,name from system_user; -> 显式指定需要新增的列属性

update 更新操作

update system_user set name = 'wjx' where id = 1; -> 显式指定需要更新的列属性

delete 删除操作

delete from system_user where id = 1; -> 显式指定需要删除的行

select 查询操作

select 1 from dual; -> 虚拟表
select * from system_user; -> 真实表

full outer join / full join 全外连接,a表有x行,b表有y行,总共为x*y行

select * from system_user,system_user_history; -> 方式一
select * from system_user full outer join system_user_history; -> 方式二

left outer join / left join 左外连接,a表有x行,b表有y行,总共为大于等于x行

select * from system_user su,system_user_history suh where su.id = suh.user_id(+); -> 方式一
select * from system_user su left join system_user_history suh on su.id = suh.user_id; -> 方式二

right outer join / right join 右外连接,a表有x行,b表有y行,总共为大于等于y行

select * from system_user su,system_user_history suh where su.id(+) = suh.user_id; -> 方式一
select * from system_user su right join system_user_history suh on su.id = suh.user_id; -> 方式二

inner join / join 内连接,匹配两个表都符合条件的行

select * from system_user su inner join system_user_history suh on su.id = suh.user_id;

group by 分组,分组条件必须作为查询列

select id from system_user group by id having  id = 1

Merge 联合操作,有则更新,无则新增

MERGE INTO 
SYSTEM_USER_DETAIL SUD 
USING 
(SELECT * FROM SYSTEM_USER where AGE = 20) SU
ON 
(SU.USER_ID = SUD.USER_ID)
WHEN MATCHED THEN 
UPDATE SET SUD.USER_ID = SU.USER_ID
WHEN NOT MATCHED THEN 
INSERT (SUD.USER_ID) VALUES (SU.USER_ID);

三、运算符号

alias 别名

select id alias_id from system_user; -> 空格
select id as alias_id from system_user; -> as
select id as "alias_id" from system_user; -> 双引号

|| 连接符

select id || '-' || name || '-' || age from system_user; -> 以id-name-age格式输出属性值

in(set) 等于集合里某个元素即返回

select * from system_user where id in (1,2,3); -> 返回id为1的行

all(set) 大于/小于集合里的所有元素即返回

select * from system_user where id > all (0,2,4); -> 不返回行,id为1的行不满足大于2/4

any(set) 大于/小于集合里的某个元素即返回

select * from system_user where id > any(0,2,4); -> 返回id为1的行,id为1的行满足大于0

distinct 去重

select distinct * from system_user;

= 等于、> 大于、>= 大于等于、< 小于、<= 小于等于、!= 不等于、<> 不等于

select * from system_user where id = 1;
select * from system_user where id > 1;
select * from system_user where id >= 1;
select * from system_user where id < 1;
select * from system_user where id <= 1;
select * from system_user where id != 1;
select * from system_user where id <> 1;

between and 范围闭区间

select * from system_user where id between 1 and 10; -> id在1到10的行

like 模糊查询,%匹配任意多个字符,_匹配任意单个字符,escape 转义关键字

select * from system_user where name like '%\_%' escape '\'; -> 匹配name带有_的行

is null 判断空

select * from system_user where age is null;

is not null 判断非空

select * from system_user where age is not null;

and 并

select * from system_user where id = 1 and name = 'wjx';

or 或

select * from system_user where id = 2 or name = 'wjx';

not 非,搭配其它关键字使用

select * from system_user where id not between 1 and 10; -> id不在1到10范围内
select * from system_user where id not in (1,2,3); -> id不等于1/2/3

order by 排序,desc降序、asc升序

select * from system_user order by id asc,name desc; -> id升序、name降序来排列行

case when then else end 多条件分支

select case id when 1 then 1 else 0 end from system_user;

decode 多条件分支

select decode(id,1,1,0) from system_user;
case id when 1 then 1 else 0 end;

savepoint 设置保存点

savepoint point_user;

rollback 回滚事务

rollback; -> 全回滚
rollback to savepoint point_a; -> 回滚到某个保存点

commit 提交事务

commit;

四、内置函数

lower 全小写

lower('A'); -> a

upper 全大写

upper('a'); -> A

initcap 首字母大写,空格隔开被认为不同词汇

initcap('hello world'); -> Hello World

concat 连接

concat('a','b'); -> ab
concat(concat('%', 'a'), '%'); -> %a%

substr 截取字符串

substr('abcdefg',1,5); -> abcde,从第1个字符开始,截取5个

length 字符串长度

length('abcde'); -> 5

regexp_replace 根据正则表达式替换字符串

regexp_replace(str, ',', ''); -> 字符串/被替换字符/替换字符

regexp_substr 根据正则表达式切割字符串

select regexp_substr(str, '[^,]+', 1, Level,'i') from dual
connect by Level <= LENGTH(str) - LENGTH(regexp_replace(str, ',', '')) + 1);

instr 返回字符串的下标,没有则-1

instr('hello',o); -> 5

lpad 左对齐,缺位补符号

lpad('hello',10,'*'); -> *****hello

rpad 右对齐,缺位补符号

rpad('hello',10,'*'); -> hello*****

trim 清除左右两侧,默认是空格

trim(' hello '); -> hello
trim('h' from 'hello'); -> ello

replace 替换字符串

replace('abc','b','d'); -> adc

round 四舍五入

round(5.234,2); -> 5.23
round(2.345,2); -> 2.35
round(sysdate,'month'); -> 按月份四舍五入

trunc 截断

trunc(2.345,2); -> 2.34
trunc(sysdate); -> 2022-01-01

mod 求余

mod(10,3); -> 1

sysdate 当前日期

select sysdate from dual; -> 今天
select sysdate+1 from dual; -> 明天
select sysdate-1 form dual; -> 昨天

add_months 月份加减

add_months(sysdate,2); -> 两个月后
add_months(sysdate,-2); -> 两个月前

last_day 月份最后一天

last_day(sysdate); -> 当月最后一天

next_day 下一个同等日期

next_day(sysdate,'星期五'); -> 下个星期五日期

to_date 字符串转日期

to_date('2022-01-01','yyyy-mm-dd');

to_char 其它类型转字符串

to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'); -> 日期转字符串
to_char(1234567.89,'999,999,999.99'); -> 1,234,567.89 -> 9代表不补零
to_char(1234567.89,'000,000,000.99'); -> 001,234,567.89 -> 0代表补零

to_number 字符串转数字

to_number('1,234','9,999'); -> 1234

nvl 输出非空

nvl(null,0); -> 0
nvl(1,0); -> 1

nvl2 非空输出表达式一,空输出表达式二

nvl2(null,0,1); -> 1
nvl2(2,0,1); -> 0

coalesce 输出非空,可变长度参数

coalesce(null,0,1); -> 0
coalesce(null,null,1); -> 1

nullif 相等输出空

nullif(1,1); -> null
nullif(1,2); -> 1

avg 平均值

select avg(id) from system_user group by id;

count 统计非空行数

select count(*) from system_user;

max 最大值

select max(id) from system_user group by id;

min 最小值

select min(id) from system_user group by id;

stddev 标准差

select stddev(id) from system_user group by id;

sum 合计

select sum(id) from system_user group by id;

listagg 分组拼接

select user_id, listagg(name,',') within group (order by user_id) name
from system_user_history group by user_id; -> 将用户所有足迹用,串起来

CHR & ASCII 特殊字符转义

select ascii('''') from dual; -> 39
select chr(39) from dual; -> '

ASCIISTR & UNISTR 编码互转解决乱码

select ASCIISTR('我') from dual;
select UNISTR('\6211') from dual;

五、约束

not null 非空约束

alter table system_user modify id constraint suid  not null; -> 添加名为suid的约束

unique 唯一约束

alter table system_user add constraint suid unique(id); -> 添加名为suid的约束

primary key 唯一非空约束

alter table system_user add constraint suid primary key(id); -> 添加名为suid的约束

foreign key 外键

alter table system_user_history add constraint suhuserid foreign key(user_id)
references system_user(id) -> 关联外表
on delete cascade / on delete set null -> 外表删除时执行操作(级联删除/级联置空)

check 检查

alter table system_user add constraint suage check(age between 18 and 35);

drop 删除约束

alter table system_user drop constraint suid;

disable 约束无效化

alter table system_user disable constraint suid;

enable 约束有效化

alter table system_user enable constraint suid;

modify 约束不能修改,只能删除再添加

alter table system_user modify(id number(10,0) constraint suid not null);

六、DataDefinitionLanguage 数据定义语言

创建表

create table system_user( -> 列级约束
  id number(10) constraint id primary key,
  name varchar2(20) constraint name unique,
  age number(10) constraint age not null
);

create table system_user( -> 表级约束
  id number(10),
  name varchar2(20),
  age number(10),
  constraint id primary key(id),
  constraint name unique(name),
  constraint age not null(age),
  constraint range check(age>0 and age<100)
);

create table system_people as select * from system_user; -> 复制现有的表和数据
create table system_people as select * from system_user where 1=2; -> 复制空表

修改表

alter table system_user add(email varchar2(20)); -> 添加列
alter table system_user modify(age number(15) default 0); -> 修改列
alter table system_user drop column email; -> 删除列
alter table system_user rename column name to username; -> 修改列名

删除表

drop table system_user;

清空表

truncate table system_user;

重命名表

rename system_user to system_people;

创建索引

create index index_name on system_user(name);

删除索引

drop index index_name;

创建序列

create sequence seq_system_user -> 序列名
increment by 1 -> 自增量
start with 1 -> 起始值
maxvalue 99999999 -> 最大值
cycle/nocycle -> 是否循环
order/noorder -> 是否有序
cache 20/nocache -> 是否缓存

修改序列

alter sequence seq_system_user order cycle; -> 修改多个属性

删除序列

drop sequence seq_system_user;

使用序列作为自增主键

select seq_system_user.nextval from dual; -> 下一个值
select seq_system_user.currval from dual; -> 当前值

创建视图

create view view_system_user as select id,name from system_user with read only; -> 添加只读权限
create or replace view view_system_user as select * from system_user; -> 修改视图

更新视图

update view_system_user set age = 25 where id = 1;
delete from view_system_user where id = 1;

删除视图

drop view view_system_user;

兼容语法

declare
    num number;
begin
    select count(1) into num from user_tables where table_name = upper('system_user');
    if num > 0 then
        execute immediate 'drop table system_user';
    end if;
    
    select count(1) into num from user_ind_columns where index_name = upper('system_user_index');
    if num > 0 then
        execute immediate 'drop index system_user_index';
    end if;
    
    select count(1) into num from user_sequences where sequence_name= upper('system_user_index_seq');
    if num > 0 then
        execute immediate 'drop sequence system_user_index_seq';
    end if;
    
    select count(1) into num from user_tab_cols where table_name = upper('system_user') and column_name = upper('user_id');
    if num > 0 then
        execute immediate 'alter table system_user drop column user_id';
    end if; 

    select count(1) into num from user_constraints where table_name = upper('system_user') and constraint_name = upper('user_id');
    if num > 0 then
        execute immediate 'alter table system_usermodify user_id null';
    end if;
end;

七、存储过程

create 创建函数

CREATE OR REPLACE PACKAGE -> 定义包名
CUSTOM_PACKAGE IS -> 包内可以定义多个函数
  PROCEDURE CUSTOM_PROCEDURE_1(PARAM IN VARCHAR2);
  PROCEDURE CUSTOM_PROCEDURE_2(PARAM OUT VARCHAR2);
END CUSTOM_PACKAGE;

CREATE OR REPLACE PACKAGE BODY -> 定义包体
CUSTOM_PACKAGE IS 
  PROCEDURE CUSTOM_PROCEDURE_1(PARAM IN VARCHAR2) AS ... END;
  PROCEDURE CUSTOM_PROCEDURE_2(PARAM OUT VARCHAR2) AS ... END;
END CUSTOM_PACKAGE;

BEGIN -> 调用函数
  CUSTOM_PACKAGE.CUSTOM_PROCEDURE_1('');
END;

declare 定义变量

declare
  name varchar2(20) := null;
  age student.age%type := null; -> 动态定义类型
  row student&rowtype := null; -> 动态定义整行

into 赋值

begin
  select student.name,student.age into name,age from student where id = 1;
exception
  when not found then
end;

cursor 游标,存储临时数据

cursor student_cursor is select * from student; -> 定义游标

student_id student.id%type; -> 定义游标属性
student_name student.name%type; -> 定义游标属性

open student_cursor; -> 打开游标
loop
  fetch student_cursor into student_id, student_name; -> 读取数据
  exit when student_cursor%NOTFOUND; -> 无数据时退出
end loop;
close student_cursor; -> 关闭游标

type student_type is record ( -> 定义游标类别
  student_id student.id%type,
  student_name student.name%type
);
type student_cursor is ref cursor return student_type; -> 定义游标返回类别

exception 异常,捕获程序错误

declare custom_exception exception; -> 自定义异常
begin
  raise custom_exception; -> 手动抛出异常
  commit;
exception
  when NO_DATA_FOUND then
    dbms_output.put_line(sqlcode); -> 编号
    dbms_output.put_line(sqlerrm); -> 描述信息
    dbms_output.put_line(dbms_utility.format_error_backtrace); -> 发生位置
    dbms_output.put_line(dbms_utility.format_call_stack); -> 发生栈
  when others then -> 捕获并处理
    rollback;
end;

dbms_output 输出日志

set serveroutput on; -> 开启输出服务
set serveroutput off; -> 关闭输出服务
dbms_output.put('不换行');
dbms_output.new_line; -> 换行
dbms_output.put_line('自动换行');

dbms_metadata 获取创建语句

select dbms_metadata.get_ddl('TABLE','TABLE_NAME','TABLE_SCHEMA') from dual; -> 参数2/3动态变更

if (boolean) then (logic) elsif (boolean) then (logic) else (logic) end if; 条件表达式

if name = 'wjx' then update student set age = '20' where id = 1;
elsif name = 'xjw' then update student set age = '21' where id = 2;
else update student set age = '21' where id = 3;
end if;

goto 循环

declare x :=10;
begin
  <<circle_point>>
  if x>0 then 
    x := x -1;
    goto circle_point;
  else
    dbms_output.put_line('循环结束');
  end if;

for (var) in (set) loop (logic) end loop; 循环

begin
  for student_list in select * from student loop
    if student_list.name = 'wjx' then
      update student set age = '20' where id = 1;
    else end if;
  end loop;
end;

begin
    for i in 1..100 loop
        dbms_output.put_line(i); -> 打印1-100
    end loop;
end;

while (boolean) loop (logic) end loop; 循环

declare x := 0;
begin
  while x < 10 loop
    x := x+1;
  end loop;
end;

loop (logic) exit when (boolean) end loop; 循环

declare x:= 0;
begin
  loop x := x + 1;
  exit when x > 10;
  end loop;
end;

八、权限

为用户授予权限

create public synonym db_name.table_name for table_name; -> 同义词
grant select on db_name.table_name to oracle_username; -> 查询
grant update on db_name.table_name to oracle_username; -> 更新
grant delete on db_name.table_name to oracle_username; -> 删除
grant insert ondb_name.table_name to oracle_username; -> 新增

查询用户表权限

select * from dba_tab_privs 
where 1= 1
and table_name = 'table_name' 
and grantee = 'oracle_username'
and privilege in ('SELECT','UPDATE','DELETE','INSERT');

九、触发器

触发类型(12种),包含新增、修改、删除

类型 描述
BEFORE INSERT 新增前,表级
BEFORE INSERT FOR EACH ROW 新增前,行级
AFTER INSERT 新增后,表级
AFTER INSERT FOR EACH ROW 新增前,行级
BEFORE UPDATE 更新前,表级
BEFORE UPDATE FOR EACH ROW 更新前,行级
AFTER UPDATE 更新后,表级
AFTER UPDATE FOR EACH ROW 更新后,行级
BEFORE DELETE 删除前,表级
BEFORE DELETE FOR EACH ROW 删除前,行级
AFTER DELETE 删除后,表级
AFTER DELETE FOR EACH ROW 删除后,行级
:NEW.column 新值,INSERT/UPDATE有,DELETE无
:OLD.column 旧值,UPDATE/DELETE有,INSERT无
OR,AFTER INSERT OR DELETE ON system_user 设立在某几种操作上触发
OF,AFTER UPDATE OF name ON system_user 设立在某个字段上触发

Insert 时机

CREATE OR REPLACE TRIGGER SYSTEM_USER_A_I
    AFTER INSERT
    ON system_user
    FOR EACH ROW
BEGIN
    INSERT INTO system_user_log(ID, DATE, TYPE, USER_ID, USER_NAME, USER_AGE)
    VALUES(SEQ_SYSTEM_USER_LOG.nextval, sysdate, 'INSERT', :NEW.id, :NEW.name, :NEW.age);
END;

Update 时机

CREATE OR REPLACE TRIGGER SYSTEM_USER_B_U
    BEFORE UPDATE
    ON system_user
    FOR EACH ROW
BEGIN
    INSERT INTO system_user_log(ID, DATE, TYPE, USER_ID, USER_NAME, USER_AGE)
    VALUES(SEQ_SYSTEM_USER_LOG.nextval, sysdate, 'UPDATE', :OLD.id, :OLD.name, :OLD.age);
END;
CREATE OR REPLACE TRIGGER SYSTEM_USER_A_U
    AFTER UPDATE
    ON system_user
    FOR EACH ROW
BEGIN
    INSERT INTO system_user_log(ID, DATE, TYPE, USER_ID, USER_NAME, USER_AGE)
    VALUES(SEQ_SYSTEM_USER_LOG.nextval, sysdate, 'UPDATE', :NEW.id, :NEW.name, :NEW.age);
END;

Delete 时机

CREATE OR REPLACE TRIGGER SYSTEM_USER_B_D
    BEFORE DELETE
    ON system_user
    FOR EACH ROW
BEGIN
    INSERT INTO system_user_log(ID, DATE, TYPE, USER_ID, USER_NAME, USER_AGE)
    VALUES(SEQ_SYSTEM_USER_LOG.nextval, sysdate, 'DELETE', :OLD.id, :OLD.name, :OLD.age);
END;

十、JDBC连接

SQL

String sql = "select id from system_user where name = ?";
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    connection = super.dataSource.getConnection();
    ps = connection.prepareStatement(sql);
    ps.setString(1, "wjx"); -> 入参

    rs = ps.executeQuery();
    while (rs.next()) {
        String id = rs.getString("id"); -> 出参
    }
} finally {
    if(rs != null) rs.close();
    if(ps != null) ps.close();
    if(connection != null) connection.close();
}

PLSQL

CREATE OR REPLACE PROCEDURE SCHEMA.GET_NEW_USER(in_date IN DATE DEFAULT sysdate, out_user_list OUT SYS_REFCURSOR) IS
--     DECLARE
--       in_date DATE := to_date('2023-01-01', 'yyyy-mm-dd');

    BEGIN
        OPEN out_user_list FOR
            SELECT su.*
            FROM system_user su
            WHERE create_date > TRUNC(in_date - 7);
    END;
/
String sql = "{call SCHEMA.GET_NEW_USER(?, ?)}";

Connection connection = null;
CallableStatement cs = null;
ResultSet rs = null;

try {
    connection = super.dataSource.getConnection();
    cs = connection.prepareCall(sql);
    cs.setString(1, new java.sql.Date());
    cs.registerOutParameter(2, -10);
    cs.execute();

    rs = cs.getObject(2, ResultSet.class);
    while (rs.next()) {
        String id = rs.getString("id"); -> 出参
    }
} finally {
    if(rs != null) rs.close();
    if(ps != null) ps.close();
    if(connection != null) connection.close();
}

FUNTION

create or replace function f_no_param return varchar2 is
begin
    return 'hello, no param';
end;

create or replace function f_have_param(id in integer, name out varchar2) return varchar2 is
begin
    name := 'wjx';
    return 'hello, have param';
end;
String noParamSql = "{? = call f_no_param}";
String haveParamSql = "{? = call f_have_param(?,?)}";
Connection connection = null;
CallableStatement cs1 = null;
CallableStatement cs2 = null;

try {
    connection = super.dataSource.getConnection();
    cs1 = connection.prepareCall(noParamSql);
    cs1.registerOutParameter(1, Types.VARCHAR); -> 返回值是出参
    cs1.execute();
    String noParamVarchar = cs1.getString(1);

    cs2 = connection.prepareCall(haveParamSql);
    cs2.registerOutParameter(1, Types.VARCHAR); -> 返回值是出参
    cs2.setInt(2, 10); -> id是入参
    cs2.registerOutParameter(3, Types.VARCHAR); -> name是出参
    cs2.execute();
    String haveParamVarchar = cs1.getString(1);
    String haveParamName = cs1.getString(3);
} finally {
    if(rs != null) rs.close();
    if(ps != null) ps.close();
    if(connection != null) connection.close();
}

SQL 执行计划

explain plan for select * from system_user where id = 1; -> 生成执行计划
select * from table(dbms_xplan.display); -> 查询执行计划
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容