初識(shí)分庫(kù)分表框架DBSPLIT

點(diǎn)擊Dbsplit進(jìn)入我們的項(xiàng)目主頁(yè)舞终,獲得更多信息和內(nèi)容。

分庫(kù)分表示意圖

什么是dbsplit?

Dbsplit擴(kuò)展了Spring的JdbcTemplate, 在JdbcTemplate上增加了分庫(kù)分表上陕,讀寫分離和失效轉(zhuǎn)移等功能硼莽,并與Spring JDBC保持相同的風(fēng)格懂鸵,簡(jiǎn)單實(shí)用套像,避免外部依賴周崭,不需要類似cobar的代理服務(wù)器,堪稱可伸縮的Spring JdbcTemplate磨取。

一方面凫岖,它對(duì)于單庫(kù)單表擴(kuò)展了JdbcTemplate模板, 使其成為一個(gè)簡(jiǎn)單的ORM框架,可以直接對(duì)領(lǐng)域?qū)ο竽P瓦M(jìn)行持久和搜索操作,并且實(shí)現(xiàn)了讀寫分離。

另一方面峭弟,對(duì)于分庫(kù)分表它與JdbcTemplate保持同樣的風(fēng)格,不但提供了一個(gè)簡(jiǎn)單的ORM框架,可以直接對(duì)領(lǐng)域?qū)ο竽P瓦M(jìn)行持久和搜索操作,還是先了數(shù)據(jù)分片和讀寫分離等高級(jí)功能朝巫。

另外,擴(kuò)展的Dbsplit保持與原有JdbcTemplate完全兼容揪荣,對(duì)于特殊需求,完全可以回溯到原有JdbcTemplate提供的功能请祖,即使用JDBC的方式來(lái)解決,這里面體現(xiàn)了通用和專用原則,通用原則解決80%的事情席纽,而專用原則解決剩余的20%的事情诈豌。

此項(xiàng)目也提供了一個(gè)方便的腳本彤蔽,可以一次性的建立多庫(kù)多表油够。

誰(shuí)應(yīng)該關(guān)注dbsplit揩悄?

特別適合想知道互聯(lián)網(wǎng)的分庫(kù)分表是怎么實(shí)現(xiàn)的,也適合那些想把分庫(kù)分表框架開箱即用的項(xiàng)目,更適合想學(xué)習(xí)互聯(lián)網(wǎng)的小伙伴們。

如果你在尋找數(shù)據(jù)庫(kù)分庫(kù)分表的輕量級(jí)解決方案发乔,請(qǐng)參考Dbsplit的實(shí)現(xiàn)和應(yīng)用場(chǎng)景起愈,它是一個(gè)兼容Spring JDBC的并且支持分庫(kù)分表的輕量級(jí)的數(shù)據(jù)庫(kù)中間件官觅,使用起來(lái)簡(jiǎn)單方便笛辟,性能接近于直接使用JDBC捷凄,并且能夠無(wú)縫的與Spring相結(jié)合,又具有很好的可維護(hù)性。

怎么使用dbsplit?

我們已經(jīng)完整的實(shí)現(xiàn)了一個(gè)具有分庫(kù)分表功能的框架dbsplit,現(xiàn)在,讓我們提供一個(gè)示例演示在我們的應(yīng)用中怎么來(lái)使用這個(gè)框架,大家也可以參考dbsplit項(xiàng)目中dbsplit-core/src/main/test中的源代碼。

首先购城,假設(shè)我們應(yīng)用中有個(gè)表需要增刪改查,它的DDL腳本如下:

drop table if exists TEST_TABLE_$I;

create table TEST_TABLE_$I
(
    ID bigint not null,
    NAME varchar(128) not null,
    GENDER               smallint default 0, 
    LST_UPD_USER         varchar(128) default "SYSTEM",
    LST_UPD_TIME         timestamp default now(),
    primary key(id),
    unique key UK_NAME(NAME)
);

