分布式事務Seata(AT模式)整合Nacos

一、Seata服務端搭建

1、下載服務端

官網(wǎng)下載:https://github.com/seata/seata/releases
下載1.5.2版本

2帜慢、創(chuàng)建Seata數(shù)據(jù)庫

CREATE DATABASE  `ry-seata` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

3、創(chuàng)建Seata數(shù)據(jù)表

腳本在Seata版本解壓目錄/script/server/db下唯卖,目前支持mysql粱玲、oracle、postgresql拜轨;


seata庫表腳本.jpg

庫表生成效果:


Seata服務庫表效果.png

4抽减、創(chuàng)建Nacos配置

1)創(chuàng)建seata服務配置seataServer.properties;

Data ID:seataServer.properties
Group: SEATA_GROUP
NameSpace:seata
配置格式:properties
注:應用的Group分組名稱與Seata的分組名稱可以不一樣;
具體內(nèi)容:

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=192.168.2.93:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=kryo
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, DB, and redis configuration values are optional.
store.mode=db

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://192.168.2.93:3306/ry-seata?rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=60000
server.recovery.asynCommittingRetryPeriod=60000
server.recovery.rollbackingRetryPeriod=60000
server.recovery.timeoutRetryPeriod=60000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

2)創(chuàng)建事務路由規(guī)則配置service.vgroupMapping.default_tx_group

Data ID:service.vgroupMapping.default_tx_group
Group: SEATA_GROUP
NameSpace:seata
配置格式:TEXT
內(nèi)容:default

3)配置最終效果

Seata服務端配置.png

5橄碾、修改seata/conf/application.yml文件內(nèi)容:

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
#  extend:
#    logstash-appender:
#      destination: 127.0.0.1:4560
#    kafka-appender:
#      bootstrap-servers: 127.0.0.1:9092
#      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 192.168.10.164:8848
      namespace: seata  
      group: SEATA_GROUP
      username: nacos
      password: nacos
      file-extension: yml
      data-id: seataServer.properties

  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      application: seata-server  
      server-addr: 192.168.10.164:8848
      group: SEATA_GROUP
      namespace: seata
      cluster: default
      username: nacos
      password: nacos
      file-extension: yml
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

6卵沉、啟動Seata服務

windox環(huán)境颠锉,直接雙擊:seata/bin/seata-server.bat
linux環(huán)境:

sh seata-server.sh -p 8091 -h 192.168.10.164 -m db

注:務必加啟動參數(shù),特別是IP與端口
打開seata控制臺:

seata控制臺.png

二史汗、Seata客戶端搭建

1琼掠、客戶端添加seata依賴

 <!-- SpringBoot Seata -->
        <!--移除alibaba-seata自帶的seata-spring-boot-starter,因為自帶的版本太低 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加seata-spring-boot-starter依賴停撞,版本需要與服務端版本相對應瓷蛙,此版本使用1.5.2 -->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.5.2</version>
        </dependency>

2、客戶端添加配置文件

注:seata客戶端的命名空間與分組名稱可以與seata服務端的不一樣戈毒,但若客戶端有多個配置文件艰猬,那它們的命名空間與分組名稱是要一致的;

1)創(chuàng)建seata客戶端的Nacos配置文件

Data ID:seata-client-test.yml
Group: DMS_TEST_GROUP
NameSpace:test
配置格式:YAML
內(nèi)容:

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      serverAddr: 192.168.10.164:8848
      namespace: seata
      group: SEATA_GROUP
      username: nacos
      password: nacos
      dataId: "seataServer.properties"

  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      application: seata-server
      serverAddr: 192.168.10.164:8848
      namespace: seata
      group: SEATA_GROUP
      username: nacos
      password: nacos

2)創(chuàng)建seata客戶端的多數(shù)據(jù)源(druid)配置文件

Data ID:druid_dynamic_test.yml
Group: DMS_TEST_GROUP
NameSpace:test
配置格式:YAML
內(nèi)容:

