Spring事務(wù)傳播與隔離級別

什么是事務(wù)

  1. 事務(wù)就是一組操作數(shù)據(jù)庫的動作集合可霎。
  2. 動作集合被完整地執(zhí)行魄鸦,我們稱該事務(wù)被提交。動作集合中的某一部分執(zhí)行失敗癣朗,整個(gè)動作集合提交失敗拾因,回到最初的狀態(tài),稱為事務(wù)回滾旷余。
  3. 事務(wù)是一系列的動作绢记,它們綜合在一起才是一個(gè)完整的工作單元,這些動作必須全部完成正卧,如果有一個(gè)失敗的話蠢熄,那么事務(wù)就會回滾到最開始的狀態(tài),仿佛什么都沒發(fā)生過一樣穗酥。

事務(wù)的特性

  1. 原子性(Atomicity):事務(wù)是一個(gè)原子操作护赊,由一系列動作組成惠遏。事務(wù)的原子性確保動作要么全部完成砾跃,要么完全不起作用。(操作)
  2. 一致性(Consistency):一旦事務(wù)完成(不管成功還是失斀谒薄)抽高,系統(tǒng)必須確保它所建模的業(yè)務(wù)處于一致的狀態(tài),而不會是部分完成部分失敗透绩。在現(xiàn)實(shí)中的數(shù)據(jù)不應(yīng)該被破壞翘骂。(數(shù)據(jù))
  3. 隔離性(Isolation):可能有許多事務(wù)會同時(shí)處理相同的數(shù)據(jù)壁熄,因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開來,防止數(shù)據(jù)損壞碳竟。(數(shù)據(jù))
  4. 持久性(Durability):一旦事務(wù)完成草丧,無論發(fā)生什么系統(tǒng)錯(cuò)誤,它的結(jié)果都不應(yīng)該受到影響莹桅,這樣就能從任何系統(tǒng)崩潰中恢復(fù)過來昌执。通常情況下,事務(wù)的結(jié)果被寫到持久化存儲器中诈泼。(數(shù)據(jù))

spring事務(wù)管理核心接口

Spring事務(wù)管理的實(shí)現(xiàn)有許多細(xì)節(jié)懂拾,如果對整個(gè)接口框架有個(gè)大體了解會非常有利于我們理解事務(wù),下面通過講解Spring的事務(wù)接口來了解Spring實(shí)現(xiàn)事務(wù)的具體策略铐达。

image

事務(wù)管理器

Spring并不直接管理事務(wù)岖赋,而是提供了多種事務(wù)管理器,他們將事務(wù)管理的職責(zé)委托給Hibernate或者JTA等持久化機(jī)制所提供的相關(guān)平臺框架的事務(wù)來實(shí)現(xiàn)瓮孙。
Spring事務(wù)管理器的接口是
org.springframework.transaction.PlatformTransactionManager唐断,通過這個(gè)接口,Spring為各個(gè)平臺如JDBC杭抠、Hibernate等都提供了對應(yīng)的事務(wù)管理器栗涂,但是具體的實(shí)現(xiàn)就是各個(gè)平臺自己的事情了。

Public interface PlatformTransactionManager()...{  
    // 由TransactionDefinition得到TransactionStatus對象
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
    // 提交
    Void commit(TransactionStatus status) throws TransactionException;  
    // 回滾
    Void rollback(TransactionStatus status) throws TransactionException;  
} 

從這里可知具體的具體的事務(wù)管理機(jī)制對Spring來說是透明的祈争,它并不關(guān)心那些斤程,那些是對應(yīng)各個(gè)平臺需要關(guān)心的,所以Spring事務(wù)管理的一個(gè)優(yōu)點(diǎn)就是為不同的事務(wù)API提供一致的編程模型菩混,如JTA忿墅、JDBC、Hibernate沮峡、JPA疚脐。

1.JDBC事務(wù)

如果應(yīng)用程序中直接使用JDBC來進(jìn)行持久化,DataSourceTransactionManager會為你處理事務(wù)邊界邢疙。為了使用DataSourceTransactionManager棍弄,你需要使用如下的XML將其裝配到應(yīng)用程序的上下文定義中

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