我們把這個(gè)DDL腳本保存到table.sql文件中,然后,我們需要準(zhǔn)備好一個(gè)Mysql的數(shù)據(jù)庫(kù)實(shí)例,實(shí)例端口為localhost:3307, 因?yàn)榄h(huán)境的限制,我們用著一個(gè)數(shù)據(jù)庫(kù)實(shí)例來(lái)模擬兩個(gè)數(shù)據(jù)庫(kù)實(shí)例,兩個(gè)數(shù)據(jù)庫(kù)實(shí)例使用同一個(gè)端口,我們?yōu)門EST_TABLE設(shè)計(jì)了2個(gè)數(shù)據(jù)庫(kù)實(shí)例瞳脓、每個(gè)實(shí)例2個(gè)數(shù)據(jù)庫(kù)哨啃、每個(gè)數(shù)據(jù)庫(kù)4個(gè)表审姓,共16個(gè)分片表。

我們使用腳本創(chuàng)建創(chuàng)建用于分片的多個(gè)數(shù)據(jù)庫(kù)和表,腳本代碼如下所示:

build-db-split.sh -i "localhost:3307,localhost:3307" -m test_db -n table.sql -x 2 -y 4 -a test_user -b test_password -c root -d youarebest -l localhost -t

這里骨宠,需要提供系統(tǒng)root用戶的用戶名和密碼。

然后相满,我們登錄Mysql的命令行客戶端诱篷,我們看到一共創(chuàng)建了4個(gè)數(shù)據(jù)庫(kù),前2個(gè)數(shù)據(jù)庫(kù)屬于數(shù)據(jù)庫(kù)實(shí)例1雳灵,后2個(gè)數(shù)據(jù)庫(kù)屬于數(shù)據(jù)庫(kù)實(shí)例2闸盔,每個(gè)數(shù)據(jù)庫(kù)有4個(gè)表悯辙。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
| test_db_0          |
| test_db_1          |
| test_db_2          |
| test_db_3          |
+--------------------+
6 rows in set (0.01 sec)

mysql> use test_db_0;
Database changed
mysql> show tables;
+---------------------+
| Tables_in_test_db_0 |
+---------------------+
| TEST_TABLE_0        |
| TEST_TABLE_1        |
| TEST_TABLE_2        |
| TEST_TABLE_3        |
+---------------------+
4 rows in set (0.00 sec)

因此,一共我們創(chuàng)建了16個(gè)分片表迎吵。

然后躲撰,我們定義對(duì)應(yīng)這個(gè)數(shù)據(jù)庫(kù)表的領(lǐng)域?qū)ο竽P停谶@個(gè)領(lǐng)域?qū)ο竽P椭谢鞣眩覀儾恍枰魏巫⒔饴5埃@是一個(gè)綠色的POJO。

public class TestTable {
    private long id;
    private String name;

    public enum Gender {
        MALE, FEMALE;

        public static Gender parse(int value) {
            for (Gender gender : Gender.values()) {
                if (value == gender.ordinal())
                    return gender;
            }
            return null;
        }
    };

    private Gender gender;
    private String lstUpdUser;
    private Date lstUpdTime;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public String getLstUpdUser() {
        return lstUpdUser;
    }

    public void setLstUpdUser(String lstUpdUser) {
        this.lstUpdUser = lstUpdUser;
    }

    public Date getLstUpdTime() {
        return lstUpdTime;
    }

    public void setLstUpdTime(Date lstUpdTime) {
        this.lstUpdTime = lstUpdTime;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

因?yàn)槲覀兊膽?yīng)用程序需要保存這個(gè)實(shí)體蔫巩,這就需要生成唯一的ID谆棱,發(fā)號(hào)器的設(shè)計(jì)和使用請(qǐng)參考第4章如何設(shè)計(jì)一款永不重復(fù)的高性能分布式發(fā)號(hào)器,這里我們需要配置一個(gè)發(fā)號(hào)器服務(wù)即可圆仔,代碼如下所示垃瞧。

    <bean id="idService" class="com.robert.vesta.service.factory.IdServiceFactoryBean"
        init-method="init">
        <property name="providerType" value="PROPERTY" />
        
        <property name="machineId" value="${vesta.machine}" />
    </bean>

