shardingsphere 4.x(一)简介及Sharding-JDBC使用

Apache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

关系型数据库当今依然占有巨大市场份额,是企业核心系统的基石,未来也难于撼动,我们更加注重在原有基础上提供增量,而非颠覆。

Sharding-JDBC

定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。

ShardingSphere-JDBC 主要做两个功能:

  • 数据分片
  • 读写分离

整合Spring Boot

项目采用Spring Boot + MybatisPlus + Sharding-JDBC +Druid 连接池

依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

水平拆分

  1. 创建数据库 test_jdbc
  2. 在数据库创建两张表 test_standard_1,test_standard_2
  3. 约定规则:test_standard_2存储ID为奇数的数据,test_standard_1存入ID为偶数的数据
  4. 配置 Sharding-JDBC 分片策略,官网地址

注意一点,sharding-jdbc 版本不一样,配置也是有很大区别的,我这里是 4.0.0-RC1,大家要看 4.0的文档

建表语句
CREATE TABLE `test_standard_1` (
  `id` bigint NOT NULL,
  `name` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

application.properties配置

我见有的人说不支持 yml 格式,所以注意下

# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.81.104:3306/test_jdbc?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021


# 指定 standard 表分布情况,配置表在哪个数据源(数据库)里面,表名称都是什么,即 m1.standard_1 m1.standard_2
spring.shardingsphere.sharding.tables.test_standard.actual-data-nodes=m1.test_standard_$->{1..2}

# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.test_standard.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.test_standard.key-generator.type=SNOWFLAKE

# 指定分片策略 约定ID值 奇数添加到standard_2 偶数添加到standard_1
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.sharding-column=id
# 会拿雪花ID % 服务数量 ,但是总会得到 0 | 1,所以会找 test_standard_0 或 test_standard_1,+1 解决这样的问题
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.algorithm-expression=test_standard_$->{id % 2 + 1}

# 打开SQL输出日志
spring.shardingsphere.props.sql.show=true

spring.main.allow-bean-definition-overriding=true
测试类

这里 就不写 TestStandardMapper 和 TestStandard 实体类了

@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public TestStandardMapper testStandardMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            TestStandard testStandard = new TestStandard();
            testStandard.setName("张三"+i);
            testStandardMapper.insert(testStandard);
        }
    }

    @Test
    void selectByID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 你的ID是什么类型这里就一定要是什么类型,否则会报错
        wrapper.eq("id",1469257890131025922L);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectByName() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 查询别的字段回去两个表都查
        wrapper.eq("name","张三3");
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectInID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会对所有ID值进行取余得到具体去哪个表查
        wrapper.in("id",1469263053449306114L,1469263055173165058L);
        List<TestStandard> testStandard = testStandardMapper.selectList(wrapper);
        System.out.println(testStandard);
    }
}

水平分库并水平分表

  1. 创建两个数据库 test_jdbc1,test_jdbc2
  2. 在这两个数据库都创建 test_standard_1,test_standard_2两张表
  3. 约定规则:
    3.1. user_id 为偶数则添加到 test_jdbc1 库中,为奇数添加到 test_jdbc2 库中
    3.2. id 为偶数添加到 test_standard_1 表,为奇数添加到 test_standard_2 表
表结构
CREATE TABLE `test_standard_1` (
  `id` BIGINT NOT NULL,
  `user_id` BIGINT DEFAULT NULL,
  `name` VARCHAR(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1,m2

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.81.104:3306/test_jdbc1?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://192.168.81.104:3306/test_jdbc2?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021


# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.test_standard.actual-data-nodes=m$->{1..2}.test_standard_$->{1..2}

# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.test_standard.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.test_standard.key-generator.type=SNOWFLAKE

# 指定表分片策略 约定ID值 奇数添加到standard_1 偶数添加到standard_2
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.sharding-column=id
# 会拿雪花ID % 服务数量 ,但是总会得到 0 | 1,所以会找 test_standard_0 或 test_standard_1
spring.shardingsphere.sharding.tables.test_standard.table-strategy.inline.algorithm-expression=test_standard_$->{id % 2 + 1}

# 指定数据库分片策略,根据user_id做判断,偶数添加到m1,奇数添加到m2,default-database-strategy=默认所有表都按这样的规则
#spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
#spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

# 对指定表做分库规则
spring.shardingsphere.sharding.tables.test_standard.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.test_standard.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}

# 打开SQL输出日志
spring.shardingsphere.props.sql.show=true

spring.main.allow-bean-definition-overriding=true
测试
@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public TestStandardMapper testStandardMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            TestStandard testStandard = new TestStandard();
            testStandard.setName("张三"+i);
            testStandard.setUserId(Math.round(Math.random()*100));
            testStandardMapper.insert(testStandard);
        }
    }

    @Test
    void selectByID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询两个数据源并直接命中到跟ID取余的表,找到数据
        wrapper.eq("id",1470229287665823746L);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectByUserID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询跟user_id取余的库,并把库中要找的表都查出来,找数据在哪里
        wrapper.eq("user_id",66);
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }


    @Test
    void selectByName() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会查询两个数据源,并且查询所有的表,找到张三3这个用户
        wrapper.eq("name","张三3");
        TestStandard testStandard = testStandardMapper.selectOne(wrapper);
        System.out.println(testStandard);
    }

    @Test
    void selectInID() {
        QueryWrapper<TestStandard> wrapper = new QueryWrapper<>();
        // 会对所有ID值进行取余得到具体去哪个表查
        wrapper.in("id",1469263053449306114L,1469263055173165058L);
        List<TestStandard> testStandard = testStandardMapper.selectList(wrapper);
        System.out.println(testStandard);
    }

}