spring:
  datasource:
    default-transaction-isolation: 2
    druid:
      aop-patterns: com.ruoyi.*,com.zlt.*
      stat-view-servlet: #登陸賬號密碼
        login-password: root
        login-username: root
        reset-enable: true
        enabled: true
        allow: 192.168.2.*,127.0.0.1,192.168.10.*
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: /*.js,/*.gif,/*.jpg,/*.bmp,/*.png,/*.css,/*.ico,/druid/*
      filter:
        wall:
          enabled: false
          config:
            multi-statement-allow: true
        stat:
          enabled: true
          log-slow-sql: true
          slow-sql-millis: 10000
          merge-sql: true
    #    type: com.alibaba.druid.pool.DruidDataSource
    #    driver-class-name: oracle.jdbc.driver.OracleDriver
    #    url: jdbc:oracle:thin:@192.168.2.101:1521/zlt
    #    username: rycloud
    #    password: rycloud
    dynamic:
      druid:
        # 下面為連接池的補充設置埋市,應用到上面所有數(shù)據(jù)源中
        initial-size: 5
        min-idle: 5
        maxActive: 20
        maxWait: 60000
        # 配置間隔多久才進行一次檢測冠桃,檢測需要關閉的空閑連接,單位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        # 配置獲取連接等待超時的時間
        minEvictableIdleTimeMillis: 300000
        # 配置一個連接在池中最小生存的時間道宅,單位是毫秒
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        maxPoolPreparedStatementPerConnectionSize: 20
        # 配置監(jiān)控統(tǒng)計攔截的filters食听,去掉后監(jiān)控界面sql無法統(tǒng)計,'wall'用于防火墻,防止sql注入
        #filters: stat,slf4j
        #connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000
      datasource:
        # 主庫數(shù)據(jù)源
        master:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: oracle.jdbc.driver.OracleDriver
          url: jdbc:oracle:thin:@192.168.2.101:1521/zlt
          username: ll_ems
          password: ll_ems
        # 審批數(shù)據(jù)源
        activiti:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: oracle.jdbc.driver.OracleDriver
          url: jdbc:oracle:thin:@192.168.2.101:1521/zlt
          username: ll_ems
          password: ll_ems
        # 消息數(shù)據(jù)源
        message:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: oracle.jdbc.driver.OracleDriver
          url: jdbc:oracle:thin:@192.168.2.101:1521/zlt
          username: rycloud
          password: rycloud
      seata: true
      # 開啟seata代理培己,開啟后默認每個數(shù)據(jù)源都代理碳蛋,如果某個不需要代理可單獨關閉

3)每個應用服務的yml文件胚泌,增補seata開啟信息

eg.
Data ID:dms-mt-biz-test.yml
Group: DMS_TEST_GROUP
NameSpace:test
配置格式:YAML
增補內(nèi)容:

# seata配置
seata:
  # 默認關閉省咨,如需啟用spring.datasource.dynami.seata需要同時開啟
  enabled: true
  # Seata 應用編號,默認為 ${spring.application.name}
  application-id: ${spring.application.name}
  # 關閉自動代理
  enableAutoDataSourceProxy: false

當然玷室,上述1零蓉、2、3的yml文件也可以合并為一個穷缤。若有細分的話敌蜂,應在服務的bootstrap.yml啟動文件中將上述共享配置納入
如:


Seata配置加載.png

4)每個應用服務都要創(chuàng)建UNDO_LOG表

MYSQL腳本:

CREATE TABLE 
    undo_log 
    ( 
        id        bigint NOT NULL AUTO_INCREMENT, 
        branch_id bigint NOT NULL, 
        xid       VARCHAR(100) NOT NULL, 
        context   VARCHAR(128) NOT NULL, 
        rollback_info LONGBLOB NOT NULL, 
        log_status   INT NOT NULL, 
        log_created  DATETIME NOT NULL, 
        log_modified DATETIME NOT NULL, 
        ext          VARCHAR(100), 
        PRIMARY KEY (id), 
        CONSTRAINT ux_undo_log UNIQUE (xid, branch_id) 
    ) 
    ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci;

ORACLE腳本:

CREATE TABLE 
    UNDO_LOG 
    ( 
        ID        NUMBER(19) NOT NULL, 
        BRANCH_ID NUMBER(19) NOT NULL, 
        XID       VARCHAR2(100) NOT NULL, 
        CONTEXT   VARCHAR2(128) NOT NULL, 
        ROLLBACK_INFO BLOB NOT NULL, 
        LOG_STATUS   NUMBER(10) NOT NULL, 
        LOG_CREATED  TIMESTAMP(0) NOT NULL, 
        LOG_MODIFIED TIMESTAMP(0) NOT NULL, 
        PRIMARY KEY (ID), 
        CONSTRAINT UX_UNDO_LOG UNIQUE (XID, BRANCH_ID) 
    );
COMMENT ON TABLE UNDO_LOG 
IS 
    'AT transaction mode undo table';

5)啟動應用服務

若在Seata服務端可以看到應用服務(客戶端)的注冊信息,則表示客戶端的配置是正常的津肛;


客戶端注冊信息.png

三章喉、使用Seata分布式事務

1、在@Service服務里使用GlobalTransactional全局事務身坐;

注意:一定要在Service服務里秸脱,不能在Controller,否則全局事務不會生效
參考代碼:

 /**
     * 提交審批
     * @param billVo 單據(jù)VO
     * @param variables 提交審批流變量
     * @param callBackFunc 提交后回調(diào)
     */
    @DS("master")
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void submitApply(T billVo, Map<String, Object> variables,
                            Function<List, Object> callBackFunc) throws TransactionException {
        //1.提交審批
        String applyUserId = variables.get(ActivitiConstants.CURRENT_LOGIN_USER_NAME) == null ? SecurityUtils.getUsername()
                : String.valueOf(variables.get(ActivitiConstants.CURRENT_LOGIN_USER_NAME));
        ActProcessInstance processInstance = actProcessService.submitApply(applyUserId,String.valueOf(billVo.getId()), variables);

        //2.提交后回調(diào)
        if (callBackFunc != null){
            if (processInstance == null || StringUtils.isBlank(processInstance.getProcessInstanceId())){
                //Fegin調(diào)用使用了Fallback降級或拋出的異常被全局處理
                //這種情況下屬于seata服務發(fā)現(xiàn)不了下游服務拋出的異常部蛇,導致事務不會觸發(fā)回滾,需手動回滾
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
                throw new CustomException("提交審批失斕健:審批流實例未能正常返回!");
            }
            List<Object> paramsList = new ArrayList<>();
            paramsList.add(billVo);
            paramsList.add(processInstance.getProcessInstanceId());
            callBackFunc.apply(paramsList);
        }
    }