實(shí)際上,DataSourceTransactionManager是通過調(diào)用java.sql.Connection來管理事務(wù)疟游,而后者是通過DataSource獲取到的呼畸。通過調(diào)用連接的commit()方法來提交事務(wù),同樣颁虐,事務(wù)失敗則通過調(diào)用rollback()方法進(jìn)行回滾蛮原。

2.Hibernate事務(wù)

如果應(yīng)用程序的持久化是通過Hibernate實(shí)習(xí)的,那么你需要使用HibernateTransactionManager另绩。對于Hibernate3儒陨,需要在Spring上下文定義中添加如下的<bean>聲明:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

sessionFactory屬性需要裝配一個(gè)Hibernate的session工廠花嘶,HibernateTransactionManager的實(shí)現(xiàn)細(xì)節(jié)是它將事務(wù)管理的職責(zé)委托給org.hibernate.Transaction對象,而后者是從Hibernate Session中獲取到的蹦漠。當(dāng)事務(wù)成功完成時(shí)椭员,HibernateTransactionManager將會調(diào)用Transaction對象的commit()方法,反之笛园,將會調(diào)用rollback()方法拆撼。

基本事務(wù)屬性的定義

上面講到的事務(wù)管理器接口PlatformTransactionManager通過getTransaction(TransactionDefinition definition)方法來得到事務(wù),這個(gè)方法里面的參數(shù)是TransactionDefinition類喘沿,這個(gè)類就定義了一些基本的事務(wù)屬性闸度。
那么什么是事務(wù)屬性呢?事務(wù)屬性可以理解成事務(wù)的一些基本配置蚜印,描述了事務(wù)策略如何應(yīng)用到方法上莺禁。事務(wù)屬性包含了5個(gè)方面:

  1. 傳播行為
  2. 隔離規(guī)則
  3. 回滾規(guī)則
  4. 事務(wù)超時(shí)
  5. 是否只讀
image

TransactionDefinition接口內(nèi)容如下:

public interface TransactionDefinition {
    int getPropagationBehavior(); // 返回事務(wù)的傳播行為
    int getIsolationLevel(); // 返回事務(wù)的隔離級別,事務(wù)管理器根據(jù)它來控制另外一個(gè)事務(wù)可以看到本事務(wù)內(nèi)的哪些數(shù)據(jù)
    int getTimeout();  // 返回事務(wù)必須在多少秒內(nèi)完成
    boolean isReadOnly(); // 事務(wù)是否只讀窄赋,事務(wù)管理器能夠根據(jù)這個(gè)返回值進(jìn)行優(yōu)化哟冬,確保事務(wù)是只讀的
} 

事務(wù)傳播行為(重點(diǎn))

什么是事務(wù)傳播?

事務(wù)傳播行為用來描述由某一個(gè)事務(wù)傳播行為修飾的方法被嵌套進(jìn)另一個(gè)方法的時(shí)事務(wù)如何傳播忆绰。

public void methodA(){
    methodB();
    //doSomething
     }
     
     @Transaction(Propagation=XXX)
     public void methodB(){
    //doSomething
 }

代碼中methodA()方法嵌套調(diào)用了methodB()方法浩峡,methodB()的事務(wù)傳播行為由@Transaction(Propagation=XXX)設(shè)置決定。這里需要注意的是methodA()并沒有開啟事務(wù)错敢,某一個(gè)事務(wù)傳播行為修飾的方法并不是必須要在開啟事務(wù)的外圍方法中調(diào)用翰灾。

spring事務(wù)傳播行為有哪些?(重點(diǎn)掌握)

