Spring 事務(wù)管理簡(jiǎn)介

事務(wù)簡(jiǎn)介

所謂事務(wù)灶芝,指的是程序中可運(yùn)行的不可分割的最小單位合呐。在生活中事務(wù)也是隨處可見的啥辨。比方說你在Steam上剁手買了一款游戲,那么付款就是一個(gè)事務(wù)拴事,要么付款成功,游戲到手圣蝎;要么付款失敗,錢退回你賬戶牲证。不可能也絕不應(yīng)該出現(xiàn)花了錢游戲卻沒到的情況坦袍。所以捂齐,事務(wù)也應(yīng)該具有兩個(gè)操作:成功時(shí)候提交奠宜,或者失敗時(shí)候回滾压真。

許多框架也提供事務(wù)管理功能榴都。JDBC中嘴高,你可以關(guān)閉自動(dòng)提交,然后使用Connection.commit()Connection.rollback()執(zhí)行提交或回滾春瞬。在Hibernate中宽气,也有類似的功能萄涯。但是涝影,這些框架的事務(wù)管理有一個(gè)問題燃逻,就是它們雖然提供了事務(wù)功能伯襟,但是為了使用這些功能姆怪,你必須在每個(gè)需要事務(wù)的地方添加額外代碼片效,當(dāng)執(zhí)行正常時(shí)提交淀衣,出現(xiàn)異常時(shí)回滾膨桥。這樣一來只嚣,程序中就會(huì)出現(xiàn)大量重復(fù)的事務(wù)管理代碼(有過這種經(jīng)歷的人應(yīng)該能夠感同身受吧)册舞。

另外事務(wù)還分為本地事務(wù)和全局事務(wù)调鲸。JDBC事務(wù)、Hibernate事務(wù)都是本地事務(wù)即供,只關(guān)注特定資源的事務(wù)管理逗嫡。全局事務(wù)則用來控制多個(gè)數(shù)據(jù)庫驱证、消息隊(duì)列等等雷滚。Spring提供了統(tǒng)一的事務(wù)管理來操作全局事務(wù)和本地事務(wù),讓我們的代碼更加簡(jiǎn)潔商源。

Spring事務(wù)管理

Spring事務(wù)的核心接口是org.springframework.transaction.PlatformTransactionManager牡彻。

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(
            TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

提交和回滾方法我們已經(jīng)了解了庄吼。getTransaction方法會(huì)根據(jù)給定的事務(wù)定義总寻,返回一個(gè)事務(wù)狀態(tài)對(duì)象渐行。事務(wù)定義包含了事務(wù)的一些特征:是否是只讀的祟印,超時(shí)設(shè)置蕴忆、事務(wù)的隔離和傳播等套鹅。Spring實(shí)現(xiàn)了幾個(gè)PlatformTransactionManager,用于不同環(huán)境(JDBC沉衣、Hibernate豌习、JPA等等)下的事務(wù)管理肥隆。我們?cè)谑褂玫臅r(shí)候只要設(shè)置好相應(yīng)的PlatformTransactionManager即可栋艳。事務(wù)管理包括在Spring核心包中吸占,所以只要項(xiàng)目中添加了spring-core.jar矾屯,那么就可以使用Spring的事務(wù)管理功能了件蚕。如果需要和Hibernate等框架的集成排作,那么還需要spring-orm.jar妄痪。

聲明式事務(wù)管理

Spring支持聲明式和編程式兩種方式來控制事務(wù)管理拌夏。最流行的方式就是使用聲明式障簿。利用聲明式事務(wù)管理站故,我們可以設(shè)置遇到什么異常時(shí)候回滾事務(wù)西篓、在哪些方法上執(zhí)行事務(wù)岂津,而不用修改任何代碼吮成。如果已經(jīng)了解了Spring AOP的話粱甫,應(yīng)該可以猜得到茶宵,Spring聲明式事務(wù)管理需要AOP代理的支持乌庶。下面我們來用一個(gè)例子說明一下瞒大。

配置PlatformTransactionManager

下面我們使用JDBC來演示一下Spring事務(wù)管理糠赦。因此首先需要配置相應(yīng)的PlatformTransactionManager拙泽,在這里是DataSourceTransactionManager顾瞻,它需要相應(yīng)的數(shù)據(jù)源來初始化荷荤。