import com.baomidou.dynamic.datasource.annotation.DS;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;

2涯鲁、分支事務Transactional巷查,使用REQUIRES_NEW

 /**
     * 事務傳播特性設置為 REQUIRES_NEW 開啟新的事務 重要S行颉!5呵搿旭寿!一定要使用REQUIRES_NEW
     */
    @DS("activiti")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void complete(String taskId, String instanceId, Map<String, Object> variables) {
         //審批動作
     }

3、調(diào)試注意事項

1)盡量不在要服務間設置斷點崇败,會引起超時许师;
2)啟動全局事務后,在控制臺就可以看到全局事務信息僚匆;
3)分支事務執(zhí)行后微渠,每個服務的業(yè)務操作在undo_log會自動記錄,但很快會回滾消失咧擂,所以有時不要以為沒有生成undo_log日志逞盆;

四、注意事項

1松申、若是Oracle版本云芦,建議引入ojdbc6驅(qū)動,減少出現(xiàn)莫名的問題

      <!-- Seata分布式事務需要的版本 -->
            <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc6</artifactId>
                <version>${oracle6.version}</version>
            </dependency>
<oracle6.version>12.1.0.1-atlassian-hosted</oracle6.version>

2贸桶、在事務過程中舅逸,不要自行攔截異常,否則seata會捕獲不到皇筛;

3琉历、若Fegin調(diào)用使用了Fallback降級或拋出的異常被全局處理;