傳播行為 含義
PROPAGATION_REQUIRED 如果當(dāng)前沒有事務(wù)稚茅,就新建一個(gè)事務(wù)纸淮,如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中亚享,這是最常見的選擇咽块,也是默認(rèn)的事務(wù)傳播行為。
PROPAGATION_REQUIRED_NEW 新建事務(wù)欺税,如果當(dāng)前存在事務(wù)侈沪,把當(dāng)前事務(wù)掛起。
PROPAGATION_SUPPORTS 支持當(dāng)前事務(wù)晚凿,如果當(dāng)前沒有事務(wù)亭罪,就以非事務(wù)方式執(zhí)行。
PROPAGATION_NOT_SUPPORTED 以非事務(wù)方式執(zhí)行操作晃虫,如果當(dāng)前存在事務(wù)皆撩,就把當(dāng)前事務(wù)掛起扣墩。
PROPAGATION_NESTED 如果當(dāng)前存在事務(wù)哲银,則在嵌套事務(wù)內(nèi)執(zhí)行扛吞。如果當(dāng)前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作荆责。
PROPAGATION_NEVER 以非事務(wù)方式執(zhí)行滥比,如果當(dāng)前存在事務(wù),則拋出異常做院。
PROPAGATION_MANDATORY 使用當(dāng)前的事務(wù)盲泛,如果當(dāng)前沒有事務(wù),就拋出異常键耕。

當(dāng)使用PROPAGATION_NESTED時(shí)寺滚,底層的數(shù)據(jù)源必須基于JDBC 3.0,并且實(shí)現(xiàn)者需要支持保存點(diǎn)事務(wù)機(jī)制屈雄。

什么是事務(wù)掛起村视?

例如方法A支持事務(wù),方法B不支持事務(wù)酒奶,方法A調(diào)用方法B蚁孔。
在方法A開始運(yùn)行時(shí),系統(tǒng)為它建立Transaction惋嚎,方法A中對于數(shù)據(jù)庫的操作杠氢,會在該Transaction的控制之下。
這時(shí)另伍,方法A調(diào)用方法B鼻百,方法A打開的Transation將掛起,方法B中任何數(shù)據(jù)庫操作摆尝,都不在該Transaction的管理之下愕宋。
當(dāng)方法B返回,方法A繼續(xù)運(yùn)行结榄,之前的Transaction恢復(fù)中贝,后面的數(shù)據(jù)庫操作繼續(xù)在該Transaction的控制之下提交或回滾。

測試案例

用戶實(shí)現(xiàn)類中包含注冊和注冊送積分兩個(gè)業(yè)務(wù)方法:

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private BSService bsService;
    //用戶注冊
    @Override
    public void registe(User user) {
    userMapper.insert(user);
    }
    //用戶注冊并送積分
    @Override
    public void registeAndCredit(User user){
        registe(user);
        Credit credit = new Credit();
        credit.setUsername(user.getName());
        credit.setScore(20);
        bsService.addCredit(credit);
    }
}

業(yè)務(wù)實(shí)現(xiàn)類中有送積分的業(yè)務(wù)方法:

@Service
public class BSServiceImpl implements BSService {
    @Autowired
    private CreditMapper creditMapper;
        //送積分
        @Override
        public void addCredit(Credit credit) {
        creditMapper.insert(credit);
        throw new RuntimeException();
    }
}

registeAndCredit方法中包含了用戶注冊和送積分兩個(gè)數(shù)據(jù)庫操作臼朗。

1.PROPAGATION_REQUIRED

如果當(dāng)前沒有事務(wù)邻寿,就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中视哑,加入到這個(gè)事務(wù)中绣否,這是最常見的選擇,也是默認(rèn)的事務(wù)傳播行為挡毅。

場景一:registeAndCredit方法不添加事務(wù)蒜撮,registe方法和addCredit方法均添加PROPAGATION_REQUIRED事務(wù),addCredit方法拋出異常。

 //送積分
@Override
@Transactional
public void addCredit(Credit credit) {
    creditMapper.insert(credit);
    throw new RuntimeException();
}
//用戶注冊
@Override
@Transactional
public void registe(User user) {
userMapper.insert(user);
}
@Test
public void test03(){
    User user = new User();
    user.setName("小紅");
    user.setAge(26);
    userService.registeAndCredit(user);
}

測試結(jié)果:用戶注冊成功段磨,送積分失敗取逾。
測試分析:因?yàn)閞egisteAndCredit沒有添加事務(wù),對于registe和addCredit來說苹支,屬于當(dāng)前沒有事務(wù)砾隅,所以各自新建事務(wù),兩個(gè)事務(wù)是獨(dú)立的债蜜,互不影響晴埂。

