spring 事务介绍与源码分析

事务
  • 事务定义
事务(Transaction)是数据库区别于文件系统的重要特性之一。MySQL 事务主要用于处理操作量大,复杂度高的数据。
1. 在 MySQL 数据库中只有 Innodb 数据库引擎的数据库或表才支持事务;
2. 事务是一个最小的不可再分的工作单元,可以用来保持数据库的完整性,保证成批的 DML(insert, update, delete) 语句, 要么全执行要么全不执行
  • 事务的ACID特征

    • 原子性
    一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
    
    • 一致性
    在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
    
    • 隔离性
    数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
    
    • 持久性
    事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
    
  • 事务的隔离级别

    查看事务级别:
    当前会话: select @@tx_isolation;
    全局: select @@global.tx_isolation;
    
    设置事务隔离级别:
    READ UNCOMMITTED
    READ COMMITTED
    REPEATABLE READ
    SERIALIZABLE
    
    当前会话: set session transaction isolatin level repeatable read;
    全局: set global transaction isolation level repeatable read;
    
    • 读未提交(Read uncommitted)
    1. 事务A未提交的数据,事务B可以读取到
    2. 该隔离级别会引起 “脏读”
    
    • 读提交 (Read committed)
    1. 事务A提交的数据,事务B可以读取到
    2. 该隔离级别会导致 “不可重复读”
    3. Oracle 默认的隔离级别
    
    • 可重复读(repeatable read)
    1. 事务A提交的数据,事务B读取不到
    2. 该隔离级别会导致 “幻读”,“幻读” 是针对 insert 操作来说的
    3. Mysql 默认的隔离级别
    
    事务A 操作 事务B 操作
    --- begin; --- ---
    --- select * from table where id = 3; 查询结果为空 --- begin;
    --- --- --- insert into table (id, value) values (3, 5);
    --- --- --- commit;
    --- insert into table (id, value) values (3, 5); 插入语句会出现异常 --- ---
    • 串行化(Serializable)
    1. 事务A和事务B,事务A在操作数据库时,事务B只能排队等待
    
  • 事务隔离的实现原理