這種情況下屬于seata服務發(fā)現(xiàn)不了下游服務拋出的異常水醋,導致事務不會觸發(fā)回滾
解決辦法:
通過 GlobalTransactionContext.reload(RootContext.getXID()).rollback() 進行手動回滾旗笔;

 if (processInstance == null || StringUtils.isBlank(processInstance.getProcessInstanceId())){
                //Fegin調(diào)用使用了Fallback降級或拋出的異常被全局處理
                //這種情況下屬于seata服務發(fā)現(xiàn)不了下游服務拋出的異常,導致事務不會觸發(fā)回滾,需手動回滾
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
                throw new CustomException("提交審批失斨糇佟:審批流實例未能正常返回蝇恶!");
            }

4、所有參與分布式事務的庫表惶桐,必須要有主鍵撮弧,且必須是唯一的主鍵,不能聯(lián)合主鍵姚糊,否則會出現(xiàn): get table meta error:Failed to fetch schema of 表名贿衍。

5、Seata不支持的庫表字段類型:NVarchar2

6叛拷、日志打印XID發(fā)現(xiàn)沒有值或不一樣

若是使用feign調(diào)用舌厨,則需要引入seata-spring-boot-starter

7、出現(xiàn):Response[ TransactionException[Could not register branch into global session xid = xxx.xxx.xx.xx:xx

原因:Seata的AT模型調(diào)用其他服務時是異步的忿薇。seata的全局事務超時時間設置太短了裙椭,導致注冊分支事務的時候躏哩,全局事務都已經(jīng)進入第二階段了。將配置文件中的事務超時等待設置長些即可:如圖(如果60秒不夠用可以在設置大些揉燃,但是對應的代碼中全局事務超時(@GlobalTransactional(timeoutMills = 默認60秒))也要設置大些)

全局事務超時設置.png

8扫尺、支持日期類型,使用kyro序列化

在seataServer.properties中炊汤,修改logSerialization

client.undo.dataValidation=true
client.undo.logSerialization=kryo
client.undo.onlyCareUpdateColumns=true

在應用服務的pom文件中正驻,引入kyro相關依賴

           <dependency>
                <groupId>com.esotericsoftware.kryo</groupId>
                <artifactId>kryo</artifactId>
                <version>${kryo.version}</version>
            </dependency>
            <dependency>
                <groupId>de.javakaffee</groupId>
                <artifactId>kryo-serializers</artifactId>
                <version>${kryo-serializers.version}</version>
            </dependency>
            <dependency>
                <groupId>com.esotericsoftware</groupId>
                <artifactId>kryo</artifactId>
                <version>${kryo-software.version}</version>
            </dependency>
        <kryo.version>2.24.0</kryo.version>
        <kryo-serializers.version>0.45</kryo-serializers.version>
        <kryo-software.version>4.0.2</kryo-software.version>
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市抢腐,隨后出現(xiàn)的幾起案子姑曙,更是在濱河造成了極大的恐慌,老刑警劉巖迈倍,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伤靠,死亡現(xiàn)場離奇詭異,居然都是意外死亡啼染,警方通過查閱死者的電腦和手機宴合,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迹鹅,“玉大人卦洽,你說我怎么就攤上這事⌒迸铮” “怎么了阀蒂?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長打肝。 經(jīng)常有香客問我脂新,道長挪捕,這世上最難降的妖魔是什么粗梭? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮级零,結(jié)果婚禮上断医,老公的妹妹穿的比我還像新娘。我一直安慰自己奏纪,他們只是感情好鉴嗤,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著序调,像睡著了一般醉锅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上发绢,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天硬耍,我揣著相機與錄音垄琐,去河邊找鬼。 笑死经柴,一個胖子當著我的面吹牛狸窘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坯认,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼翻擒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了牛哺?” 一聲冷哼從身側(cè)響起陋气,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎引润,沒想到半個月后恩伺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡椰拒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年晶渠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片燃观。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡褒脯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缆毁,到底是詐尸還是另有隱情番川,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布脊框,位于F島的核電站颁督,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浇雹。R本人自食惡果不足惜沉御,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昭灵。 院中可真熱鬧吠裆,春花似錦、人聲如沸烂完。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抠蚣。三九已至祝旷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怀跛。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工奇昙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敌完。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓储耐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滨溉。 傳聞我的和親對象是個殘疾皇子什湘,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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