<!--定義事務(wù)管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!--定義數(shù)據(jù)源-->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
      destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="12345678"/>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg ref="dataSource"/>
</bean>

然后我們需要一個(gè)類來進(jìn)行事務(wù)管理蕴纳。首先我們定義一個(gè)接口古毛。

public interface UserService {
    void add(User user);

    User get(String username);
}

然后來實(shí)現(xiàn)這個(gè)接口嫂冻。在這里我用了Spring JDBC來進(jìn)行數(shù)據(jù)操作桨仿。throwException來模擬拋出異常的情況案狠。

public class JdbcUserService implements UserService {

    private JdbcTemplate template;
    private boolean throwException;

    @Autowired
    public void setTemplate(JdbcTemplate template) {
        this.template = template;
    }

    public void setThrowException(boolean throwException) {
        this.throwException = throwException;
    }


    @Override
    public void add(User user) {
        template.update("INSERT INTO user(name) VALUES(?)", user.getName());
        if (throwException) {
            throw new RuntimeException("拋出異常");
        }
    }

    @Override
    public User get(String username) {
        return template.queryForObject("SELECT id,name FROM user WHERE name=?", new UserRowMapper(), username);
    }
}

配置事務(wù)管理

然后我們需要配置一個(gè)切入點(diǎn)和通知伴嗡,指定哪些方法應(yīng)用什么樣的事務(wù)管理从铲,這一部分屬于AOP的部分名段,這里不再細(xì)述伸辟。我們需要<tx:advice>節(jié)點(diǎn)設(shè)置事務(wù)管理信夫,該節(jié)點(diǎn)需要設(shè)置標(biāo)識(shí)符和事務(wù)管理器静稻。<tx:attributes>節(jié)點(diǎn)中的配置表示振湾,以get開頭的方法是只讀的,其他方法不是只讀的树酪。這有助于Spring正確設(shè)置事務(wù)续语。

<tx:advice id="txAdvice"
           transaction-manager="dataSourceTransactionManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
<!--使用AOP設(shè)置事務(wù)管理-->
<aop:config>
    <aop:pointcut id="userService"
                  expression="execution(* yitian..transaction.JdbcUserService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="userService"/>
</aop:config>

回滾操作

默認(rèn)情況下绵载,Spring會(huì)在方法中拋出運(yùn)行時(shí)錯(cuò)誤時(shí)執(zhí)行回滾焚虱,如果方法中拋出受檢異常則不回滾鹃栽。我們可以向<tx:method/>節(jié)點(diǎn)添加rollback-for屬性來指定當(dāng)方法拋出什么異常時(shí)執(zhí)行回滾躯畴,這里的異撑畛可以是某一個(gè)具體的異常饮亏,也可以是一些異常的父類路幸。

<tx:attributes>
    <tx:method name="get*" read-only="true"/>
    <tx:method name="*" rollback-for="Exception"/>
</tx:attributes>

相應(yīng)的付翁,還有一個(gè)no-rollback-for屬性來配置在遇到某些異常下不執(zhí)行回滾操作百侧。

<tx:attributes>
    <tx:method name="get*" read-only="true"/>
    <tx:method name="*" no-rollback-for="IndexOutOfBoundsException"/>
</tx:attributes>

如果遇到了多個(gè)回滾規(guī)則佣渴,以最具體的那一個(gè)為準(zhǔn)观话。所以下面的配置频蛔,當(dāng)遇到InstrumentNotFoundException時(shí)不會(huì)回滾晦溪,當(dāng)遇到其他異常時(shí)則執(zhí)行回滾挣跋。

<tx:advice id="txAdvice">
    <tx:attributes>
    <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
    </tx:attributes>
</tx:advice>

事務(wù)傳播級(jí)別

上面簡(jiǎn)單使用了<tx:advice/>節(jié)點(diǎn)舟肉。下面我們來分析一下這個(gè)節(jié)點(diǎn)的配置路媚。默認(rèn)情況下,<tx:advice/>的配置如下:

  • 傳播設(shè)置為:REQUIRED
  • 隔離級(jí)別是:DEFAULT
  • 事務(wù)是可讀可寫的
  • 事務(wù)超時(shí)是底層事務(wù)系統(tǒng)的默認(rèn)超時(shí),如果底層不支持就沒有超時(shí)
  • 任何運(yùn)行時(shí)異常會(huì)觸發(fā)回滾裤园,任何受檢異常不觸發(fā)回滾拧揽。

