spring自å¾äº‹åŠ¡½Ž¡ç†æ¨¡å—。而且˜q™ä¸ªäº‹åŠ¡½Ž¡ç†æ˜¯ä¸€ä¸ªæŠ½è±¡è®¾è®¡ï¼Œå¯ä»¥åº”用到很多场åˆï¼ŒåŒ…括普通的DataSourceåQŒjtaåQŒjmså’Œhibernate上ã€?/p>
è¦æ£¼‹®ä‹É用spring的事务,首先需è¦äº†è§£spring在事务设计上的一些概å¿?
¾lŸè§‚spring事务åQŒå›´¾l•ç€ä¸¤ä¸ªæ ¸å¿ƒPlatformTransactionManagerå’ŒTransactionStatus
PlatformTransactionManager直译˜q‡æ¥ž®±æ˜¯òq›_°ç›¸å…³äº‹åŠ¡åQŒè¿™é‡Œçš„òq›_°æŒ‡çš„æ˜¯â€œäº‹åŠ¡æºâ€ï¼ŒåŒ…æ‹¬åˆšæ‰æˆ‘说的DataSourceåQŒjta½{‰ç‰ã€‚è¿™äº›æ— ä¸€ä¸æ˜¯ä¸€ä¸ªäº‹åŠ¡æºã€‚广义的è¯ß_¼Œå‡¡æ˜¯å¯ä»¥å®Œæˆäº‹åŠ¡æ€§æ“作的对象åQŒéƒ½å¯ä»¥è®¾è®¡å‡ºç›¸å¯¹åº”çš„PlatformTransactionManageråQŒåªè¦è¿™ä¸ªäº‹åŠ¡æºæ”¯æŒcommitåQŒrollbackå’ŒgetTransactionè¯æ„ã€?/p>
查看spring代ç åQŒå¯ä»¥å‘现这些manager实现事务åQŒå°±æ˜¯è°ƒç”¨äº‹åŠ¡æºçš„事务æ“作方æ³?/p>
比如
HibernateTransactionManager
jdbc 的DataSourceTransactionManager
那么PlatformTransactionManagerä»¥ä»€ä¹ˆä¾æ®å¤„ç†äº‹åС呢åQ?
是TransactionStatus
查看apiå‘现˜q™ä¸ªæŽ¥å£æœ‰ä¸‰ä¸ªæ–¹æ³?
isNewTransaction() åQŒisRollbackOnly()åQŒsetRollbackOnly()
PlatformTransactionManagerž®±æ˜¯æ ÒŽ®å‰ä¸¤ä¸ªæ–¹æ³•决定是å¦è¦åˆ›å¾ä¸€ä¸ªæ–°äº‹åŠ¡åQŒæ˜¯è¦é€’交˜q˜æ˜¯å›žæ»šã€‚至于第三个æ–ÒŽ³•是改å˜äº‹åС当å‰çжæ€çš„åQŒå¾ˆå¤šåœ°æ–šwƒ½è¦ç”¨åˆŽÍ¼ŒååPlatformTransactionManager自èín好åƒä¸æ€Žä¹ˆç”¨ï¼Œæ¯•竟事务状æ€çš„æ”¹å˜æ˜¯ç”±½E‹åºå‘˜ä»£ç 决定的åQŒä¸éœ€è¦ä¸€ä¸ªmanager多管闲事ã€?/p>
æ€È»“ä¸Šé¢æ‰€è¯´çš„åQŒspring的事务由PlatformTransactionManager½Ž¡ç†åQŒmanager最åŽè°ƒç”¨äº‹åŠ¡æºçš„æ–¹æ³•æ¥å®žçŽ°ä¸€ä¸ªäº‹åŠ¡è¿‡½E‹ã€‚而manager通过TransactionStatus æ¥å†³å®šå¦‚何实现ã€?
接下去说spring事务ä¸çš„TransactionTemplateå’ŒTransactionInterceptor
TransactionTemplate其实和springä¸å…¶ä»–çš„template的作用类ä¼û|¼Œèµ·åˆ°åŒ–简代ç 的作用,ä¸è¦è¢«å®ƒé‚£ä¹ˆé•¿çš„åå—å“倒了åQŒäº‹å®žä¸Š˜q™ä¸ªtemplateòq¶ä¸æ˜¯ä»€ä¹ˆéžå¸¸æ ¸å¿ƒçš„对象。如果比较妽I¶æ´¾çš„,å¯ä»¥åŽÈœ‹çœ‹template设计模å¼åQŒåœ¨æ¤å°±ä¸å†å¯ÒŽ¤èµ˜è¿°äº†ã€?
ä¸ÞZ»€ä¹ˆè¦æœ‰TransactionTemplateåQŸå…ˆæ¥çœ‹çœ‹å¦‚果没有TransactionTemplateåQŒæˆ‘们的代ç 该怎么å†?/p>
å…ˆæ¥çœ‹çœ‹spring referenceä¸çš„一ŒDµä»£ç ?
åŒä¸Šé¢çš„代ç 如出一辙,å‰åŽæ˜¯äº‹åС处ç†ä»£ç ,当ä¸é‚£æ®µresult = action.doInTransaction(status);是我们的应用代ç 。至于action是什么,全看å„ä½çš„需è¦äº†ã€‚但是有一点è¦ä¸»è¦åQŒå¦‚果利用TransactionTemplateåQŒé‚£ä¹ˆä»–ä¸ç®¡ä½ 扔å‡ÞZ»€ä¹ˆå¼‚帔Rƒ½ä¼šå›žæ»šäº‹åŠ¡ï¼Œä½†æ˜¯å›žæ»šçš„æ˜¯å“ªä¸ªäº‹åŠ¡å‘¢ï¼Ÿ¾l§ç®‹æŒ–代ç ?
特别是在一些多事务æºçš„½E‹åºé‡Œï¼Œ˜q™ç‚¹åƒä¸‡ä¸èƒ½æžé”™ã€‚如果多个事务æºä¹‹é—´è¦å®Œæˆå…¨å±€äº‹åŠ¡åQŒè¿˜æ˜¯è€è€å®žå®žç”¨åˆ†å¸ƒå¼äº‹åŠ¡ç®¡ç†æœåŠ¡å§åQˆjtaåQ?/p>
那么TransactionInterceptor是干什么的åQŸè¿™ä¸ªæ˜¯spring 的声明å¼äº‹åŠ¡çš„æ”¯æŒæ–¹å¼ã€‚å› ä¸ºç”¨TransactionTemplateè¦ç¡¬¾~–ç åQŒè€Œä¸”调整事务½{–ç•¥å¾ˆéº»çƒ¦ï¼ˆä¸æ˜¯è¯´ä¸èƒ½è°ƒã€‚ä‹D个例å原æ¥ç¨‹åºæŠ›å‡ºå¼‚常A需è¦å›žæ»šï¼ŒçŽ°åœ¨ä¸éœ€è¦è¦åQŒæˆ‘ž®±å¯ä»¥æŠŠa catchåƒæŽ‰ã€‚è¿™æ—¶å€™templatež®×ƒ¸ä¼šå›žæ»šäº†ã€‚但是毋ơ调整都è¦é‡å†™ç¼–ç 。)而用TransactionInterceptorž®±å¯ä»¥å°†˜q™äº›è°ƒæ•´å†™åœ¨é…ç½®ä¸ã€‚æˆ‘ä»¬å†æ¥æŒ–TransactionInterceptor的代ç ?/p>
所以ä‹É用spring的事务管ç†éœ€è¦ä½œ˜q™äº›äº?
1åQŒè®¾¾|®å¥½äº‹åŠ¡æºï¼Œæ¯”如DataSourceåQŒhibernateçš„session。如果有多个事务æºè¦è€ƒè™‘ä»–ä»¬ä¹‹é—´æ˜¯å¦æœ‰å…¨å±€äº‹åŠ¡åQŒå¦‚果有åQŒè€è€å®žå®žç”¨jtaåQŒå¦åˆ™å°±éœ€è¦è‡ªå·±å†™ä¸€ä¸ªmanageräº?
2åQŒè®¾¾|®manageråQŒæ ¹æ®ä½ 的事务æºé€‰æ‹©å¯¹åº”çš„PlatformTransactionManager
3åQŒé€‰æ‹©å®žçŽ°äº‹ç‰©çš„æ–¹å¼ï¼Œç”¨template˜q˜æ˜¯interceptor。用template代ç 直观点,但是template所½Ž¡è¾–çš„managerå’Œä½ åº”ç”¨ä»£ç æ‰€ç”¨çš„事务æºè¦ä¸€è‡´ã€‚如果用interceptoråƒä¸‡æ³¨æ„åQŒä¸€å®šè¦è°ƒç”¨interceptor那个beanåQŒè€Œä¸æ˜¯åŽŸå§‹çš„é‚£ä¸ªtarget。在å›å上我已ç»çœ‹åˆ°è‡›_°‘有两个朋å‹è¯´spring事物ä¸è“v作用åQŒä»Žé…置和代ç 上看都æ£ç¡®åQŒè¿™æ—¶è¦å¥½å¥½æŸ¥æŸ¥åQŒè°ƒç”¨çš„bean是哪一个ã€?
4åQŒè¿™ä¸ªæ˜¯è®¾è®¡é—®é¢˜äº†ï¼ŒæŽ¨è事务处于一个较高层‹Æ¡ï¼Œæ¯”如service上的æŸä¸ªå‡½æ•°åQŒè€Œåº•层的daoå¯ä»¥ä¸è€ƒè™‘事务åQŒå¦åˆ™å¯èƒ½ä¼šå‡ºçŽ°äº‹åŠ¡åµŒå¥—åQŒå¢žåŠ ç¨‹åºå¤æ‚度ã€?/p>
一ã€åˆ›å»ºã€?br />   好了åQŒçŸ¥é“String是éžå¯å˜¾cÖM»¥åŽï¼Œæˆ‘们å¯ä»¥˜q›ä¸€æ¥äº†è§£Stringçš„æž„é€ æ–¹å¼äº†ã€‚创å»ÞZ¸€ä¸ªStirng对象åQŒä¸»è¦å°±æœ‰ä»¥ä¸‹ä¸¤¿Uæ–¹å¼ï¼š
    虽然两个è¯å¥éƒ½æ˜¯˜q”回一个String对象的引用,但是jvmå¯¹ä¸¤è€…çš„å¤„ç†æ–¹å¼æ˜¯ä¸ä¸€æ ïLš„。对于第一¿U,jvm会马上在heapä¸åˆ›å»ÞZ¸€ä¸ªString对象åQŒç„¶åŽå°†è¯¥å¯¹è±¡çš„引用˜q”回¾l™ç”¨æˆ—÷€‚对于第二ç§åQŒjvm首先会在内部¾l´æŠ¤çš„strings poolä¸é€šè¿‡Stringçš?equels æ–ÒŽ³•æŸ¥æ‰¾æ˜¯å¯¹è±¡æ± ä¸æ˜¯å¦å˜æ”¾æœ‰è¯¥String对象åQŒå¦‚果有åQŒåˆ™˜q”回已有的String对象¾l™ç”¨æˆøP¼Œè€Œä¸ä¼šåœ¨heapä¸é‡æ–°åˆ›å»ÞZ¸€ä¸ªæ–°çš„String对象åQ›å¦‚æžœå¯¹è±¡æ± ä¸æ²¡æœ‰è¯¥String对象åQŒjvm则在heapä¸åˆ›å»ºæ–°çš„String对象åQŒå°†å…¶å¼•用返回给用户åQŒåŒæ—¶å°†è¯¥å¼•ç”¨æ·»åŠ è‡³strings poolä¸ã€‚注æ„:使用½W¬ä¸€¿U方法创建对象时åQŒjvm是ä¸ä¼šä¸»åŠ¨æŠŠè¯¥å¯¹è±¡æ”¾åˆ°strings pool里é¢çš„,除鞽E‹åºè°ƒç”¨ Stringçš„internæ–ÒŽ³•。看下é¢çš„例å:
  å†çœ‹ä¸‹é¢çš„例å:
   ä¸ÞZ»€ä¹ˆjvmå¯ä»¥˜q™æ ·å¤„ç†String对象呢?ž®±æ˜¯å› 䨓Stringçš„éžå¯å˜æ€§ã€‚æ—¢ç„¶æ‰€å¼•ç”¨çš„å¯¹è±¡ä¸€æ—¦åˆ›å»ºå°±æ°æ€¸æ›´æ”¹åQŒé‚£ä¹ˆå¤šä¸ªå¼•用共用一个对象时互ä¸å½±å“ã€?/p>
二ã€ä¸²æŽ¥ï¼ˆConcatenationåQ‰ã€?br />    java½E‹åºå‘˜åº”è¯¥éƒ½çŸ¥é“æ»¥ç”¨String的串接æ“作符是会影哽E‹åºçš„æ€§èƒ½çš„。性能问题从何而æ¥å‘¢ï¼Ÿå½’æ ¹¾l“底ž®±æ˜¯String¾cÈš„éžå¯å˜æ€§ã€‚既然String对象都是éžå¯å˜çš„åQŒä¹Ÿž®±æ˜¯å¯¹è±¡ä¸€æ—¦åˆ›å»ÞZº†ž®×ƒ¸èƒ½å¤Ÿæ”¹å˜å…¶å†…在状æ€äº†åQŒä½†æ˜¯ä¸²æŽ¥æ“作明显是è¦å¢žé•¿å—½W¦ä¸²çš„ï¼Œä¹Ÿå°±æ˜¯è¦æ”¹å˜String的内部状æ€ï¼Œä¸¤è€…出çŽîCº†çŸ›ç›¾ã€‚怎么办呢åQŸè¦¾l´æŠ¤Stringçš„éžå¯å˜æ€§ï¼Œåªå¥½åœ¨ä¸²æŽ¥å®ŒæˆåŽæ–°å¾ä¸€ä¸ªString 对象æ¥è¡¨½Cºæ–°äº§ç”Ÿçš„å—½W¦ä¸²äº†ã€‚也ž®±æ˜¯è¯ß_¼Œæ¯ä¸€‹Æ¡æ‰§è¡Œä¸²æŽ¥æ“作都会导致新对象的äñ”生,如果串接æ“作执行很频¾J,ž®×ƒ¼šå¯ÆD‡´å¤§é‡å¯¹è±¡çš„创建,性能问题也就éšä¹‹è€Œæ¥äº†ã€?br />   ä¸ÞZº†è§£å†³˜q™ä¸ªé—®é¢˜åQŒjdk为String¾cÀL供了一个å¯å˜çš„é…套¾c»ï¼ŒStringBuffer。ä‹É用StringBuffer对象åQŒç”±äºŽè¯¥¾cÀL˜¯å¯å˜çš„,串接时仅仅时改å˜äº†å†…部数æ®ç»“构,而ä¸ä¼šåˆ›å»ºæ–°çš„å¯¹è±¡ï¼Œå› æ¤æ€§èƒ½ä¸Šæœ‰å¾ˆå¤§çš„æé«˜ã€‚针对啾U¿ç¨‹åQŒjdk 5.0˜q˜æä¾›äº†StringBuilder¾c»ï¼Œåœ¨å•¾U¿ç¨‹çŽ¯å¢ƒä¸‹ï¼Œç”׃ºŽä¸ç”¨è€ƒè™‘åŒæ¥é—®é¢˜åQŒä‹É用该¾cÖM‹É性能得到˜q›ä¸€æ¥çš„æé«˜ã€?/p>
三ã€String的长åº?br />  我们å¯ä»¥ä½¿ç”¨ä¸²æŽ¥æ“作½W¦å¾—åˆîC¸€ä¸ªé•¿åº¦æ›´é•¿çš„å—符ä¸ÔŒ¼Œé‚£ä¹ˆåQŒString对象最多能容纳多少å—符呢?查看Stringçš„æºä»£ç 我们å¯ä»¥å¾—知¾c»String䏿˜¯ä½¿ç”¨åŸ?count æ¥è®°å½•对象嗽W¦çš„æ•°é‡åQŒè€ŒcountÂ çš„ç±»åž‹äØ“ intåQŒå› æ¤ï¼Œæˆ‘们å¯ä»¥æŽ¨æµ‹æœ€é•¿çš„长度ä¸?2^32åQŒä¹Ÿž®±æ˜¯4Gã€?br />   ä¸è¿‡åQŒæˆ‘们在¾~–写æºä»£ç 的时候,如果使用 Sting str = "aaaa";çš„åÅžå¼å®šä¹‰ä¸€ä¸ªå—½W¦ä¸²åQŒé‚£ä¹ˆåŒå¼•å·é‡Œé¢çš„ASCIIå—符最多åªèƒ½æœ‰ 65534 ä¸ªã€‚äØ“ä»€ä¹ˆå‘¢åQŸå› 为在classæ–‡äšg的规范ä¸åQ?CONSTANT_Utf8_info表ä¸ä½¿ç”¨ä¸€ä¸?6ä½çš„æ— 符åäh•´æ•°æ¥è®°å½•å—符串的长度的,最多能表示 65536个å—节,而java class æ–‡äšg是ä‹É用一¿Uå˜ä½“UTF-8æ ¼å¼æ¥å˜æ”‘Ö—½W¦çš„åQŒnullå€ég‹É用两个å—节æ¥è¡¨ç¤ºåQŒå› æ¤åªå‰©ä¸‹ 65536åQ?2 åQ?65534个å—èŠ‚ã€‚ä¹Ÿæ£æ˜¯å˜ä½“UTF-8çš„åŽŸå› ï¼Œå¦‚æžœå—符串ä¸å«æœ‰ä¸æ–‡½{‰éžASCIIå—符åQŒé‚£ä¹ˆåŒå¼•å·ä¸å—½W¦çš„æ•°é‡ä¼šæ›´ž®‘ï¼ˆä¸€ä¸ªä¸æ–‡å—½W¦å 用三个å—èŠ‚ï¼‰ã€‚å¦‚æžœè¶…å‡ø™¿™ä¸ªæ•°é‡ï¼Œåœ¨ç¼–译的时候编译器会报错ã€?/p>
/**
* @author 王政
* @date 2006-11-24
* @note 转è²è¯äh³¨æ˜Žå‡ºå¤?
*/
在所有ä‹Éç”?spring 的应用ä¸, 声明å¼äº‹åŠ¡ç®¡ç†å¯èƒ½æ˜¯ä½¿ç”¨çŽ‡æœ€é«˜çš„åŠŸèƒ½äº? 但是, 从我观察到的情况çœ?
¾lå¤§å¤šæ•°äººåÆˆä¸èƒ½æ·±åˆ»ç†è§£äº‹åŠ¡å£°æ˜Žä¸ä¸åŒäº‹åŠ¡ä¼ æ’属性酾|®çš„çš„å«ä¹? 让我们æ¥çœ‹ä¸€ä¸?TransactionDefinition 接å£ä¸çš„定义
我们å¯ä»¥çœ‹åˆ°, åœ?spring ä¸ä¸€å…±å®šä¹‰äº†å…ç§äº‹åŠ¡ä¼ æ’属æ€? å¦‚æžœä½ è§‰å¾—çœ‹èµäh¥ä¸å¤Ÿç›´è§‚, 那么我æ¥è½¬è„“一个满大街都有的翻è¯?/p>
在我所è§è¿‡çš„误解ä¸, 最常è§çš„æ˜¯ä¸‹é¢˜q™ç§:
/**
* 事务属性酾|®äØ“ PROPAGATION_REQUIRED
*/
void methodA() {
// 调用 ServiceB 的方�
ServiceB.methodB();
}
那么如果 ServiceB çš?methodB 如果é…置了事åŠ? ž®±å¿…™å»é…¾|®äØ“ PROPAGATION_NESTED
˜q™ç§æƒÏx³•å¯èƒ½å®³äº†ä¸å°‘äº? è®¤äØ“ Service 之间应该é¿å…互相调用, 其实æ ÒŽœ¬ä¸ç”¨æ‹…心˜q™ç‚¹åQŒPROPAGATION_REQUIRED å·²ç»è¯´å¾—很明ç™?
如果当剾U¿ç¨‹ä¸å·²¾lå˜åœ¨äº‹åŠ? æ–ÒŽ³•è°ƒç”¨ä¼šåŠ å…¥æ¤äº‹åŠ¡, æžœå½“å‰æ²¡æœ‰äº‹åŠ¡ï¼Œž®±æ–°å»ÞZ¸€ä¸ªäº‹åŠ? 所ä»?ServiceB#methodB() 的事务åªè¦éµå¾ªæœ€æ™®é€šçš„规则é…ç½®ä¸?PROPAGATION_REQUIRED å›_¯, 如果 ServiceB#methodB (我们¿UîC¹‹ä¸ºå†…部事åŠ? ä¸ÞZ¸‹æ–‡æ‰“下基¼‹€) 抛了异常, 那么 ServiceA#methodA(我们¿UîC¹‹ä¸ºå¤–部事åŠ? 如果没有ç‰ÒŽ®Šé…ç½®æ¤å¼‚常时事务æäº¤ (å?+MyCheckedException的用æ³?, é‚£ä¹ˆæ•´ä¸ªäº‹åŠ¡æ˜¯ä¸€å®šè¦ rollback çš? 什ä¹?Service åªèƒ½è°?Dao ä¹‹ç±»çš„è¨€è®ºçº¯å±žæ— ½E½ä¹‹è°? spring åªè´Ÿè´£é…¾|®äº†äº‹åŠ¡å±žæ€§æ–¹æ³•çš„æ‹¦æˆª, 它怎么知é“ä½ è¿™ä¸ªæ–¹æ³•æ˜¯åœ?Service ˜q˜æ˜¯ Dao é‡??
说了˜q™ä¹ˆåŠå¤©, 那到底什么是真æ£çš„事务嵌套呢, è§£é‡Šä¹‹å‰æˆ‘们æ¥çœ‹ä¸€ä¸?Juergen Hoeller 的原è¯?/p>
Such independent inner transactions are for example used for id generation through manual sequences, where the access to the sequence table should happen in its own transactions, to keep the lock there as short as possible. The goal there is to avoid tying the sequence locks to the (potentially much longer running) outer transaction, with the sequence lock not getting released before completion of the outer transaction.
PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. ãTf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.
Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction.
For example, consider parsing a very large input file consisting of account transfer blocks: The entire file should essentially be parsed within one transaction, with one single commit at the end. But if a block fails, its transfers need to be rolled back, writing a failure marker somewhere. You could either start over the entire transaction every time a block fails, remembering which blocks to skip - or you mark each block as a nested transaction, only rolling back that specific set of operations, keeping the previous work of the outer transaction. The latter is of course much more efficient, in particular when a block at the end of the file fails.
So if an inner transaction throws an exception and is supposed to be rolled back (according to the rollback rules), the transaction will get rolled back to the savepoint taken at the start of the inner transaction. The immediate calling code can then decide to catch the exception and proceed down some other path within the outer transaction.
If the code that called the inner transaction lets the exception propagate up the call chain, the exception will eventually reach the demarcation code of the outer transaction. At that point, the rollback rules of the outer transaction decide whether to trigger a rollback. That would be a rollback of the entire outer transaction then.
So essentially, it depends on your exception handling. If you catch the exception thrown by the inner transaction, you can proceed down some other path within the outer transaction. If you let the exception propagate up the call chain, it's eventually gonna cause a rollback of the entire outer transaction.
也就是说, 最å®ÒŽ˜“å¼„æØœæ·†çš„å…¶å®žæ˜?PROPAGATION_REQUIRES_NEW å’?PROPAGATION_NESTED, 那么˜q™ä¸¤¿Uæ–¹å¼åˆæœ‰ä½•区别å‘? 我简å•çš„¾˜»è¯‘一ä¸?Juergen Hoeller çš„è¯ :
PROPAGATION_REQUIRES_NEW å¯åŠ¨ä¸€ä¸ªæ–°çš? ä¸ä¾èµ–于环境çš?"内部" 事务. ˜q™ä¸ªäº‹åŠ¡ž®†è¢«å®Œå…¨ commited æˆ?rolled back 而ä¸ä¾èµ–于外部事åŠ? 它拥有自å·Þqš„隔离范围, 自己的é”, ½{‰ç‰. 当内部事务开始执行时, 外部事务ž®†è¢«æŒ‚è“v, 内务事务¾l“æŸæ—? 外部事务ž®†ç‘ô¾l执è¡?
å¦ä¸€æ–šw¢, PROPAGATION_NESTED 开始一ä¸?"嵌套çš? 事务, 它是已ç»å˜åœ¨äº‹åŠ¡çš„ä¸€ä¸ªçœŸæ£çš„å事åŠ? 潜套事务开始执行时, 它将å–得一ä¸?savepoint. 如果˜q™ä¸ªåµŒå¥—事务å¤ÞpÓ|, 我们ž®†å›žæ»šåˆ°æ?savepoint. 潜套事务是外部事务的一部分, åªæœ‰å¤–部事务¾l“æŸåŽå®ƒæ‰ä¼šè¢«æäº?
ç”±æ¤å¯è§, PROPAGATION_REQUIRES_NEW å’?PROPAGATION_NESTED 的最大区别在äº? PROPAGATION_REQUIRES_NEW 完全是一个新的事åŠ? è€?PROPAGATION_NESTED 则是外部事务的å事务, 如果外部事务 commit, 潜套事务也会è¢?commit, ˜q™ä¸ªè§„åˆ™åŒæ ·é€‚用äº?roll back.
那么外部事务如何利用嵌套事务çš?savepoint ç‰ÒŽ€§å‘¢, æˆ‘ä»¬ç”¨ä»£ç æ¥è¯´è¯
˜q™ç§æƒ…况ä¸? å› äØ“ ServiceB#methodB çš„äº‹åŠ¡å±žæ€§äØ“ PROPAGATION_REQUIRES_NEW, 所以两者ä¸ä¼šå‘生ä“Q何关¾p? ServiceA#methodA å’?ServiceB#methodB ä¸ä¼šå› 䨓å¯ÒŽ–¹çš„æ‰§è¡Œæƒ…况而媄å“事务的¾l“æžœ, å› äØ“å®ƒä»¬æ ÒŽœ¬ž®±æ˜¯ä¸¤ä¸ªäº‹åŠ¡, åœ?ServiceB#methodB 执行æ—?ServiceA#methodA 的事务已¾l挂起了 (关于事务挂è“v的内容已¾lè¶…å‡ÞZº†æœ¬æ–‡çš„è®¨è®ø™Œƒå›? 有时间我会å†å†™ä¸€äº›æŒ‚èµïLš„æ–‡ç« ) .
那么 PROPAGATION_NESTED åˆæ˜¯æ€Žä¹ˆå›žäº‹å‘? ¾l§ç®‹çœ‹ä»£ç ?/p>
现在的情况就å˜å¾—æ¯”è¾ƒå¤æ‚äº? ServiceB#methodB 的事务属性被é…ç½®ä¸?PROPAGATION_NESTED, æ¤æ—¶ä¸¤è€…之间刞®†å¦‚何å作呢? ä»?Juergen Hoeller 的原è¯ä¸æˆ‘们å¯ä»¥æ‰‘Öˆ°½{”案, ServiceB#methodB 如果 rollback, 那么内部事务(å?ServiceB#methodB) ž®†å›žæ»šåˆ°å®ƒæ‰§è¡Œå‰çš?SavePoint(注æ„, ˜q™æ˜¯æœ¬æ–‡ä¸ç¬¬ä¸€‹Æ¡æåˆ°å®ƒ, æ½œå¥—äº‹åŠ¡ä¸æœ€æ ¸å¿ƒçš„æ¦‚å¿?, 而外部事åŠ?å?ServiceA#methodA) å¯ä»¥æœ‰ä»¥ä¸‹ä¸¤¿Uå¤„ç†æ–¹å¼?
1. 改写 ServiceA 如下
˜q™ç§æ–¹å¼ä¹Ÿæ˜¯æ½œå¥—事务最有äh值的地方, 它è“våˆîCº†åˆ†æ”¯æ‰§è¡Œçš„æ•ˆæž? 如果 ServiceB.methodB å¤ÞpÓ|, 那么执行 ServiceC.methodC(), è€?ServiceB.methodB å·²ç»å›žæ»šåˆ°å®ƒæ‰§è¡Œä¹‹å‰çš?SavePoint, 所以ä¸ä¼šäñ”ç”Ÿè„æ•°æ®(ç›¸å½“äºŽæ¤æ–ÒŽ³•从未执行˜q?, ˜q™ç§ç‰ÒŽ€§å¯ä»¥ç”¨åœ¨æŸäº›ç‰¹ŒDŠçš„业务ä¸? è€?PROPAGATION_REQUIRED å’?PROPAGATION_REQUIRES_NEW 都没有办法åšåˆ°è¿™ä¸€ç‚? (题外è¯?: 看到˜q™ç§ä»£ç , ä¼ég¹Žä¼¼æ›¾ç›¸è¯†, 惌™“väº?prototype.js ä¸çš„ Try 函数 )
2. 代ç ä¸åšä»ÖM½•修改, 那么如果内部事务(å?ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之å‰çš?SavePoint(在ä“Q何情况下都会如æ¤),
外部事务(å?ServiceA#methodA) ž®†æ ¹æ®å…·ä½“çš„é…置军_®šè‡ªå·±æ˜?commit ˜q˜æ˜¯ rollback (+MyCheckedException).
上é¢å¤§è‡´è®²è¿°äº†æ½œå¥—事务的使用场景, 䏋颿ˆ‘们æ¥çœ‹å¦‚何åœ?spring ä¸ä‹Éç”?PROPAGATION_NESTED, 首先æ¥çœ‹ AbstractPlatformTransactionManager
1. 我们è¦è®¾¾|?transactionManager çš?nestedTransactionAllowed å±žæ€§äØ“ true, 注æ„, æ¤å±žæ€§é»˜è®¤äØ“ false!!!
å†çœ‹ AbstractTransactionStatus#createAndHoldSavepoint() æ–ÒŽ³•
å¯ä»¥çœ‹åˆ° Savepoint æ˜?SavepointManager.createSavepoint 实现çš? å†çœ‹ SavepointManager 的层‹Æ¡ç»“æž? å‘现
�Template 实现�JdbcTransactionObjectSupport, 常用�DatasourceTransactionManager, HibernateTransactionManager
ä¸çš„ TransactonObject 都是它的åç±» :
JdbcTransactionObjectSupport å‘Šè¯‰æˆ‘ä»¬å¿…é¡»è¦æ»¡‘³ä¸¤ä¸ªæ¡ä»¶æ‰èƒ?createSavepoint :
2. java.sql.Savepoint å¿…é¡»å˜åœ¨, å?jdk 版本è¦?1.4+
3. Connection.getMetaData().supportsSavepoints() å¿…é¡»ä¸?true, å?jdbc drive å¿…é¡»æ”¯æŒ JDBC 3.0
¼‹®ä¿ä»¥ä¸Šæ¡äšg都满‘›_Ž, ä½ å°±å¯ä»¥ž®è¯•使用 PROPAGATION_NESTED äº? (全文å®?
Â
Servletå’?/span>Filterçš?/span>url匚w…以åŠurl-pattern详解     Servletå’?/span>filteræ˜?/span>J2EEå¼€å‘ä¸å¸¸ç”¨çš„æŠ€æœ¯ï¼Œä½¿ç”¨æ–¹ä¾¿åQŒé…¾|®ç®€å•,è€å°‘皆宜。估计大多数朋å‹éƒ½æ˜¯ç›´æŽ¥é…置用,也没有关心过具体的细节,今天é‡åˆ°ä¸€ä¸ªé—®é¢˜ï¼Œä¸Šç½‘查了servlet的规范æ‰å‘现åQ?/span>servletå’?/span>filterä¸çš„url-pattern˜q˜æ˜¯æœ‰ä¸€äº›æ–‡ç« 在里é¢çš„,æ€È»“了一些东西,攑ևºæ¥ä¾›å¤§å®¶å‚考,以å…é‡åˆ°é—®é¢˜åˆè¦‹¹ªè´¹æ—‰™—´ã€?/span>    一åQ?/font>servlet容器å¯?/span>url的匹é…过½E‹ï¼šÂ    Â
    æ ÒŽ®˜q™ä¸ªè§„则表,ž®Þpƒ½å¾ˆæ¸…楚的知é“servlet的匹é…过½E‹ï¼Œæ‰€ä»¥å®šä¹?/span>servlet的时候也è¦è€ƒè™‘url-pattern的写法,以å…出错ã€?/span>      对于filteråQŒä¸ä¼šåƒservleté‚£æ ·åªåŒ¹é…一ä¸?/span>servletåQŒå› ä¸?/span>filterçš„é›†åˆæ˜¯ä¸€ä¸ªé“¾åQŒæ‰€ä»¥åªä¼šæœ‰å¤„ç†çš„顺åºä¸åŒï¼Œè€Œä¸ä¼šå‡ºçްåªé€‰æ‹©ä¸€ä¸?/span>filterã€?/span>Filter的处ç†é¡ºåºå’Œfilter-mappingåœ?/span>web.xmlä¸å®šä¹‰çš„™åºåºç›¸åŒã€?/span>    二,url-pattern详解        åœ?/span>web.xmlæ–‡äšgä¸ï¼Œä»¥ä¸‹è¯æ³•ç”¨äºŽå®šä¹‰æ˜ å°„åQ?/span> l ä»?/span>â€?â€?/span>开头和ä»?/span>â€?*â€?/span>¾l“尾的是用æ¥åšèµ\å¾„æ˜ ž®„çš„ã€?/span> l 以剾~€â€?.â€?/span>开头的是用æ¥åšæ‰©å±•æ˜ å°„çš„ã€?/span> l â€?â€?是用æ¥å®šä¹?/span>default servletæ˜ å°„çš„ã€?/span> l 剩下的都是用æ¥å®šä¹‰è¯¦¾l†æ˜ ž®„的。比如: /aa/bb/cc.action 所以,ä¸ÞZ»€ä¹ˆå®šä¹?/span>â€?*.actionâ€?/span>˜q™æ ·ä¸€ä¸ªçœ‹èµäh¥å¾ˆæ£å¸¸çš„匚w…会错åQŸå› 䏸™¿™ä¸ªåŒ¹é…å³å±žäºŽè·¯å¾„æ˜ å°„åQŒä¹Ÿå±žäºŽæ‰©å±•æ˜ å°„åQŒå¯¼è‡´å®¹å™¨æ— 法判æ–ã€?/span> ã€å‚考内å®V€?/span>                            Java  Servlet 2.4 Specification |