場景二:registeAndCredit方法添加PROPAGATION_REQUIRED事務(wù)。對于registe和addCredit來說寻定,屬于存在事務(wù)儒洛,是否添加PROPAGATION_REQUIRED均屬于同一個(gè)事務(wù)。

如果事務(wù)中異常被try catch處理后狼速,事務(wù)正常提交晶丘。(嵌套調(diào)用方法除外)
使用此事務(wù),在事務(wù)A中又開了一個(gè)事務(wù)B唐含,其實(shí)AB是同一種事務(wù)浅浮,當(dāng)事務(wù)回滾B時(shí)已經(jīng)將事務(wù)標(biāo)記為回滾,如果在A中try catch之后捷枯,事務(wù)A再次執(zhí)行commit會報(bào)異常:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only(事務(wù)已經(jīng)被標(biāo)記為回滾)
代碼如下:

 //用戶注冊并送積分
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void registeAndCredit(User user){
    registe(user);
    Credit credit = new Credit();
    credit.setUsername(user.getName());
    credit.setScore(20);
    try {
        bsService.addCredit(credit);
    }catch (Exception e){
        System.out.println("%%%%%%%%%%%%%%%%%%%jiaixnxiao%%%%%%%%%%");
    }
}

//送積分
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addCredit(Credit credit) {
    creditMapper.insert(credit);
    throw new RuntimeException();
}

執(zhí)行registeAndCredit拋出事務(wù)已經(jīng)被標(biāo)記為回滾的異常滚秩。

2.PROPAGATION_REQUIRED_NEW

新建事務(wù),如果當(dāng)前存在事務(wù)淮捆,把當(dāng)前事務(wù)掛起郁油。

PROPAGATION_REQUIRES_NEW 啟動一個(gè)新的、和外層事務(wù)無關(guān)的“內(nèi)部”事務(wù)攀痊。該事務(wù)擁有自己的獨(dú)立隔離級別和鎖桐腌,不依賴于外部事務(wù),獨(dú)立地提交和回滾苟径。當(dāng)內(nèi)部事務(wù)開始執(zhí)行時(shí)案站,外部事務(wù) 將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時(shí)棘街,外部事務(wù)才繼續(xù)執(zhí)行蟆盐。

場景一:registeAndCredit添加PROPAGATION_REQUIRED事務(wù),addCredit添加PROPAGATION_REQUIRES_NEW事務(wù)遭殉,并且拋出異常

  1. 如果不在registeAndCredit中對addCredit進(jìn)行try catch的話石挂,兩個(gè)事務(wù)均回滾,因?yàn)閍ddCredit拋出異常到registeAndCredit险污。(可以理解為addCredit開啟新事物拋出異常并回滾痹愚,異常被當(dāng)前事務(wù)registeAndCredit接收,因此也回滾)。
  2. registeAndCredit對addCredit進(jìn)行try catch拯腮,新事物回滾窖式,當(dāng)前事務(wù)正常commit,所以用戶注冊成功疾瓮,送積分操作回滾脖镀。

場景二:registeAndCredit添加PROPAGATION_REQUIRES_NEW事務(wù)飒箭,addCredit添加PROPAGATION_REQUIRES_NEW事務(wù)狼电,并且拋出異常,與場景一相同弦蹂。

場景三:registeAndCredit添加PROPAGATION_REQUIRED事務(wù)肩碟,addCredit添加PROPAGATION_REQUIRES_NEW事務(wù),在registeAndCredit中拋出異常凸椿,因?yàn)閍ddCredit創(chuàng)建了新事務(wù)削祈,是兩個(gè)不同的事務(wù),所以用戶注冊回滾脑漫,送積分提交成功髓抑。

3.PROPAGATION_NESTED

如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行优幸。如果當(dāng)前沒有事務(wù)吨拍,則執(zhí)行與PROPAGATION_REQUIRED類似的操作。