首先來說明一下事務(wù)的傳播强法,這指的是外層事務(wù)和內(nèi)層事務(wù)之間的關(guān)系闰歪。常用的值有三個(gè):PROPAGATION_REQUIRED 蓖墅、PROPAGATION_REQUIRES_NEWPROPAGATION_NESTED教翩。

首先來說說PROPAGATION_REQUIRED饱亿。當(dāng)外層事務(wù)需要一個(gè)內(nèi)層事務(wù)的時(shí)候彪笼,會(huì)直接使用當(dāng)前的外層事務(wù)配猫。這樣一來多個(gè)方法可能會(huì)共享同一個(gè)事務(wù)泵肄。如果內(nèi)層事務(wù)出現(xiàn)回滾腐巢,那么外層事務(wù)會(huì)也會(huì)回滾。這種情況下內(nèi)層事務(wù)會(huì)拋出一個(gè)UnexpectedRollbackException異常诵盼,外層調(diào)用者需要捕獲該異常來判斷外層事務(wù)是否已回滾风宁。

PROPAGATION_REQUIRES_NEW會(huì)為每個(gè)事務(wù)創(chuàng)建完全獨(dú)立的事務(wù)作用域戒财,如果外層事務(wù)需要一個(gè)內(nèi)層事務(wù),內(nèi)層事務(wù)會(huì)先掛起外層事務(wù)幽崩,當(dāng)內(nèi)層事務(wù)執(zhí)行完畢之后會(huì)恢復(fù)外層事務(wù)慌申。這樣一來內(nèi)外層事務(wù)的提交和回滾完全是獨(dú)立的理郑,不會(huì)互相干擾柒爵。

PROPAGATION_NESTED使用帶有多個(gè)保存點(diǎn)的單個(gè)事務(wù)赚爵。這些保存點(diǎn)會(huì)映射到JDBC的保存點(diǎn)上棉胀。所以只能用于JDBC環(huán)境和DataSourceTransactionManager中。

事務(wù)的隔離級(jí)別冀膝,除了DEFAULT之外唁奢,剩下的幾種隔離級(jí)別和JDBC中的隔離級(jí)別一一對(duì)應(yīng)。詳細(xì)情況請(qǐng)查看JDBC的相關(guān)文檔畸写。

測(cè)試事務(wù)

前面都配置完成之后,我們就可以測(cè)試一下Spring的事務(wù)管理功能氓扛。下面使用了一個(gè)測(cè)試類來測(cè)試枯芬。設(shè)置userService.setThrowException(false)之后论笔,事務(wù)不會(huì)拋出異常狂魔,我們可以看到成功插入了用戶數(shù)據(jù)待错。當(dāng)設(shè)置userService.setThrowException(true),事務(wù)會(huì)拋出異常,我們發(fā)現(xiàn)這次沒有插入數(shù)據(jù)。

@ContextConfiguration(locations = {"classpath:transaction.xml"})
@RunWith(SpringRunner.class)
public class TransactionTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private JdbcUserService userService;

    @Before
    public void before() {
        jdbcTemplate.execute("CREATE TABLE user(id INT AUTO_INCREMENT PRIMARY KEY ,name VARCHAR(255))");
    }

    @After
    public void after() {
        jdbcTemplate.execute("DROP TABLE IF EXISTS user");
    }

    @Test
    public void testTransaction() {
        //事務(wù)成功
        userService.setThrowException(false);
        User user = new User();
        user.setName("yitian");
        userService.add(user);
        User u = userService.get(user.getName());
        assertEquals(user.getName(), u.getName());
        //事務(wù)失敗
        userService.setThrowException(true);
        user.setName("liu6");
        u = null;
        try {
            userService.add(user);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        try {
            //由于沒有記錄卸例,Spring JDBC會(huì)拋出異常
            //所以必須捕獲該異常
            u = userService.get(user.getName());
        } catch (EmptyResultDataAccessException e) {
            System.out.println(e.getMessage());
        }

        assertNull(u);

    }
}

注解配置

前面用的都是XML配置方式呜舒,還可以使用注解配置聲明式事務(wù)管理。這需要在配置文件中添加一行,這一行仍然需要指明使用的事務(wù)管理器啤咽。