接下來(lái),我們?cè)赟pring環(huán)境中定義這個(gè)表的分片信息坪郭,這包括數(shù)據(jù)庫(kù)名稱个从、表名稱、數(shù)據(jù)庫(kù)分片數(shù)歪沃、表的分片數(shù)嗦锐,以及讀寫分離等信息,本例中我們制定數(shù)據(jù)庫(kù)前綴為test_db沪曙,數(shù)據(jù)庫(kù)表名為TEST_TABLE奕污,每個(gè)實(shí)例2個(gè)數(shù)據(jù)庫(kù),每個(gè)數(shù)據(jù)庫(kù)4張表液走,分片采用采用水平下標(biāo)策略菊值,并且打開讀寫分離外驱。

    <bean name="splitTable" class="com.robert.dbsplit.core.SplitTable"
        init-method="init">

        <property name="dbNamePrefix" value="test_db" />
        <property name="tableNamePrefix" value="TEST_TABLE" />

        <property name="dbNum" value="2" />
        <property name="tableNum" value="4" />

        <property name="splitStrategyType" value="HORIZONTAL" />
        <property name="splitNodes">
            <list>
                <ref bean="splitNode1" />
                <ref bean="splitNode2" />
            </list>
        </property>

        <property name="readWriteSeparate" value="true" />

    </bean>

我們看到,這個(gè)splitTable引用了兩個(gè)數(shù)據(jù)庫(kù)實(shí)例節(jié)點(diǎn):splitNode1和splitNode2腻窒,他們的聲明如下:

    <bean name="splitNode1" class="com.robert.dbsplit.core.SplitNode">
        <property name="masterTemplate" ref="masterTemplate0" />
        <property name="slaveTemplates">
            <list>
                <ref bean="slaveTemplate00"></ref>
            </list>
        </property>
    </bean>

    <bean name="splitNode2" class="com.robert.dbsplit.core.SplitNode">
        <property name="masterTemplate" ref="masterTemplate1" />
        <property name="slaveTemplates">
            <list>
                <ref bean="slaveTemplate10"></ref>
            </list>
        </property>
    </bean>

每個(gè)數(shù)據(jù)庫(kù)實(shí)例節(jié)點(diǎn)都引用了一個(gè)數(shù)據(jù)庫(kù)主模板以及若干個(gè)數(shù)據(jù)庫(kù)從模板昵宇,這是用來(lái)實(shí)現(xiàn)讀寫分離的,因?yàn)槲覀兇蜷_了讀寫分離設(shè)置儿子,所有的讀操作將由dbsplit路由到數(shù)據(jù)庫(kù)的從模板上瓦哎,數(shù)據(jù)庫(kù)的主從模板的聲明引用到我們生命的數(shù)據(jù)庫(kù),因?yàn)槲覀兪窃诒镜刈鰷y(cè)試柔逼,這些數(shù)據(jù)源都指向了本地的Mysql數(shù)據(jù)庫(kù)localhost:3307蒋譬。

    <bean id="masterTemplate0" class="org.springframework.jdbc.core.JdbcTemplate"
        abstract="false" lazy-init="false" autowire="default"
        dependency-check="default">
        <property name="dataSource">
            <ref bean="masterDatasource0" />
        </property>
    </bean>

    <bean id="slaveTemplate00" class="org.springframework.jdbc.core.JdbcTemplate"
        abstract="false" lazy-init="false" autowire="default"
        dependency-check="default">
        <property name="dataSource">
            <ref bean="slaveDatasource00" />
        </property>
    </bean>

到現(xiàn)在為止,我們定義好了表的分片信息愉适,把我們把這個(gè)表加入到SplitTablesHolder的Bean中犯助,代碼如下所示:

    <bean name="splitTablesHolder" class="com.robert.dbsplit.core.SplitTablesHolder"
        init-method="init">
        <property name="splitTables">
            <list>
                <ref bean="splitTable" />
            </list>
        </property>
    </bean>

接下來(lái),我們就需要聲明我們的SimpleSplitJdbcTemplate的Bean维咸,它需要引用SplitTablesHolder的Bean剂买,以及配置讀寫分離的策略,配置代碼如下所示癌蓖,

    <bean name="simpleSplitJdbcTemplate" class="com.robert.dbsplit.core.SimpleSplitJdbcTemplate">
        <property name="splitTablesHolder" ref="splitTablesHolder" />
        <property name="readWriteSeparate" value="${dbsplit.readWriteSeparate}" />
    </bean>