spring事务
  • 简单应用实例
    • 编程式事务
      • TransactionTemplate

        // 使用模板方法设计模式对原始事务管理方式进行了封装。
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                update(1, "zhangsan-tx");
                insert(2, "lisi-tx", "345", "comment11");
            }
        });
        
      • TransactionManager

        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        try {
            update(1, "zhangsan-tx");
            insert(2, "lisi-tx", "345", "comment11");
            transactionManager.commit(transactionStatus);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            transactionManager.rollback(transactionStatus);
        }
        
        • TransactionManager
          spring本身不支持底层的事务实现,只是负责包装底层事务,应用底层支持什么样的事务策略,spring就支持什么样的事务策略,例如:
          1. JDBC事务:DataSourceTransactionManager


            images
          2. Hibernate事务:HibernateTransactionManager

          3. JPA事务:JpaTransactionManager

          4. Java原生API事务:JtaTransactionManager,分布式事务处理

        - TransactionStatus:事务具体运行状态
            ![images](https://upload-images.jianshu.io/upload_images/8024044-8972551d870e7572?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


        - TransactionDefinition:事务定义信息(隔离,传播,超时,只读)
            ![images](https://upload-images.jianshu.io/upload_images/8024044-dfc40fe836faaa82?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

+ 声明式事务
    - TransactionProxyFactoryBean
        为每个需要事务支持的 Bean 创建代理类
        ```java
        @Bean(name = "daoProxy")
        public TransactionProxyFactoryBean daoTemplate(DeclareDaoService declareDaoService) {
            TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
            transactionProxyFactoryBean.setTransactionManager(transactionManager());
            transactionProxyFactoryBean.setTarget(declareDaoService);
            Properties properties = new Properties();
            properties.setProperty("*", "PROPAGATION_REQUIRED");
            transactionProxyFactoryBean.setTransactionAttributes(properties);
            return transactionProxyFactoryBean;
        }
        ```

    - TransactionInterceptor
        ```java
        @Bean("transactionInterceptor")
        public TransactionInterceptor transactionInterceptor() {
            TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
            transactionInterceptor.setTransactionManager(transactionManager());
            Properties properties = new Properties();
            properties.setProperty("*", "PROPAGATION_REQUIRED");
            transactionInterceptor.setTransactionAttributes(properties);
            return transactionInterceptor;
        }

        @Bean
        public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){
            BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
            beanNameAutoProxyCreator.setBeanNames("*Service");
            beanNameAutoProxyCreator.setInterceptorNames("transactionInterceptor");
            return beanNameAutoProxyCreator;
        }
        ```

    - xml 配置文件 tx:advice 
        ```xml
        <!-- 定义事务管理器(声明式的事务) -->  
        <bean id="transactionManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>

        <!-- 
            通过对源码的分析 tx 标签的解析流程:
            XmlBeanDefinitionReader
                DefaultBeanDefinitionDocumentReader
                    DefaultNamespaceHandlerResolver(META-INF/spring.handlers)
                        TxNamespaceHandler
                            TxAdviceBeanDefinitionParser
                            AnnotationDrivenBeanDefinitionParser
                            JtaTransactionManagerBeanDefinitionParser
            TxAdviceBeanDefinitionParser -> 最终注册的 BeanDefinition 为 TransactionInterceptor              
        -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="*" propagation="REQUIRED" />
            </tx:attributes>
        </tx:advice>
        
        <aop:config>
            <aop:pointcut id="interceptorPointCuts"
                expression="execution(* *..*(..))" />
            <aop:advisor advice-ref="txAdvice"
                pointcut-ref="interceptorPointCuts" />        
        </aop:config> 
        ```

    - 注解的方式
        ```java
        @EnableTransactionManagement
        public class TxConfig {
        }

        @Service
        @Transactional
        public class DeclareCglibDaoService {
        }

        ```
  • spring事务的两种实现方式

    • 基于java动态代码的方式

    • cgLib的方式

  • 源码分析

    • 声明式事务基于 XML 配置的实现方式

      <!-- 
          通过对源码的分析 tx 标签的解析流程:
          XmlBeanDefinitionReader
              DefaultBeanDefinitionDocumentReader
                  DefaultNamespaceHandlerResolver(META-INF/spring.handlers)
                      TxNamespaceHandler
                          TxAdviceBeanDefinitionParser
                          AnnotationDrivenBeanDefinitionParser
                          JtaTransactionManagerBeanDefinitionParser
          TxAdviceBeanDefinitionParser -> 最终注册的 BeanDefinition 为 TransactionInterceptor
      
          aop:config 标签解析
              1. 生成一个后置处理器 AspectJAwareAdvisorAutoProxyCreator
              2. 解析 advisor 标签: 生成 DefaultBeanFactoryPointcutAdvisor        
      -->
      
      1. TxAdviceBeanDefinitionParser
        TxAdviceBeanDefinitionParser 最终会生成 TransactionInterceptor 的 BeanDefinition
      class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
          
          // ...
          @Override
          protected Class<?> getBeanClass(Element element) {
              return TransactionInterceptor.class;
          }
      
          // 根据 tx:attributes 子标签创建 TransactionAttributeSource 事务属性解析器
          protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
              // 1. 解析 transactionManager 属性
              builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
              // 2. 获取 attributes 子标签
              List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
              if (txAttributes.size() > 1) {
                  parserContext.getReaderContext().error(
                          "Element <attributes> is allowed at most once inside element <advice>", element);
              }
              else if (txAttributes.size() == 1) {
                  // Using attributes source.
                  Element attributeSourceElement = txAttributes.get(0);
                  // 3. 解析 attribute 子标签,注册属性解析器 NameMatchTransactionAttributeSource
                  RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
                  builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
              }
              else {
                  // Assume annotations source.
                  // 4. 注入 @Transaction 属性解析器 AnnotationTransactionAttributeSource
                  builder.addPropertyValue("transactionAttributeSource",
                          new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
              }
          }
          // ...
      }    
      
      1. TransactionInterceptor


        images

        TransactionInterceptor 实现了 MethodInterceptor 接口重写了 invoke 方法,根据 Spring AOP 的源码分析可知,MethodInterceptor 实现了 Advice 接口最终会同 pointcut 一起生成一个 Advisor 在动态代理中用于方法的增强。

      public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
          // ...
          @Override
          @Nullable
          public Object invoke(MethodInvocation invocation) throws Throwable {
              // Work out the target class: may be {@code null}.
              // The TransactionAttributeSource should be passed the target class
              // as well as the method, which may be from an interface.
              Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
      
              // Adapt to TransactionAspectSupport's invokeWithinTransaction...
              return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
          }
          // ...
          
          protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
          final InvocationCallback invocation) throws Throwable {
      
              // If the transaction attribute is null, the method is non-transactional.
              // 1. 获取事务属性解析器
              TransactionAttributeSource tas = getTransactionAttributeSource();
              final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
              // 2. 决定事务管理器
              final PlatformTransactionManager tm = determineTransactionManager(txAttr);
              // 3. 确定方法连接点的唯一标识
              final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
      
              if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
                  // Standard transaction demarcation with getTransaction and commit/rollback calls.
                  // 2. 根据情况决定创建事物
                  TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
                  Object retVal = null;
                  try {
                      // This is an around advice: Invoke the next interceptor in the chain.
                      // This will normally result in a target object being invoked.
                      // 3. 调用目标方法和拦截器链
                      retVal = invocation.proceedWithInvocation();
                  }
                  catch (Throwable ex) {
                      // target invocation exception
                      // 4. 异常回滚
                      completeTransactionAfterThrowing(txInfo, ex);
                      throw ex;
                  }
                  finally {
                      // 5. 保证清理工作
                      cleanupTransactionInfo(txInfo);
                  }
                  // 6. 事物提交操作
                  commitTransactionAfterReturning(txInfo);
                  return retVal;
              }
      
              else {
                  final ThrowableHolder throwableHolder = new ThrowableHolder();
      
                  // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
                  try {
                      Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
                          TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                          try {
                              return invocation.proceedWithInvocation();
                          }
                          catch (Throwable ex) {
                              if (txAttr.rollbackOn(ex)) {
                                  // A RuntimeException: will lead to a rollback.
                                  if (ex instanceof RuntimeException) {
                                      throw (RuntimeException) ex;
                                  }
                                  else {
                                      throw new ThrowableHolderException(ex);
                                  }
                              }
                              else {
                                  // A normal return value: will lead to a commit.
                                  throwableHolder.throwable = ex;
                                  return null;
                              }
                          }
                          finally {
                              cleanupTransactionInfo(txInfo);
                          }
                      });
      
                      // Check result state: It might indicate a Throwable to rethrow.
                      if (throwableHolder.throwable != null) {
                          throw throwableHolder.throwable;
                      }
                      return result;
                  }
                  catch (ThrowableHolderException ex) {
                      throw ex.getCause();
                  }
                  catch (TransactionSystemException ex2) {
                      if (throwableHolder.throwable != null) {
                          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                          ex2.initApplicationException(throwableHolder.throwable);
                      }
                      throw ex2;
                  }
                  catch (Throwable ex2) {
                      if (throwableHolder.throwable != null) {
                          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                      }
                      throw ex2;
                  }
              }
          }
      }
      
    • 声明式事务基于注解的实现方式

      1. EnableTransactionManagerment
        • 引入 TransactionManagementConfigurationSelector
        @Import(TransactionManagementConfigurationSelector.class)
        public @interface EnableTransactionManagement {
        
            boolean proxyTargetClass() default false;
        
            AdviceMode mode() default AdviceMode.PROXY;
        
            int order() default Ordered.LOWEST_PRECEDENCE;
        
        }
        
        • TransactionManagementConfigurationSelector
          默认加载两个类:AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration
        public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
            @Override
            protected String[] selectImports(AdviceMode adviceMode) {
                switch (adviceMode) {
                    case PROXY:
                        // 默认加载两个类:AutoProxyRegistrar 和  ProxyTransactionManagementConfiguration
                        return new String[] {AutoProxyRegistrar.class.getName(),
                                ProxyTransactionManagementConfiguration.class.getName()};
                    case ASPECTJ:
                        return new String[] {determineTransactionAspectClass()};
                    default:
                        return null;
                }
            }
        
            private String determineTransactionAspectClass() {
                return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
                        TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
                        TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
            }
        
        }
        
        • AutoProxyRegistrar
          默认注册 InfrastructureAdvisorAutoProxyCreator
        public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        
            private final Log logger = LogFactory.getLog(getClass());
            @Override
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                boolean candidateFound = false;
                Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
                for (String annType : annTypes) {
                    AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
                    if (candidate == null) {
                        continue;
                    }
                    Object mode = candidate.get("mode");
                    Object proxyTargetClass = candidate.get("proxyTargetClass");
                    if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                            Boolean.class == proxyTargetClass.getClass()) {
                        candidateFound = true;
                        if (mode == AdviceMode.PROXY) {
                            // 默认加载 InfrastructureAdvisorAutoProxyCreator 类
                            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                            if ((Boolean) proxyTargetClass) {
                                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                                return;
                            }
                        }
                    }
                }
                if (!candidateFound && logger.isInfoEnabled()) {
                    String name = getClass().getSimpleName();
                    logger.info(String.format("%s was imported but no annotations were found " +
                            "having both 'mode' and 'proxyTargetClass' attributes of type " +
                            "AdviceMode and boolean respectively. This means that auto proxy " +
                            "creator registration and configuration may not have occurred as " +
                            "intended, and components may not be proxied as expected. Check to " +
                            "ensure that %s has been @Import'ed on the same class where these " +
                            "annotations are declared; otherwise remove the import of %s " +
                            "altogether.", name, name, name));
                }
            }
        
        }
        
        • AbstractTransactionManagementConfiguration
          1. //注册事务增强器BeanFactoryTransactionAttributeSourceAdvisor
          2. //注册事务属性解析器 AnnotationTransactionAttributeSource,解析注解中的各种属性,比如propagation、isolation、timeout等
          3. //注册了TransactionInterceptor事务拦截器:保存了事务属性信息、事务管理器
        @Configuration(proxyBeanMethods = false)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
            // 1. 注册事务增强器BeanFactoryTransactionAttributeSourceAdvisor
            @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
            @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
            public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
                    TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
        
                BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
                advisor.setTransactionAttributeSource(transactionAttributeSource);
                advisor.setAdvice(transactionInterceptor);
                if (this.enableTx != null) {
                    advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
                }
                return advisor;
            }
        
            // 2. 注册事务属性解析器,解析注解中的各种属性,比如propagation、isolation、timeout等
            @Bean
            @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
            public TransactionAttributeSource transactionAttributeSource() {
                return new AnnotationTransactionAttributeSource();
            }
        
            // 3. 注册了TransactionInterceptor事务拦截器:保存了事务属性信息、事务管理器
            @Bean
            @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
            public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
                TransactionInterceptor interceptor = new TransactionInterceptor();
                interceptor.setTransactionAttributeSource(transactionAttributeSource);
                if (this.txManager != null) {
                    interceptor.setTransactionManager(this.txManager);
                }
                return interceptor;
            }
        
        }
        
        • AnnotationTransactionAttributeSource 事务注解解析器
        public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
                implements Serializable {
        
            public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
                this.publicMethodsOnly = publicMethodsOnly;
                if (jta12Present || ejb3Present) {
                    this.annotationParsers = new LinkedHashSet<>(4);
                    // 创建 Transaction 注解解析
                    this.annotationParsers.add(new SpringTransactionAnnotationParser());
                    if (jta12Present) {
                        this.annotationParsers.add(new JtaTransactionAnnotationParser());
                    }
                    if (ejb3Present) {
                        this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
                    }
                }
                else {
                    this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
                }
            }
        }
        
        • SpringTransactionAnnotationParser, @Transaction 注解解析器
        public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
        
            @Override
            public boolean isCandidateClass(Class<?> targetClass) {
                return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
            }
        
            @Override
            @Nullable
            public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
                AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                        element, Transactional.class, false, false);
                if (attributes != null) {
                    return parseTransactionAnnotation(attributes);
                }
                else {
                    return null;
                }
            }
        
            public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
                return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
            }
        
            protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
                RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        
                Propagation propagation = attributes.getEnum("propagation");
                rbta.setPropagationBehavior(propagation.value());
                Isolation isolation = attributes.getEnum("isolation");
                rbta.setIsolationLevel(isolation.value());
                rbta.setTimeout(attributes.getNumber("timeout").intValue());
                rbta.setReadOnly(attributes.getBoolean("readOnly"));
                rbta.setQualifier(attributes.getString("value"));
        
                List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
                for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
                    rollbackRules.add(new RollbackRuleAttribute(rbRule));
                }
                for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
                    rollbackRules.add(new RollbackRuleAttribute(rbRule));
                }
                for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
                    rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
                }
                for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
                    rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
                }
                rbta.setRollbackRules(rollbackRules);
        
                return rbta;
            }
        
        }
        
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容