垂直分库

  1. 创建两个不同的数据库 user_db,order_db
  2. 在user_db库里面创建 user_info,order_db 库里面创建order_info表

垂直分库一般适用于微服务,一个业务连一个库,我这里有点多数据源的意思。

配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1,m2

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://192.168.81.104:3306/order_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021

# 针对 user_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=m$->{1}.user_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.user_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.user_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.algorithm-expression=user_info

# 针对order_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=m$->{2}.order_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.order_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.algorithm-expression=order_info

# 打开SQL输出日志
spring.shardingsphere.props.sql.show=true

spring.main.allow-bean-definition-overriding=true
测试

注意,这里记得要给实体类上加 @Table 注明实体类与哪张表有关系,否则插入报错

@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public UserInfoMapper userInfoMapper;
    @Resource
    public OrderInfoMapper orderInfoMapper;

    @Test
    void insert() {
        for(int i=0;i<10;i++) {
            UserInfo userInfo = new UserInfo();
            userInfo.setName("用户"+i);
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setName("用户"+i);
            orderInfoMapper.insert(orderInfo);
            userInfoMapper.insert(userInfo);
        }
    }

}

全局表(公共表)

  1. 存储固定数据的表,表数据很少发生变化,查询时候经常进行关联
  2. 在每个数据库中创建出相同结构的公共表
  3. 公共表的数据要添加都添加,要删除都删除
  4. 在 user_db,order_db中创建公共表,public_info
配置
# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1,m2

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://192.168.81.104:3306/order_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=dev_fqr
spring.shardingsphere.datasource.m2.password=Dev@fqr2021

# 针对 user_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=m$->{1}.user_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.user_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.user_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user_info.table-strategy.inline.algorithm-expression=user_info

# 针对order_db 库的某些表进行特殊处理
# 指定 数据库的分布情况 以及 表的分布情况
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=m$->{2}.order_info
# 分布式序列策略配置
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.order_info.key-generator.type=SNOWFLAKE
# 指定表分片策略 约定ID值
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.algorithm-expression=order_info


# 配置公共表
spring.shardingsphere.sharding.broadcast-tables=public_info
# 指定 standard 这张表里面主键的生成策略
spring.shardingsphere.sharding.tables.public_info.key-generator.column=id
# 指定算法名称
spring.shardingsphere.sharding.tables.public_info.key-generator.type=SNOWFLAKE


# 打开SQL输出日志
spring.shardingsphere.props.sql.show=true

spring.main.allow-bean-definition-overriding=true
测试
@SpringBootTest
class ShardingJdbcApplicationTests {

    @Resource
    public PublicInfoMapper publicInfoMapper;

    @Test
    void insert() {
        // 会往不同数据源相同表插入数据
        for(int i=0;i<10;i++) {
            PublicInfo publicInfo = new PublicInfo();
            publicInfo.setName("公共数据"+i);
            publicInfo.setForeignKey((long)i);
            publicInfoMapper.insert(publicInfo);
        }
    }

    @Test
    void select() {
        QueryWrapper<PublicInfo> wrapper = new QueryWrapper<>();
        // 会随机从m1,m2 中读取数据
        for(int i=0;i<10;i++) {
            wrapper.eq("id", 1470262655996567553L);
            PublicInfo publicInfo = publicInfoMapper.selectOne(wrapper);
            System.out.println(publicInfo);
        }
    }
    
}

读写分离配置

Sharding-JDBC 会根据语义的不同,来区分主从的读写分离,如 update、insert 等走主库,select 走从库

# 配置 sharding-jdbc 分片策略
# 配置数据源,起一个别名,可以有多个数据源用 都好分割
spring.shardingsphere.datasource.names=m1,s1

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=dev_fqr
spring.shardingsphere.datasource.m1.password=Dev@fqr2021

# 配置数据源的驱动\连接池\账号密码等
spring.shardingsphere.datasource.s1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.s1.url=jdbc:mysql://192.168.81.104:3306/user_db?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.s1.username=dev_fqr
spring.shardingsphere.datasource.s1.password=Dev@fqr2021


# 主从主要配置,多个从可以以','分割,ds0 是一个逻辑库,统一主从主体信息
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m1
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s1

# 指定 表的分布情况
spring.shardingsphere.sharding.tables.user_info.actual-data-nodes=ds0.user_info


# 打开SQL输出日志
spring.shardingsphere.props.sql.show=true

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

推荐阅读更多精彩内容