我們有了SimpleSplitJdbcTemplate的Bean瞬哼,我們就可以把它導(dǎo)出給我們的服務(wù)層來(lái)使用了。這里我們通過(guò)一個(gè)測(cè)試用例來(lái)演示租副,在測(cè)試用例中初始化剛才我們配置的Spring環(huán)境坐慰,從Spring環(huán)境中獲取SimpleSplitJdbcTemplate的Bean simpleSplitJdbcTemplate,然后用僧,示例里面的方法插入TEST_TABLE的記錄结胀,然后,再把這條記錄查詢出來(lái)责循,代碼如下所示把跨。

    public void testSimpleSplitJdbcTemplate() {
        SimpleSplitJdbcTemplate simpleSplitJdbcTemplate = (SimpleSplitJdbcTemplate) applicationContext
                .getBean("simpleSplitJdbcTemplate");
        IdService idService = (IdService) applicationContext
                .getBean("idService");

        // Make sure the id generated is not align multiple of 1000
        Random random = new Random(new Date().getTime());
        for (int i = 0; i < random.nextInt(16); i++)
            idService.genId();

        long id = idService.genId();
        System.out.println("id:" + id);

        TestTable testTable = new TestTable();
        testTable.setId(id);
        testTable.setName("Alice-" + id);
        testTable.setGender(Gender.MALE);
        testTable.setLstUpdTime(new Date());
        testTable.setLstUpdUser("SYSTEM");

        simpleSplitJdbcTemplate.insert(id, testTable);

        TestTable q = new TestTable();

        TestTable testTable1 = simpleSplitJdbcTemplate.get(id, id,
                TestTable.class);

        AssertJUnit.assertEquals(testTable.getId(), testTable1.getId());
        AssertJUnit.assertEquals(testTable.getName(), testTable1.getName());
        AssertJUnit.assertEquals(testTable.getGender(), testTable1.getGender());
        AssertJUnit.assertEquals(testTable.getLstUpdUser(),
                testTable1.getLstUpdUser());
        // mysql store second as least time unit but java stores miliseconds, so
        // round up the millisends from java time
        AssertJUnit.assertEquals(
                (testTable.getLstUpdTime().getTime() + 500) / 1000 * 1000,
                testTable1.getLstUpdTime().getTime());

        System.out.println("testTable1:" + testTable1);
    }

如何使用用于創(chuàng)建分庫(kù)分表的腳本?

這里介紹一個(gè)用于創(chuàng)建分庫(kù)分表的腳本沼死,這個(gè)腳本可以一次性的按照規(guī)則在多個(gè)mysql示例上創(chuàng)建多個(gè)數(shù)據(jù)庫(kù)和表着逐,以及在每一個(gè)數(shù)據(jù)庫(kù)實(shí)例上創(chuàng)建一個(gè)統(tǒng)一的用戶,并分配相應(yīng)的權(quán)限給此用戶意蛀。

1. 使用方法

Usage: $0 -i [INSTANCE_STR] -m [DB_PREFIX] -n [TABLE_SQL_FILE] -x [DB_SPLIT_NUM] -y [TABLE_SPLIT_NUM] -a [USER] -b [PASSWORD] -c [ROOT_USER] -d [ROOT_PASSWORD] -l [CONNECTION_HOST] -t 

Descriptions:
-i : instances string.
-m : db name.
-n : table file name.
-x : db number.
-y : table number.
-a : user name to be created.
-b : password for the user name to be created.
-c : root user.
-d : password for root user.
-l : for the connection host.
-t : debug sql output.

2. 使用示例

Example1: $0 -i "localhost:3306,localhost:3306" -m test_db -n table.sql -x 2 -y 2 -a test_user -b test_password -c root -d youarebest -l localhost -t
Example2: $0 -i "localhost:3306,localhost:3306" -m test_db -n table.sql -x 2 -y 2 -a test_user -b test_password -c root -d youarebest -l localhost

3. 源碼

#!/bin/bash

insts=localhost:3306,localhost:3306

db_prefix=test_db
table_sql_file=table.sql