場景一:與PROPAGATION_REQUIRED_NEW場景一相同网杆。
場景三:registeAndCredit添加PROPAGATION_REQUIRED事務(wù)羹饰,addCredit添加PROPAGATION_NESTED事務(wù),在registeAndCredit中拋出異常碳却。addCredit創(chuàng)建了registeAndCredit事務(wù)的嵌套事務(wù)队秩,外圍事務(wù)拋出異常回滾昼浦,嵌套事務(wù)也回滾馍资。所以用戶注冊回滾,送積分回滾关噪。

新事務(wù)與嵌套事務(wù)

PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區(qū)別在于:PROPAGATION_REQUIRES_NEW 將創(chuàng)建一個(gè)全新的事務(wù)迷帜,它和外層事務(wù)沒有任何關(guān)系,而 PROPAGATION_NESTED 將創(chuàng)建一個(gè)依賴于外層事務(wù)的子事務(wù)色洞,當(dāng)外層事務(wù)提交或回滾時(shí)戏锹,子事務(wù)也會連帶提交和回滾。

注意問題

  1. 當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_MANDATORY時(shí)火诸,它就不能被非事務(wù)的業(yè)務(wù)方法調(diào)用锦针。如將addCredit設(shè)置為PROPAGATION_MANDATORY,如果controller直接調(diào)用addCredit方法,將引發(fā)一個(gè)異常奈搜。正確的情況是:addCredit方法必須被另一個(gè)帶事務(wù)的業(yè)務(wù)方法調(diào)用悉盆。所以 PROPAGATION_MANDATORY的方法一般都是被其它業(yè)務(wù)方法間接調(diào)用的。
  2. 當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_NEVER時(shí)馋吗,它將不能被擁有事務(wù)的其它業(yè)務(wù)方法調(diào)用焕盟。假設(shè)addCredit設(shè)置為PROPAGATION_NEVER,當(dāng)registeAndCredit擁有一個(gè)事務(wù)時(shí)宏粤,addCredit方法將拋出異常脚翘。所以PROPAGATION_NEVER方法一般是被直接調(diào)用的。
  3. 當(dāng)方法被設(shè)置為PROPAGATION_NOT_SUPPORTED時(shí)绍哎,外層業(yè)務(wù)方法的事務(wù)會被掛起来农,當(dāng)內(nèi)部方法運(yùn)行完成后,外層方法的事務(wù)重新運(yùn)行崇堰。如果外層方法沒有事務(wù)沃于,直接運(yùn)行,不需要做任何其它的事海诲。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末繁莹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子特幔,更是在濱河造成了極大的恐慌咨演,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敬辣,死亡現(xiàn)場離奇詭異雪标,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)溉跃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門村刨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人撰茎,你說我怎么就攤上這事嵌牺。” “怎么了龄糊?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵逆粹,是天一觀的道長。 經(jīng)常有香客問我炫惩,道長僻弹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任他嚷,我火速辦了婚禮蹋绽,結(jié)果婚禮上芭毙,老公的妹妹穿的比我還像新娘。我一直安慰自己卸耘,他們只是感情好退敦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚣抗,像睡著了一般侈百。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翰铡,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天钝域,我揣著相機(jī)與錄音,去河邊找鬼两蟀。 笑死网梢,一個(gè)胖子當(dāng)著我的面吹牛震缭,可吹牛的內(nèi)容都是我干的赂毯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拣宰,長吁一口氣:“原來是場噩夢啊……” “哼党涕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起巡社,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤膛堤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后晌该,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肥荔,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年朝群,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燕耿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姜胖,死狀恐怖誉帅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情右莱,我是刑警寧澤蚜锨,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站慢蜓,受9級特大地震影響亚再,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晨抡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一氛悬、第九天 我趴在偏房一處隱蔽的房頂上張望饲鄙。 院中可真熱鬧,春花似錦圆雁、人聲如沸忍级。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轴咱。三九已至,卻和暖如春烈涮,著一層夾襖步出監(jiān)牢的瞬間朴肺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工坚洽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戈稿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓讶舰,卻偏偏與公主長得像鞍盗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子跳昼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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