<tx:annotation-driven transaction-manager="txManager"/>

如果你全部使用注解配置鳞青,那么在標(biāo)記了@Configuration的類上在添加@EnableTransactionManagement即可埃儿。需要注意這兩種方法都會(huì)在當(dāng)前ApplicationContext中尋找@Transactional Bean威鹿。

注解配置主要使用@Transactional注解,該注解可以放置到類、接口或者公有方法上。該注解還有一些屬性和XML配置相對(duì)應(yīng)。但是根據(jù)配置的不同,注解可能不會(huì)起作用。下面是Spring官方的兩段話羹奉。

Spring建議你只在具體類上應(yīng)用注解@Transactional注解,而不是注解到接口上。你可以將注解應(yīng)用到接口(或者接口方法)上,但是這只在你知道你在用基于接口的代理時(shí)起作用。實(shí)際上撩匕,Java注解不會(huì)從接口繼承,這意味著如果你使用基于類的代理(proxy-target-class="true")或者基于編織的切面( mode="aspectj")令漂,那么事務(wù)設(shè)置不會(huì)被代理和編織體系識(shí)別收叶,事務(wù)對(duì)象也不會(huì)被包裝到事務(wù)代理中,這毫無疑問是件壞事俏竞。

在代理模式(這是默認(rèn)選項(xiàng))中,只有顯式經(jīng)過代理的方法調(diào)用會(huì)被攔截烦秩。這意味著自我調(diào)用,也就是目標(biāo)對(duì)象中的一個(gè)方法調(diào)用該目標(biāo)對(duì)象的另一個(gè)方法岭皂,不會(huì)在運(yùn)行時(shí)觸發(fā)事務(wù),即使該方法標(biāo)記了@Transactional。同樣的片部,代理必須完全初始化來提供期望的行為曾雕,所以你不應(yīng)該在初始化代碼中依賴這樣的功能(例如@PostConstruct)顾犹。

如果需要使用多個(gè)事務(wù)管理器噩咪,可以像下面這樣。

public class TransactionalService {

   @Transactional("order")
   public void setSomething(String name) { ... }

   @Transactional("account")
   public void doSomething() { ... }
}

配置文件中竖般,事務(wù)管理器需要使用<qualifier>節(jié)點(diǎn)指定不同的名稱疗韵。

<tx:annotation-driven/>

    <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        ...
        <qualifier value="order"/>
    </bean>

    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        ...
        <qualifier value="account"/>
    </bean>

如果要應(yīng)用的注解有很多地方重復(fù)革砸,可以將它們定義為一個(gè)自定義注解仗岸,然后使用自定義注解應(yīng)用到需要的地方。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("account")
public @interface AccountTx {
}

Hibernate事務(wù)管理

前面簡(jiǎn)單使用了JDBC的事務(wù)管理。不過實(shí)際上大部分人應(yīng)該都需要使用Hibernate等高級(jí)框架的事務(wù)管理功能赴恨。下面也做一些介紹锹安。

首先需要一個(gè)接口叹哭,定義我們需要的操作入宦。

public interface UserDao {
    void add(User user);

    User get(String name);
}

然后我們實(shí)現(xiàn)這個(gè)接口,定義hibernate數(shù)據(jù)訪問病苗。這里使用了HibernateTemplate類阵幸,這個(gè)類是Spring提供的夺克,我們可以使用這個(gè)類簡(jiǎn)化Hibernate操作。我們可以看到使用這個(gè)類不需要操作Session爆安,Session會(huì)由Spring自動(dòng)管理叛复。當(dāng)然,這里為了使用Hibernate的自然主鍵扔仓,所以還是需要直接使用Session來查找自然主鍵致扯。

public class DefaultUserDao implements UserDao {
    private HibernateTemplate template;
    private SessionFactory sessionFactory;

    @Autowired
    public void setTemplate(HibernateTemplate template) {
        this.template = template;
    }

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public void add(User user) {
        template.save(user);
    }

    @Override
    public User get(String name) {
        Session session = sessionFactory.getCurrentSession();
        return session.bySimpleNaturalId(User.class).load(name);
    }
}