db_num=2
table_num=2

user_name=test_user
password=test_password

root_user_name=root
root_password=cool

debug=FALSE

conn_host=localhost

build_db() {
  inst=$1
  inst_arr=(${inst//:/ })

  host=${inst_arr[0]}
  port=${inst_arr[1]}

  db=$2
  db_no=$3
  
  echo "info: building instance $inst db $db db no $db_no"

  for ((k=0;k<$table_num;k++)); do
    ((table_no=$table_num*$db_no+$k))

    echo "info: building instance $inst db $db db no $db_no table $table_no"    
    
    sql_command="sed 's/"'$index'"/$table_no/g' ./$table_sql_file | tr -t '\n' '\0'"
    sql_create_table=`eval "$sql_command"`
    
    if [[ $debug = 'TRUE' ]]; then
        echo "Create Table SQL: $sql_create_table"
    fi
    mysql -u$root_user_name -p$root_password -e "$sql_create_table" $db 2> /dev/null
     
  done  
}

build_inst() {
  inst=$1
  inst_arr=(${inst//:/ })

  host=${inst_arr[0]}
  port=${inst_arr[1]}

  inst_no=$2
  
  echo "info: building instance $inst no $inst_no"
  
  sql_delete_user="delete from mysql.user where user = '$user_name'; flush privileges"
  
  if [[ $debug = 'TRUE' ]]; then
    echo "Delete User SQL: $sql_delete_user"
  fi
  mysql -u$root_user_name -p$root_password -e "$sql_delete_user" 2> /dev/null
  
  mysql -u$root_user_name -p$root_password -e "create user '$user_name'@'$conn_host' identified by '$password'"
    
  for ((j=0;j<$db_num;j++)); do
    ((db_no=$db_num*$inst_no+$j)) 
    
    create_database_sql="drop database if exists ${db_prefix}_${db_no};create database ${db_prefix}_${db_no}"
    
    if [[ $debug = 'TRUE' ]]; then
      echo "Create Database SQL: $create_database_sql"
    fi    
    mysql -u$root_user_name -p$root_password -e "$create_database_sql" 2> /dev/null

    assign_rights_sql="grant all privileges on ${db_prefix}_${db_no}.* to '$user_name'@'$conn_host' identified by '$password';flush privileges"
    
    if [[ $debug = 'TRUE' ]]; then
      echo "Assign Rights SQL: $assign_rights_sql"
    fi    
    mysql -u$root_user_name -p$root_password -e "assign_rights_sql" 2> /dev/null    

    build_db $inst ${db_prefix}_${db_no} $db_no
  done   
}

main() {
    echo "properties: insts=$insts db_prefix=$db_prefix table_sql_file=$table_sql_file db_num=$db_num table_num=$table_num user_name=$user_name password=$password root_user_name=$root_user_name root_password=$root_password"

    insts_arr=(${insts//,/ })  
    insts_num=${#insts_arr[@]} 
    
    for ((i=0;i<$insts_num;i++)); do
      build_inst ${insts_arr[$i]} $i
    done
}

PrintUsage()
{
cat << EndOfUsageMessage

    Usage: $0 -i [INSTANCE_STR] -m [DB_PREFIX] -n [TABLE_SQL_FILE] -x [DB_SPLIT_NUM] -y [TABLE_SPLIT_NUM] -a [USER] -b [PASSWORD] -c [ROOT_USER] -d [ROOT_PASSWORD] -l [CONNECTION_HOST] -t 
    
    Descriptions:
    -i : instances string.
    -m : db name.
    -n : table file name.
    -x : db number.
    -y : table number.
    -a : user name to be created.
    -b : password for the user name to be created.
    -c : root user.
    -d : password for root user.
    -l : for the connection host.
    -t : debug sql output.
    
    Example1: $0 -i "localhost:3306,localhost:3306" -m test_db -n table.sql -x 2 -y 2 -a test_user -b test_password -c root -d youarebest -l localhost -t
    Example2: $0 -i "localhost:3306,localhost:3306" -m test_db -n table.sql -x 2 -y 2 -a test_user -b test_password -c root -d youarebest -l localhost
    
EndOfUsageMessage
}

InvalidCommandSyntaxExit()
{
        echo "Invalid command\n`PrintUsage`"
        exit;
}

if [ $# -eq 0 ]
then
    echo "`PrintUsage`"
    exit 1
fi


while getopts "i:m:n:x:y:a:b:c:d:l:t" arg
do
        case $arg in
             i)
                insts=$OPTARG 
                ;;
             m)
                db_prefix=$OPTARG
                ;;
             n)
                table_sql_file=$OPTARG
                ;;
             x)
                db_num=$OPTARG
                ;;
             y)
                table_num=$OPTARG
                ;;
             a)
                user_name=$OPTARG
                ;;
             b)
                password=$OPTARG
                ;;
             c)
                root_user_name=$OPTARG
                ;;
             d)
                root_password=$OPTARG
                ;;
             l)
                conn_host=$OPTARG
                ;;
             t)
                debug=TRUE
                ;;
             ?) 
                echo "`InvalidCommandSyntaxExit`"
                exit 1
                ;;
        esac