然后是Spring的配置,所有內(nèi)容都在前面解釋過了当辐。所以應(yīng)該很容易理解抖僵。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--設(shè)置數(shù)據(jù)源-->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"/>
        <property name="username" value="root"/>
        <property name="password" value="12345678"/>
    </bean>
    <!--設(shè)置SessionFactory-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
            <list>
                <value>yitian.learn.hibernate.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
            </props>
        </property>
    </bean>
    <!--設(shè)置hibernate模板-->
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <!--設(shè)置hibernate事務(wù)管理器-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <!--用戶數(shù)據(jù)訪問對(duì)象-->
    <bean id="userDao" class="yitian.learn.hibernate.DefaultUserDao"/>
    <!--設(shè)置事務(wù)管理-->
    <tx:advice id="txAdvice"
               transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <!--使用AOP設(shè)置事務(wù)管理-->
    <aop:config>

        <aop:pointcut id="userDaoPointcut"
                      expression="execution(* yitian.learn.hibernate.DefaultUserDao.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="userDaoPointcut"/>

    </aop:config>
</beans>

最后使用一個(gè)測(cè)試類來測(cè)試一下代碼≡稻荆可以看到耍群,在操作數(shù)據(jù)上我們完全沒有使用Hibernate的事務(wù)API义桂,完全交由Spring管理。當(dāng)然如果拋出異常蹈垢,Spring也會(huì)回滾慷吊。

@ContextConfiguration(locations = {"classpath:hibernate-bean.xml"})
@RunWith(SpringRunner.class)
public class HibernateTransactionTest {
    @Autowired
    private UserDao userDao;

    @Test
    public void testHibernateTransaction() {
        User user = new User();
        user.setUsername("yitian");
        user.setPassword("1234");
        user.setNickname("易天");
        user.setBirthday(LocalDate.now());
        userDao.add(user);

        User u = userDao.get(user.getUsername());
        System.out.println(u);
        assertEquals(user.getNickname(), u.getNickname());
    }
}

代碼在Csdn code,有興趣的同學(xué)可以看看曹抬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溉瓶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谤民,更是在濱河造成了極大的恐慌堰酿,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件张足,死亡現(xiàn)場(chǎng)離奇詭異触创,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)为牍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門哼绑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碉咆,你說我怎么就攤上這事抖韩。” “怎么了疫铜?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵茂浮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我块攒,道長(zhǎng)励稳,這世上最難降的妖魔是什么佃乘? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任囱井,我火速辦了婚禮,結(jié)果婚禮上趣避,老公的妹妹穿的比我還像新娘庞呕。我一直安慰自己,他們只是感情好程帕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布住练。 她就那樣靜靜地躺著,像睡著了一般愁拭。 火紅的嫁衣襯著肌膚如雪讲逛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天岭埠,我揣著相機(jī)與錄音盏混,去河邊找鬼蔚鸥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛许赃,可吹牛的內(nèi)容都是我干的止喷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼混聊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弹谁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起句喜,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤预愤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后藤滥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鳖粟,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拙绊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了向图。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡标沪,死狀恐怖榄攀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情金句,我是刑警寧澤檩赢,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站违寞,受9級(jí)特大地震影響贞瞒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趁曼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一军浆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挡闰,春花似錦乒融、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至奢驯,卻和暖如春申钩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘪阁。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工撒遣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留断盛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓愉舔,卻偏偏與公主長(zhǎng)得像钢猛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子轩缤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評(píng)論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理命迈,服務(wù)發(fā)現(xiàn),斷路器火的,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • 這部分的參考文檔涉及數(shù)據(jù)訪問和數(shù)據(jù)訪問層和業(yè)務(wù)或服務(wù)層之間的交互壶愤。 Spring的綜合事務(wù)管理支持覆蓋很多細(xì)節(jié),然...
    竹天亮閱讀 1,033評(píng)論 0 0
  • 很多人喜歡這篇文章馏鹤,特此同步過來 由淺入深談?wù)搒pring事務(wù) 前言 這篇其實(shí)也要?dú)w納到《常識(shí)》系列中征椒,但這重點(diǎn)又...
    碼農(nóng)戲碼閱讀 4,706評(píng)論 2 59
  • 說個(gè)從朋友那聽來的故事吧勃救。 高中時(shí)候朋友戀愛了,對(duì)象和他一個(gè)班治力,問起戀愛經(jīng)過也是一波三折的朋友說蒙秒, 從第一次走進(jìn)教...
    軟牙糖閱讀 208評(píng)論 0 0