done

這個(gè)腳本僅僅是一個(gè)示例耸别,計(jì)劃中,這個(gè)腳本需要支持三種分庫(kù)分表的策略县钥,數(shù)據(jù)庫(kù)和表下標(biāo)累積的策略秀姐,數(shù)據(jù)庫(kù)和表下標(biāo)歸零的策略與兩種混合策略, 當(dāng)前腳本只支持第一種。

我們需要注意若贮,這個(gè)建庫(kù)腳本不支持建立主從關(guān)系省有,但是可以建立主庫(kù)和從庫(kù)后再手工建立主從關(guān)系痒留。

請(qǐng)掃描下面二維碼加入我們。


云時(shí)代架構(gòu)公眾號(hào)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蠢沿,一起剝皮案震驚了整個(gè)濱河市伸头,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舷蟀,老刑警劉巖恤磷,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異野宜,居然都是意外死亡扫步,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門匈子,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)河胎,“玉大人,你說(shuō)我怎么就攤上這事虎敦∮卧溃” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵原茅,是天一觀的道長(zhǎng)赘艳。 經(jīng)常有香客問(wèn)我雾家,道長(zhǎng),這世上最難降的妖魔是什么寞埠? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任摩骨,我火速辦了婚禮通贞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恼五。我一直安慰自己昌罩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布灾馒。 她就那樣靜靜地躺著茎用,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睬罗。 梳的紋絲不亂的頭發(fā)上轨功,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音容达,去河邊找鬼古涧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛花盐,可吹牛的內(nèi)容都是我干的羡滑。 我是一名探鬼主播菇爪,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柒昏!你這毒婦竟也來(lái)了凳宙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昙楚,失蹤者是張志新(化名)和其女友劉穎近速,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堪旧,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡削葱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淳梦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片析砸。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爆袍,靈堂內(nèi)的尸體忽然破棺而出首繁,到底是詐尸還是另有隱情,我是刑警寧澤陨囊,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布弦疮,位于F島的核電站,受9級(jí)特大地震影響蜘醋,放射性物質(zhì)發(fā)生泄漏胁塞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一压语、第九天 我趴在偏房一處隱蔽的房頂上張望啸罢。 院中可真熱鬧,春花似錦胎食、人聲如沸扰才。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)衩匣。三九已至,卻和暖如春粥航,著一層夾襖步出監(jiān)牢的瞬間舵揭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工躁锡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留午绳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓映之,卻偏偏與公主長(zhǎng)得像拦焚,于是被迫代替她去往敵國(guó)和親蜡坊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理赎败,服務(wù)發(fā)現(xiàn)秕衙,斷路器,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評(píng)論 6 342
  • 上帝之火閱讀 137評(píng)論 0 4
  • 高數(shù)及線代 個(gè)人技能 社會(huì)研究方法
    Whale__fall閱讀 125評(píng)論 0 0
  • 支原體是一種微生物原核細(xì)胞,細(xì)菌和病毒之間的體積,對(duì)人類致病性支原體有3種,其中支原體是人類泌尿生殖道常見(jiàn)的病原體...
    匡湊盯匡閱讀 289評(píng)論 0 0