ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>国内精品久久久久久久影视简单,亚洲精品成人自拍,中文字幕在线一区http://www.aygfsteel.com/NeonWay/archive/2007/01/22/95243.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Mon, 22 Jan 2007 03:22:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2007/01/22/95243.htmlhttp://www.aygfsteel.com/NeonWay/comments/95243.htmlhttp://www.aygfsteel.com/NeonWay/archive/2007/01/22/95243.html#Feedback1http://www.aygfsteel.com/NeonWay/comments/commentRss/95243.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/95243.html
abstract classå’Œinterface是Java语言中对于抽象类定义˜q›è¡Œæ”¯æŒçš„两¿UæœºåˆÓž¼Œæ­£æ˜¯ç”׃ºŽ˜q™ä¸¤¿Uæœºåˆ¶çš„存在åQŒæ‰èµ‹äºˆäº†Java强大的面向对象能力。abstract classå’Œinterfaceä¹‹é—´åœ¨å¯¹äºŽæŠ½è±¡ç±»å®šä¹‰çš„æ”¯æŒæ–¹é¢å…·æœ‰å¾ˆå¤§çš„ç›æ€¼¼æ€§ï¼Œç”šè‡³å¯ä»¥ç›æ€º’替换åQŒå› æ­¤å¾ˆå¤šå¼€å‘者在˜q›è¡ŒæŠ½è±¡¾cÕd®šä¹‰æ—¶å¯¹äºŽabstract classå’Œinterface的选择昑־—比较随意。其实,两者之间还是有很大的区别的åQŒå¯¹äºŽå®ƒä»¬çš„选择甚至反映出对于问题领域本质的理解、对于设计意囄¡š„理解是否正确、合理。本文将对它们之间的区别˜q›è¡Œä¸€ç•ªå‰–析,试图¾l™å¼€å‘者提供一个在二者之间进行选择的依据。Â?

理解抽象¾c»Â?

abstract classå’Œinterface在Java语言中都是用来进行抽象类åQˆæœ¬æ–‡ä¸­çš„æŠ½è±¡ç±»òq‰™žä»Žabstract class¾˜»è¯‘而来åQŒå®ƒè¡¨ç¤ºçš„æ˜¯ä¸€ä¸ªæŠ½è±¡ä½“åQŒè€Œabstract class为Java语言中用于定义抽象类的一¿Uæ–¹æ³•,误‚¯»è€…注意区分)定义的,那么什么是抽象¾c»ï¼Œä½¿ç”¨æŠ½è±¡¾c»èƒ½ä¸ºæˆ‘们带来什么好处呢åQŸÂ?

在面向对象的概念中,我们知道所有的对象都是通过¾cÀL¥æç»˜çš„,但是反过来却不是˜q™æ ·ã€‚åÆˆä¸æ˜¯æ‰€æœ‰çš„¾c»éƒ½æ˜¯ç”¨æ¥æ¾l˜å¯¹è±¡çš„åQŒå¦‚果一个类中没有包含èƒö够的信息来描¾l˜ä¸€ä¸ªå…·ä½“的对象åQŒè¿™æ ïLš„¾cÕd°±æ˜¯æŠ½è±¡ç±»ã€‚抽象类往往用来表征我们在对问题领域˜q›è¡Œåˆ†æžã€è®¾è®¡ä¸­å¾—出的抽象概念,是对一¾pÕdˆ—看上åŽÖM¸åŒï¼Œä½†æ˜¯æœ¬è´¨ä¸Šç›¸åŒçš„具体概念的抽象。比如:如果我们˜q›è¡Œä¸€ä¸ªå›¾å½¢ç¼–辑èÊY件的开发,ž®×ƒ¼šå‘现问题领域存在着圆、三角åÅž˜q™æ ·ä¸€äº›å…·ä½“概念,它们是不同的åQŒä½†æ˜¯å®ƒä»¬åˆéƒ½å±žäºŽåŞ状这样一个概念,形状˜q™ä¸ªæ¦‚念在问题领域是不存在的åQŒå®ƒž®±æ˜¯ä¸€ä¸ªæŠ½è±¡æ¦‚å¿üc€‚正是因为抽象的概念在问题领域没有对应的具体概念åQŒæ‰€ä»¥ç”¨ä»¥è¡¨å¾æŠ½è±¡æ¦‚å¿ëŠš„抽象¾cÀL˜¯ä¸èƒ½å¤Ÿå®žä¾‹åŒ–的。Â?

在面向对象领域,抽象¾cÖM¸»è¦ç”¨æ¥è¿›è¡Œç±»åž‹éšè—ã€‚我们可以构造出一个固定的一¾l„行为的抽象描述åQŒä½†æ˜¯è¿™¾l„行为却能够有ä“Q意个可能的具体实现方式。这个抽象描˜q°å°±æ˜¯æŠ½è±¡ç±»åQŒè€Œè¿™ä¸€¾l„ä“Q意个可能的具体实现则表现为所有可能的‹z„¡”Ÿ¾c…R€‚æ¨¡å—å¯ä»¥æ“ä½œä¸€ä¸ªæŠ½è±¡ä½“ã€‚ç”±äºŽæ¨¡å—ä¾èµ–äºŽä¸€ä¸ªå›ºå®šçš„æŠ½è±¡ä½“ï¼Œå› æ­¤å®ƒå¯ä»¥æ˜¯ä¸å…è®æ€¿®æ”¹çš„åQ›åŒæ—Óž¼Œé€šè¿‡ä»Žè¿™ä¸ªæŠ½è±¡ä½“‹z„¡”ŸåQŒä¹Ÿå¯æ‰©å±•此模块的行为功能。熟悉OCP的读者一定知道,ä¸ÞZº†èƒ½å¤Ÿå®žçŽ°é¢å‘å¯¹è±¡è®¾è®¡çš„ä¸€ä¸ªæœ€æ ¸å¿ƒçš„åŽŸåˆ™OCP(Open-Closed Principle)åQŒæŠ½è±¡ç±»æ˜¯å…¶ä¸­çš„关键所在。Â?


从语法定义层面看abstract class和interface 

在语法层面,Java语言对于abstract classå’Œinterface¾l™å‡ºäº†ä¸åŒçš„定义方式åQŒä¸‹é¢ä»¥å®šä¹‰ä¸€ä¸ªåä¸ºDemo的抽象类ä¸ÞZ¾‹æ¥è¯´æ˜Žè¿™¿Uä¸åŒã€‚Â?

使用abstract class的方式定义Demo抽象¾cÈš„æ–¹å¼å¦‚下åQšÂ?

abstract class Demo {�
 abstract void method1(); 
 abstract void method2(); 
 …�
}�

使用interface的方式定义Demo抽象¾cÈš„æ–¹å¼å¦‚下åQšÂ?

interface Demo { 
 void method1(); 
 void method2(); 
 …�
} 

在abstract class方式中,Demo可以有自å·Þqš„æ•°æ®æˆå‘˜åQŒä¹Ÿå¯ä»¥æœ‰éžabstarct的成员方法,而在interface方式的实çŽîC¸­åQŒDemo只能够有静态的不能被修改的数据成员åQˆä¹Ÿž®±æ˜¯å¿…须是static final的,不过在interface中一般不定义数据成员åQ‰ï¼Œæ‰€æœ‰çš„æˆå‘˜æ–ÒŽ³•都是abstract的。从某种意义上说åQŒinterface是一¿Uç‰¹ŒDŠåŞ式的abstract class。Â?

      从编½E‹çš„角度来看åQŒabstract classå’Œinterface都可以用来实çŽ?design by contract"的思想。但是在具体的ä‹É用上面还是有一些区别的。Â?

首先åQŒabstract class在Java语言中表½Cºçš„æ˜¯ä¸€¿Uç‘ô承关¾p»ï¼Œä¸€ä¸ªç±»åªèƒ½ä½¿ç”¨ä¸€‹Æ¡ç‘ô承关¾p…R€‚但是,一个类却可以实现多个interface。也许,˜q™æ˜¯Java语言的设计者在考虑Java对于多重¾l§æ‰¿çš„æ”¯æŒæ–¹é¢çš„一¿UæŠ˜ä¸­è€ƒè™‘吧。Â?

其次åQŒåœ¨abstract class的定义中åQŒæˆ‘ä»¬å¯ä»¥èµ‹äºˆæ–¹æ³•çš„é»˜è®¤è¡ŒäØ“ã€‚ä½†æ˜¯åœ¨interface的定义中åQŒæ–¹æ³•å´ä¸èƒ½æ‹¥æœ‰é»˜è®¤è¡ŒäØ“åQŒäؓ了绕˜q‡è¿™ä¸ªé™åˆÓž¼Œå¿…须使用委托åQŒä½†æ˜¯è¿™ä¼šÂ å¢žåŠ ä¸€äº›å¤æ‚æ€§ï¼Œæœ‰æ—¶ä¼šé€ æˆå¾ˆå¤§çš„éº»çƒ¦ã€‚Â?

åœ¨æŠ½è±¡ç±»ä¸­ä¸èƒ½å®šä¹‰é»˜è®¤è¡Œä¸ø™¿˜å­˜åœ¨å¦ä¸€ä¸ªæ¯”较严重的问题åQŒé‚£ž®±æ˜¯å¯èƒ½ä¼šé€ æˆ¾l´æŠ¤ä¸Šçš„éºÈƒ¦ã€‚因为如果后来想修改¾cȝš„界面åQˆä¸€èˆ¬é€šè¿‡abstract class或者interface来表½Cºï¼‰ä»¥é€‚应新的情况åQˆæ¯”如,æ·ÕdŠ æ–°çš„æ–ÒŽ³•或者给已用的方法中æ·ÕdŠ æ–°çš„å‚æ•°åQ‰æ—¶åQŒå°±ä¼šéžå¸¸çš„éºÈƒ¦åQŒå¯èƒ½è¦èŠÞp´¹å¾ˆå¤šçš„æ—¶é—ß_¼ˆå¯¹äºŽ‹z„¡”Ÿ¾cÕd¾ˆå¤šçš„æƒ…况åQŒå°¤ä¸ºå¦‚此)。但是如果界面是通过abstract class来实现的åQŒé‚£ä¹ˆå¯èƒ½å°±åªéœ€è¦ä¿®æ”¹å®šä¹‰åœ¨abstract classä¸­çš„é»˜è®¤è¡ŒäØ“ž®±å¯ä»¥äº†ã€‚Â?

同样åQŒå¦‚果不能在抽象¾cÖM¸­å®šä¹‰é»˜è®¤è¡ŒäØ“åQŒå°±ä¼šå¯¼è‡´åŒæ ïLš„æ–ÒŽ³•实现出现在该抽象¾cÈš„æ¯ä¸€ä¸ªæ´¾ç”Ÿç±»ä¸­ï¼Œ˜qåäº?one ruleåQŒone place"原则åQŒé€ æˆä»£ç é‡å¤åQŒåŒæ ·ä¸åˆ©äºŽä»¥åŽçš„维护。因此,在abstract classå’Œinterface间进行选择时要非常的小心。Â?


从设计理念层面看abstract class和interface 

上面主要从语法定义和¾~–程的角度论˜qîCº†abstract classå’Œinterface的区别,˜q™äº›å±‚面的区别是比较低层‹Æ¡çš„、非本质的。本ž®èŠ‚ž®†ä»Žå¦ä¸€ä¸ªå±‚面:abstract classå’Œinterface所反映出的设计理念åQŒæ¥åˆ†æžä¸€ä¸‹äºŒè€…的区别。作者认为,从这个层面进行分析才能理解二者概å¿ëŠš„本质所在。Â?

前面已经提到˜q‡ï¼Œabstarct class在Java语言中体çŽîCº†ä¸€¿Uç‘ô承关¾p»ï¼Œè¦æƒ³ä½¿å¾—¾l§æ‰¿å…³ç³»åˆç†åQŒçˆ¶¾cÕd’Œ‹z„¡”Ÿ¾cÖM¹‹é—´å¿…™åÕd­˜åœ?is a"关系åQŒå³çˆ¶ç±»å’Œæ´¾ç”Ÿç±»åœ¨æ¦‚忉|œ¬è´¨ä¸Šåº”该是相同的åQˆå‚考文献ã€?〕中有关äº?is a"关系的大½‹‡å¹…深入的论˜qŽÍ¼Œæœ‰å…´­‘£çš„读者可以参考)。对于interface 来说则不ç„Óž¼Œòq¶ä¸è¦æ±‚interface的实现者和interface定义在概忉|œ¬è´¨ä¸Šæ˜¯ä¸€è‡´çš„åQŒä»…仅是实现了interface定义的契¾U¦è€Œå·²ã€‚äØ“äº†ä‹Éè®ø™¿°ä¾¿äºŽç†è§£åQŒä¸‹é¢å°†é€šè¿‡ä¸€ä¸ªç®€å•的实例˜q›è¡Œè¯´æ˜Žã€‚Â?

考虑˜q™æ ·ä¸€ä¸ªä¾‹å­ï¼Œå‡è®¾åœ¨æˆ‘们的问题领域中有一个关于Door的抽象概念,该Doorå…ähœ‰æ‰§è¡Œä¸¤ä¸ªåŠ¨ä½œopenå’ŒcloseåQŒæ­¤æ—¶æˆ‘们可以通过abstract class或者interface来定义一个表½Cø™¯¥æŠ½è±¡æ¦‚念的类型,定义方式分别如下所½Cºï¼šÂ 

使用abstract class方式定义DooråQšÂ?

abstract class Door { 
 abstract void open(); 
 abstract void close()åQ›Â?
} 

  
使用interface方式定义DooråQšÂ?


interface Door { 
 void open(); 
 void close(); 
} 

  
其他具体的Door¾cÕdž‹å¯ä»¥extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看èµäh¥å¥½åƒä½¿ç”¨abstract classå’Œinterface没有大的区别。Â?

如果现在要求Door˜q˜è¦å…ähœ‰æŠ¥è­¦çš„功能。我们该如何设计针对该例子的¾cȝ»“构呢åQˆåœ¨æœ¬ä¾‹ä¸­ï¼Œä¸»è¦æ˜¯äؓ了展½Cºabstract classå’Œinterface反映在设计理念上的区别,其他斚w¢æ— å…³çš„问题都做了½Ž€åŒ–或者忽略)åQŸä¸‹é¢å°†¾|—列出可能的解决æ–ÒŽ¡ˆåQŒåƈ从设计理念层面对˜q™äº›ä¸åŒçš„æ–¹æ¡ˆè¿›è¡Œåˆ†æžã€‚Â?

解决æ–ÒŽ¡ˆä¸€åQšÂ?

½Ž€å•的在Door的定义中增加一个alarmæ–ÒŽ³•åQŒå¦‚下: 

abstract class Door { 
 abstract void open(); 
 abstract void close()åQ›Â?
 abstract void alarm(); 
} 

  
或者�

interface Door { 
 void open(); 
 void close(); 
 void alarm(); 
} 

  
那么å…ähœ‰æŠ¥è­¦åŠŸèƒ½çš„AlarmDoor的定义方式如下: 

class AlarmDoor extends Door { 
 void open() { … } 
 void close() { … } 
 void alarm() { … } 
} 

  
或者�

class AlarmDoor implements Door {�
 void open() { … } 
 void close() { … } 
 void alarm() { … } 
}�

˜q™ç§æ–ÒŽ³•˜qåäº†é¢å‘对象设计中的一个核心原则ISPåQˆInterface Segregation PricipleåQ‰ï¼Œåœ¨Door的定义中把Door概念本èín固有的行为方法和另外一个概å¿?报警å™?çš„è¡Œä¸ºæ–¹æ³•æØœåœ¨äº†ä¸€èµ—÷€‚这样引èµïLš„一个问题是那些仅仅依赖于Door˜q™ä¸ªæ¦‚å¿µçš„æ¨¡å—ä¼šå› äØ“"报警å™?˜q™ä¸ªæ¦‚念的改变(比如åQšä¿®æ”¹alarmæ–ÒŽ³•的参敎ͼ‰è€Œæ”¹å˜ï¼Œåä¹‹ä¾ç„¶ã€‚Â?

解决æ–ÒŽ¡ˆäºŒï¼šÂ 

既然open、closeå’Œalarm属于两个不同的概念,æ ÒŽ®ISP原则应该把它们分别定义在代表˜q™ä¸¤ä¸ªæ¦‚å¿ëŠš„抽象¾cÖM¸­ã€‚定义方式有åQšè¿™ä¸¤ä¸ªæ¦‚念都ä‹É用abstract class方式定义åQ›ä¸¤ä¸ªæ¦‚念都使用interface方式定义åQ›ä¸€ä¸ªæ¦‚念ä‹É用abstract class方式定义åQŒå¦ä¸€ä¸ªæ¦‚念ä‹É用interface方式定义。Â?

昄¡„¶åQŒç”±äºŽJava语言不支持多重ç‘ô承,所以两个概念都使用abstract class方式定义是不可行的。后面两¿Uæ–¹å¼éƒ½æ˜¯å¯è¡Œçš„åQŒä½†æ˜¯å¯¹äºŽå®ƒä»¬çš„选择却反映出对于问题领域中的概念本质的理解、对于设计意囄¡š„反映是否正确、合理。我们一一来分析、说明。Â?

如果两个概念都ä‹É用interface方式来定义,那么ž®±åæ˜ å‡ºä¸¤ä¸ªé—®é¢˜åQ?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|œ¬è´¨ä¸Šåˆ°åº•是Door˜q˜æ˜¯æŠ¥è­¦å™¨ï¼Ÿ2、如果我们对于问题领域的理解没有问题åQŒæ¯”如:我们通过对于问题领域的分析发现AlarmDoor在概忉|œ¬è´¨ä¸Šå’ŒDoor是一致的åQŒé‚£ä¹ˆæˆ‘们在实现时就没有能够正确的揭½Cºæˆ‘们的设计意图åQŒå› ä¸ºåœ¨˜q™ä¸¤ä¸ªæ¦‚å¿ëŠš„定义上(均ä‹É用interface方式定义åQ‰åæ˜ ä¸å‡ÞZ¸Š˜q°å«ä¹‰ã€‚Â?

如果我们对于问题领域的理解是åQšAlarmDoor在概忉|œ¬è´¨ä¸Šæ˜¯DooråQŒåŒæ—¶å®ƒæœ‰å…·æœ‰æŠ¥è­¦çš„功能。我们该如何来设计、实现来明确的反映出我们的意思呢åQŸå‰é¢å·²¾lè¯´˜q‡ï¼Œabstract class在Java语言中表½CÞZ¸€¿Uç‘ô承关¾p»ï¼Œè€Œç‘ô承关¾pÕdœ¨æœ¬è´¨ä¸Šæ˜¯"is a"关系。所以对于Door˜q™ä¸ªæ¦‚念åQŒæˆ‘们应该ä‹É用abstarct class方式来定义。另外,AlarmDooråˆå…·æœ‰æŠ¥è­¦åŠŸèƒ½ï¼Œè¯´æ˜Žå®ƒåˆèƒ½å¤Ÿå®ŒæˆæŠ¥è­¦æ¦‚å¿µä¸­å®šä¹‰çš„è¡ŒäØ“åQŒæ‰€ä»¥æŠ¥è­¦æ¦‚念可以通过interface方式定义。如下所½Cºï¼šÂ 

abstract class Door { 
 abstract void open(); 
 abstract void close()åQ›Â?
} 
interface Alarm { 
 void alarm(); 
} 
class AlarmDoor extends Door implements Alarm { 
 void open() { … } 
 void close() { … } 
    void alarm() { … } 
} 

  
˜q™ç§å®žçŽ°æ–¹å¼åŸºæœ¬ä¸Šèƒ½å¤Ÿæ˜Ž¼‹®çš„反映出我们对于问题领域的理解åQŒæ­£¼‹®çš„æ­ç¤ºæˆ‘们的设计意图。其实abstract class表示的是"is a"关系åQŒinterface表示的是"like a"关系åQŒå¤§å®¶åœ¨é€‰æ‹©æ—¶å¯ä»¥ä½œä¸ÞZ¸€ä¸ªä¾æ®ï¼Œå½“ç„¶˜q™æ˜¯å»ºç«‹åœ¨å¯¹é—®é¢˜é¢†åŸŸçš„理解上的,比如åQšå¦‚果我们认为AlarmDoor在概忉|œ¬è´¨ä¸Šæ˜¯æŠ¥è­¦å™¨åQŒåŒæ—¶åˆå…ähœ‰Door的功能,那么上述的定义方式就要反˜q‡æ¥äº†ã€‚ Â?/font> 

]]>
spring事务探烦 http://www.aygfsteel.com/NeonWay/archive/2007/01/15/93872.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Mon, 15 Jan 2007 02:10:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2007/01/15/93872.htmlhttp://www.aygfsteel.com/NeonWay/comments/93872.htmlhttp://www.aygfsteel.com/NeonWay/archive/2007/01/15/93872.html#Feedback0http://www.aygfsteel.com/NeonWay/comments/commentRss/93872.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/93872.htmlhttp://www.javaeye.com/topic/11190?page=1

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

代码
  1. protected void doCommit(DefaultTransactionStatus status) {   
  2.         HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();   
  3.         if (status.isDebug()) {   
  4.             logger.debug("Committing Hibernate transaction on session [" +   
  5.                     txObject.getSessionHolder().getSession() + "]");   
  6.         }   
  7.         try {   
  8.             txObject.getSessionHolder().getTransaction().commit();   
  9.         }   
  10. ...   
  11.   
  12.     }  

jdbc 的DataSourceTransactionManager

代码
  1. protected void doCommit(DefaultTransactionStatus status) {   
  2.         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
  3.         Connection con = txObject.getConnectionHolder().getConnection();   
  4.         if (status.isDebug()) {   
  5.             logger.debug("Committing JDBC transaction on connection [" + con + "]");   
  6.         }   
  7.         try {   
  8.             con.commit();   
  9.         }   
  10.         ...   
  11.     }  

那么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µä»£ç ?

代码
  1. DefaultTransactionDefinition def = new DefaultTransactionDefinition()   
  2. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);   
  3.   
  4. TransactionStatus status = transactionManager.getTransaction(def);   
  5.   
  6. try {   
  7.     // execute your business logic here   
  8. } catch (MyException ex) {   
  9.     transactionManager.rollback(status);   
  10.     throw ex;   
  11. }   
  12. transactionManager.commit(status);  

˜q™æ˜¯ç›´æŽ¥ä½¿ç”¨transactionManager的例子,可以看到真正执行business logic 的地æ–ÒŽ˜¯åœ¨try当中那段åQŒå‰åŽçš„代码都是ä¸ÞZº†å®Œæˆäº‹åŠ¡½Ž¡ç†çš„。如果每个business logic都要写上那么一ŒDµï¼Œæˆ‘肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码

代码
  1. public Object execute(TransactionCallback action) throws TransactionException {   
  2.         TransactionStatus status = this.transactionManager.getTransaction(this);   
  3.         Object result = null;   
  4.         try {   
  5.             result = action.doInTransaction(status);   
  6.         }   
  7.         catch (RuntimeException ex) {   
  8.             // transactional code threw application exception -> rollback   
  9.             rollbackOnException(status, ex);   
  10.             throw ex;   
  11.         }   
  12.         catch (Error err) {   
  13.             // transactional code threw error -> rollback   
  14.             rollbackOnException(status, err);   
  15.             throw err;   
  16.         }   
  17.         this.transactionManager.commit(status);   
  18.         return result;   
  19.     }  

同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要åQŒå¦‚果利用TransactionTemplateåQŒé‚£ä¹ˆä»–不管你扔å‡ÞZ»€ä¹ˆå¼‚帔Rƒ½ä¼šå›žæ»šäº‹åŠ¡ï¼Œä½†æ˜¯å›žæ»šçš„æ˜¯å“ªä¸ªäº‹åŠ¡å‘¢ï¼Ÿ¾l§ç®‹æŒ–代ç ?

代码
  1. private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {   
  2.         if (logger.isDebugEnabled()) {   
  3.             logger.debug("Initiating transaction rollback on application exception", ex);   
  4.         }   
  5.         try {   
  6.             this.transactionManager.rollback(status);   
  7.         }   
  8.         catch (RuntimeException ex2) {   
  9.             logger.error("Application exception overridden by rollback exception", ex);   
  10.             throw ex2;   
  11.         }   
  12.         catch (Error err) {   
  13.             logger.error("Application exception overridden by rollback error", ex);   
  14.             throw err;   
  15.         }   
  16.     }  

真相大白åQŒæ˜¯å¯¹template所持有的某个transactionManager˜q›è¡Œå›žæ»šã€‚所以如果你的应用代码用的是事务源a的一些资源,比如到服务器a的一个datasourceåQŒä½†æ˜¯ä½ çš„transactionManager½Ž¡ç†çš„æ˜¯å¦ä¸€äº›èµ„源,比如服务器b的一个datasourceåQŒä»£ç é“å®šä¸ä¼šæ­£å¸¸è¿è¡?

特别是在一些多事务源的½E‹åºé‡Œï¼Œ˜q™ç‚¹åƒä¸‡ä¸èƒ½æžé”™ã€‚如果多个事务源之间要完成全局事务åQŒè¿˜æ˜¯è€è€å®žå®žç”¨åˆ†å¸ƒå¼äº‹åŠ¡ç®¡ç†æœåŠ¡å§åQˆjtaåQ?/p>

那么TransactionInterceptor是干什么的åQŸè¿™ä¸ªæ˜¯spring 的声明式事务的支持方式。因为用TransactionTemplate要硬¾~–码åQŒè€Œä¸”调整事务½{–略很麻烦(不是说不能调。ä‹D个例子原来程序抛出异常A需要回滚,现在不需要要åQŒæˆ‘ž®±å¯ä»¥æŠŠa catch吃掉。这时候templatež®×ƒ¸ä¼šå›žæ»šäº†ã€‚但是每‹Æ¡è°ƒæ•´éƒ½è¦é‡å†™ç¼–码。)而用TransactionInterceptorž®±å¯ä»¥å°†˜q™äº›è°ƒæ•´å†™åœ¨é…ç½®ä¸­ã€‚我们再来挖TransactionInterceptor的代ç ?/p>

代码
  1. public Object invoke(MethodInvocation invocation) throws Throwable {   
  2.         // Work out the target class: may be null.   
  3.         // The TransactionAttributeSource should be passed the target class   
  4.         // as well as the method, which may be from an interface   
  5.         Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;   
  6.            
  7.         // Create transaction if necessary   
  8.         TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);   
  9.   
  10.         Object retVal = null;   
  11.         try {   
  12.             // This is an around advice.   
  13.             // Invoke the next interceptor in the chain.   
  14.             // This will normally result in a target object being invoked.   
  15.             retVal = invocation.proceed();   
  16.         }   
  17.         catch (Throwable ex) {   
  18.             // target invocation exception   
  19.             doCloseTransactionAfterThrowing(txInfo, ex);   
  20.             throw ex;   
  21.         }   
  22.         finally {   
  23.             doFinally(txInfo);   
  24.         }   
  25.         doCommitTransactionAfterReturning(txInfo);   
  26.   
  27.         return retVal;   
  28.     }  

万变不离其宗�

所以ä‹É用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>

]]>
理解 java中Stringhttp://www.aygfsteel.com/NeonWay/archive/2007/01/15/93859.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Mon, 15 Jan 2007 01:56:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2007/01/15/93859.htmlhttp://www.aygfsteel.com/NeonWay/comments/93859.htmlhttp://www.aygfsteel.com/NeonWay/archive/2007/01/15/93859.html#Feedback2http://www.aygfsteel.com/NeonWay/comments/commentRss/93859.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/93859.htmlhttp://www.javaeye.com/post/199106

 要理è§?java中String的运作方式,必须明确一点:String是一个非可变¾c»ï¼ˆimmutableåQ‰ã€‚什么是非可变类呢?½Ž€å•说来,非可变类的实例是不能被修改的åQŒæ¯ä¸ªå®žä¾‹ä¸­åŒ…含的信息都必须在该实例创徏的时候就提供出来åQŒåƈ且在对象的整个生存周期内固定不变。javaä¸ÞZ»€ä¹ˆè¦æŠŠString设计为非可变¾cÕd‘¢åQŸä½ å¯ä»¥é—®é—® james Gosling åQšï¼‰ã€‚但是非可变¾cȝ¡®å®žæœ‰ç€è‡ªèín的优势,如状态单一åQŒå¯¹è±¡ç®€å•,便于¾l´æŠ¤ã€‚å…¶‹Æ¡ï¼Œè¯¥ç±»å¯¹è±¡å¯¹è±¡æœ¬è´¨ä¸Šæ˜¯¾U¿ç¨‹å®‰å…¨çš„,不要求同步。此外用户可以共享非可变对象åQŒç”šè‡›_¯ä»¥å…±äº«å®ƒä»¬çš„内部信息。(详见 《Effective java》item 13åQ‰ã€‚String¾cÕdœ¨java中被大量˜qç”¨åQŒç”šè‡›_œ¨classæ–‡äšg中都有其íw«åª„åQŒå› æ­¤å°†å…¶è®¾è®¡äØ“½Ž€å•轻便的非可变类是比较合适的ã€?

一、创建ã€?br />    好了åQŒçŸ¥é“String是非可变¾cÖM»¥åŽï¼Œæˆ‘们可以˜q›ä¸€æ­¥äº†è§£String的构造方式了。创å»ÞZ¸€ä¸ªStirng对象åQŒä¸»è¦å°±æœ‰ä»¥ä¸‹ä¸¤¿Uæ–¹å¼ï¼š

java 代码
  1. String str1 = new String("abc");    
  2. Stirng str2 = "abc";  

     虽然两个语句都是˜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æ–ÒŽ³•。看下面的例子:

java 代码
  1. String str1 = new String("abc"); //jvm 在堆上创å»ÞZ¸€ä¸ªString对象   
  2.   
  3.  //jvm 在strings pool中找不到å€égؓ“abc”的字符ä¸ÔŒ¼Œå› æ­¤   
  4.  //在堆上创å»ÞZ¸€ä¸ªString对象åQŒåƈž®†è¯¥å¯¹è±¡çš„引用加入至strings poolä¸?  
  5.  //此时堆上有两个String对象   
  6. Stirng str2 = "abc";   
  7.   
  8.  if(str1 == str2){   
  9.          System.out.println("str1 == str2");   
  10.  }else{   
  11.          System.out.println("str1 != str2");   
  12.  }   
  13.   //打印¾l“果是 str1 != str2,å› äØ“å®ƒä»¬æ˜¯å †ä¸Šä¸¤ä¸ªä¸åŒçš„å¯¹è±¡   
  14.   
  15.   String str3 = "abc";   
  16.  //此时åQŒjvm发现strings pool中已有“abc”对象了åQŒå› ä¸ºâ€œabc”equels “abcâ€?  
  17.  //因此直接˜q”回str2指向的对象给str3åQŒä¹Ÿž®±æ˜¯è¯´str2å’Œstr3是指向同一个对象的引用   
  18.   if(str2 == str3){   
  19.          System.out.println("str2 == str3");   
  20.   }else{   
  21.          System.out.println("str2 != str3");   
  22.   }   
  23.  //打印¾l“果为 str2 == str3  

   再看下面的例子:

java 代码
  1. String str1 = new String("abc"); //jvm 在堆上创å»ÞZ¸€ä¸ªString对象   
  2.   
  3. str1 = str1.intern();   
  4. //½E‹åºæ˜‘Ö¼ž®†str1攑ֈ°strings pool中,intern˜qè¡Œ˜q‡ç¨‹æ˜¯è¿™æ ïLš„åQšé¦–先查看strings pool   
  5. //有没“abc”对象的引用åQŒæ²¡æœ‰ï¼Œåˆ™åœ¨å †ä¸­æ–°å¾ä¸€ä¸ªå¯¹è±¡ï¼Œç„¶åŽž®†æ–°å¯¹è±¡çš„引用加入至   
  6. //strings pool中。执行完该语句后åQŒstr1原来指向的Stringå¯¹è±¡å·²ç»æˆäØ“åžƒåœ¾å¯¹è±¡äº†ï¼Œéšæ—¶ä¼?  
  7. //被GC攉™›†ã€?  
  8.   
  9. //此时åQŒjvm发现strings pool中已有“abc”对象了åQŒå› ä¸ºâ€œabc”equels “abcâ€?  
  10. //因此直接˜q”回str1指向的对象给str2åQŒä¹Ÿž®±æ˜¯è¯´str2å’Œstr1引用着同一个对象,   
  11. //此时åQŒå †ä¸Šçš„æœ‰æ•ˆå¯¹è±¡åªæœ‰ä¸€ä¸ªã€?  
  12. Stirng str2 = "abc";   
  13.   
  14.  if(str1 == str2){   
  15.          System.out.println("str1 == str2");   
  16.  }else{   
  17.          System.out.println("str1 != str2");   
  18.  }   
  19.   //打印¾l“果是 str1 == str2   
  20.   


    ä¸Þ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>

]]>
解惑 spring 嵌套事务http://www.aygfsteel.com/NeonWay/archive/2006/12/29/90727.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Fri, 29 Dec 2006 06:06:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2006/12/29/90727.htmlhttp://www.aygfsteel.com/NeonWay/comments/90727.htmlhttp://www.aygfsteel.com/NeonWay/archive/2006/12/29/90727.html#Feedback0http://www.aygfsteel.com/NeonWay/comments/commentRss/90727.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/90727.html http://www.javaeye.com/topic/35907

解惑 spring 嵌套事务

/**
* @author 王政
* @date 2006-11-24
* @note 转蝲è¯äh³¨æ˜Žå‡ºå¤?
*/

在所有ä‹Éç”?spring 的应用中, 声明式事务管理可能是使用率最高的功能äº? 但是, 从我观察到的情况çœ?
¾lå¤§å¤šæ•°äººåƈ不能深刻理解事务声明中不同事务传播属性配¾|®çš„的含ä¹? 让我们来看一ä¸?TransactionDefinition 接口中的定义

代码
  1. /**   
  2.      * Support a current transaction, create a new one if none exists.   
  3.      * Analogous to EJB transaction attribute of the same name.   
  4.      *  < p > This is typically the default setting of a transaction definition.   
  5.      */   
  6.     int  PROPAGATION_REQUIRED  =  0 ;   
  7.   
  8.     /**   
  9.      * Support a current transaction, execute non-transactionally if none exists.   
  10.      * Analogous to EJB transaction attribute of the same name.   
  11.      *  < p > Note: For transaction managers with transaction synchronization,   
  12.      * PROPAGATION_SUPPORTS is slightly different from no transaction at all,   
  13.      * as it defines a transaction scopp that synchronization will apply for.   
  14.      * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)   
  15.      * will be shared for the entire specified scope. Note that this depends on   
  16.      * the actual synchronization configuration of the transaction manager.   
  17.      * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization   
  18.      */   
  19.     int  PROPAGATION_SUPPORTS  =  1 ;   
  20.   
  21.     /**   
  22.      * Support a current transaction, throw an exception if none exists.   
  23.      * Analogous to EJB transaction attribute of the same name.   
  24.      */   
  25.     int  PROPAGATION_MANDATORY  =  2 ;   
  26.   
  27.     /**   
  28.      * Create a new transaction, suspend the current transaction if one exists.   
  29.      * Analogous to EJB transaction attribute of the same name.   
  30.      *  < p > Note: Actual transaction suspension will not work on out-of-the-box   
  31.      * on all transaction managers. This in particular applies to JtaTransactionManager,   
  32.      * which requires the  < code > javax.transaction.TransactionManager </ code >  to be   
  33.      * made available it to it (which is server-specific in standard J2EE).   
  34.      * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager   
  35.      */   
  36.     int  PROPAGATION_REQUIRES_NEW  =  3 ;   
  37.   
  38.     /**   
  39.      * Execute non-transactionally, suspend the current transaction if one exists.   
  40.      * Analogous to EJB transaction attribute of the same name.   
  41.      *  < p > Note: Actual transaction suspension will not work on out-of-the-box   
  42.      * on all transaction managers. This in particular applies to JtaTransactionManager,   
  43.      * which requires the  < code > javax.transaction.TransactionManager </ code >  to be   
  44.      * made available it to it (which is server-specific in standard J2EE).   
  45.      * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager   
  46.      */   
  47.     int  PROPAGATION_NOT_SUPPORTED  =  4 ;   
  48.   
  49.     /**   
  50.      * Execute non-transactionally, throw an exception if a transaction exists.   
  51.      * Analogous to EJB transaction attribute of the same name.   
  52.      */   
  53.     int  PROPAGATION_NEVER  =  5 ;   
  54.   
  55.     /**   
  56.      * Execute within a nested transaction if a current transaction exists,   
  57.      * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.   
  58.      *  < p > Note: Actual creation of a nested transaction will only work on specific   
  59.      * transaction managers. Out of the box, this only applies to the JDBC   
  60.      * DataSourceTransactionManager when working on a JDBC 3.0 driver.   
  61.      * Some JTA providers might support nested transactions as well.   
  62.      * @see org.springframework.jdbc.datasource.DataSourceTransactionManager   
  63.      */   
  64.     int  PROPAGATION_NESTED  =  6 ;   

我们可以看到, åœ?spring 中一共定义了六种事务传播属æ€? 如果你觉得看èµäh¥ä¸å¤Ÿç›´è§‚, 那么我来转脓一个满大街都有的翻è¯?/p>

引用

PROPAGATION_REQUIRED -- 支持当前事务åQŒå¦‚果当前没有事务,ž®±æ–°å»ÞZ¸€ä¸ªäº‹åŠ¡ã€‚è¿™æ˜¯æœ€å¸¸è§çš„é€‰æ‹©ã€?
PROPAGATION_SUPPORTS -- 支持当前事务åQŒå¦‚果当前没有事务,ž®×ƒ»¥éžäº‹åŠ¡æ–¹å¼æ‰§è¡Œã€?
PROPAGATION_MANDATORY -- 支持当前事务åQŒå¦‚果当前没有事务,ž®±æŠ›å‡ºå¼‚常ã€?
PROPAGATION_REQUIRES_NEW -- 新徏事务åQŒå¦‚果当前存在事务,把当前事务挂赗÷€?
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作åQŒå¦‚果当前存在事务,ž®±æŠŠå½“前事务挂è“vã€?
PROPAGATION_NEVER -- 以非事务方式执行åQŒå¦‚果当前存在事务,则抛出异常ã€?
PROPAGATION_NESTED -- 如果当前存在事务åQŒåˆ™åœ¨åµŒå¥—事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED¾cÖM¼¼çš„æ“ä½œã€?
前六个策略类ä¼égºŽEJB CMTåQŒç¬¬ä¸ƒä¸ªåQˆPROPAGATION_NESTEDåQ‰æ˜¯Spring所提供的一个特ŒDŠå˜é‡ã€?
它要求事务管理器或者ä‹É用JDBC 3.0 Savepoint APIæä¾›åµŒå¥—äº‹åŠ¡è¡ŒäØ“åQˆå¦‚Springçš„DataSourceTransactionManageråQ?

在我所见过的误解中, 最常见的是下面˜q™ç§:

引用

假如有两个业务接�ServiceA �ServiceB, 其中 ServiceA 中有一个方法实现如�

/**
* 事务属性配¾|®äØ“ 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>

Juergen Hoeller 写道

PROPAGATION_REQUIRES_NEW starts a new, independent "inner" transaction for the given scope. This transaction will be committed or rolled back completely independent from the outer transaction, having its own isolation scope, its own set of locks, etc. The outer transaction will get suspended at the beginning of the inner one, and resumed once the inner one has completed.

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.

Juergen Hoeller 写道

Rolling back the entire transaction is the choice of the demarcation code/config that started the outer transaction.

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 ç‰ÒŽ€§å‘¢, 我们用代码来说话

代码
  1. ServiceA {   
  2.        
  3.      /**  
  4.      * 事务属性配¾|®äؓ PROPAGATION_REQUIRED  
  5.      */   
  6.      void  methodA() {   
  7.         ServiceB.methodB();   
  8.     }   
  9.   
  10. }   
  11.   
  12. ServiceB {   
  13.        
  14.      /**  
  15.      * 事务属性配¾|®äؓ PROPAGATION_REQUIRES_NEW  
  16.      */     
  17.      void  methodB() {   
  18.     }   
  19.        
  20. }      

˜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>

代码
  1. ServiceA {   
  2.        
  3.      /**  
  4.      * 事务属性配¾|®äؓ PROPAGATION_REQUIRED  
  5.      */   
  6.      void  methodA() {   
  7.         ServiceB.methodB();   
  8.     }   
  9.   
  10. }   
  11.   
  12. ServiceB {   
  13.        
  14.      /**  
  15.      * 事务属性配¾|®äؓ PROPAGATION_NESTED  
  16.      */     
  17.      void  methodB() {   
  18.     }   
  19.        
  20. }      

现在的情况就变得比较复杂äº? ServiceB#methodB 的事务属性被配置ä¸?PROPAGATION_NESTED, 此时两者之间又ž®†å¦‚何协作呢? ä»?Juergen Hoeller 的原话中我们可以扑ֈ°½{”案, ServiceB#methodB 如果 rollback, 那么内部事务(å?ServiceB#methodB) ž®†å›žæ»šåˆ°å®ƒæ‰§è¡Œå‰çš?SavePoint(注意, ˜q™æ˜¯æœ¬æ–‡ä¸­ç¬¬ä¸€‹Æ¡æåˆ°å®ƒ, 潜套事务中最核心的概å¿?, 而外部事åŠ?å?ServiceA#methodA) 可以有以下两¿Uå¤„理方å¼?

1. 改写 ServiceA 如下

代码
  1. ServiceA {   
  2.        
  3.      /**  
  4.      * 事务属性配¾|®äؓ PROPAGATION_REQUIRED  
  5.      */   
  6.      void  methodA() {   
  7.          try  {   
  8.             ServiceB.methodB();   
  9.         }  catch  (SomeException) {   
  10.              // 执行其他业务, 如 ServiceC.methodC();   
  11.         }   
  12.     }   
  13.   
  14. }   
  15.   

˜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. /**  
  2.  * Create a TransactionStatus for an existing transaction.  
  3.  */   
  4. private  TransactionStatus handleExistingTransaction(   
  5.         TransactionDefinition definition, Object transaction,  boolean  debugEnabled)   
  6.          throws  TransactionException {   
  7.   
  8.    ... 省略   
  9.   
  10.      if  (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {   
  11.          if  (!isNestedTransactionAllowed()) {   
  12.              throw   new  NestedTransactionNotSupportedException(   
  13.                      "Transaction manager does not allow nested transactions by default - "  +   
  14.                      "specify 'nestedTransactionAllowed' property with value 'true'" );   
  15.         }   
  16.          if  (debugEnabled) {   
  17.             logger.debug( "Creating nested transaction with name ["  + definition.getName() +  "]" );   
  18.         }   
  19.          if  (useSavepointForNestedTransaction()) {   
  20.              // Create savepoint within existing Spring-managed transaction,   
  21.              // through the SavepointManager API implemented by TransactionStatus.   
  22.              // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.   
  23.             DefaultTransactionStatus status =   
  24.                     newTransactionStatus(definition, transaction,  false ,  false , debugEnabled,  null );   
  25.             status.createAndHoldSavepoint();   
  26.              return  status;   
  27.         }   
  28.          else  {   
  29.              // Nested transaction through nested begin and commit/rollback calls.   
  30.              // Usually only for JTA: Spring synchronization might get activated here   
  31.              // in case of a pre-existing JTA transaction.   
  32.             doBegin(transaction, definition);   
  33.              boolean  newSynchronization = ( this .transactionSynchronization != SYNCHRONIZATION_NEVER);   
  34.              return  newTransactionStatus(definition, transaction,  true , newSynchronization, debugEnabled,  null );   
  35.         }   
  36.     }   
  37. }   


一目了�

1. 我们要设¾|?transactionManager çš?nestedTransactionAllowed å±žæ€§äØ“ true, 注意, æ­¤å±žæ€§é»˜è®¤äØ“ false!!!

再看 AbstractTransactionStatus#createAndHoldSavepoint() æ–ÒŽ³•

代码
  1. /**  
  2.  * Create a savepoint and hold it for the transaction.  
  3.  * @throws org.springframework.transaction.NestedTransactionNotSupportedException  
  4.  * if the underlying transaction does not support savepoints  
  5.  */  
  6. public void createAndHoldSavepoint() throws TransactionException {   
  7.     setSavepoint(getSavepointManager().createSavepoint());   
  8. }   

可以看到 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å’ŒFilterçš„url匚w…ä»¥åŠurl-pattern详解http://www.aygfsteel.com/NeonWay/archive/2006/12/21/89194.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Thu, 21 Dec 2006 01:23:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2006/12/21/89194.htmlhttp://www.aygfsteel.com/NeonWay/comments/89194.htmlhttp://www.aygfsteel.com/NeonWay/archive/2006/12/21/89194.html#Feedback0http://www.aygfsteel.com/NeonWay/comments/commentRss/89194.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/89194.html
 

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‹ï¼š

     

当一个请求发送到servlet容器的时候,容器先会ž®†è¯·æ±‚çš„urlå‡åŽ»å½“å‰åº”ç”¨ä¸Šä¸‹æ–‡çš„è·¯å¾„ä½œäØ“servlet的映ž®?/span>urlåQŒæ¯”如我讉K—®çš„æ˜¯http://localhost/test/aaa.htmlåQŒæˆ‘的应用上下文æ˜?/span>teståQŒå®¹å™¨ä¼šž®?/span>http://localhost/teståŽÀLމåQŒå‰©ä¸‹çš„/aaa.html部分拿来å?/span>servlet的映ž®„匹配。这个映ž®„匹配过½E‹æ˜¯æœ‰é¡ºåºçš„åQŒè€Œä¸”当有一ä¸?/span>servlet匚w…æˆåŠŸä»¥åŽåQŒå°±ä¸ä¼šåŽÈ†ä¼šå‰©ä¸‹çš„servlet了(filter不同åQŒåŽæ–‡ä¼šæåˆ°åQ‰ã€‚其匚w…è§„则和顺序如下:

1.     ¾_„¡¡®è·¯å¾„匚w…ã€‚例子:比如servletA çš?/span>url-patternä¸?/span> /teståQ?/span>servletBçš?/span>url-patternä¸?/span>/* åQŒè¿™ä¸ªæ—¶å€™ï¼Œå¦‚果我访问的urlä¸?/span>http://localhost/teståQŒè¿™ä¸ªæ—¶å€™å®¹å™¨å°±ä¼šå…ˆ˜q›è¡Œ¾_„¡¡®è·¯å¾„匚w…åQŒå‘çŽ?/span>/test正好è¢?/span>servletA¾_„¡¡®åŒšw…åQŒé‚£ä¹ˆå°±åŽ»è°ƒç”?/span>servletAåQŒä¹Ÿä¸ä¼šåŽÈ†ä¼šå…¶ä»–çš„servlet了ã€?/span>

2.     最长èµ\径匹配。例子:servletAçš?/span>url-patternä¸?/span>/test/*åQŒè€?/span>servletBçš?/span>url-patternä¸?/span>/test/a/*åQŒæ­¤æ—¶è®¿é—?/span>http://localhost/test/aæ—Óž¼Œå®¹å™¨ä¼šé€‰æ‹©è·¯å¾„最长的servlet来匹配,也就是这里的servletBã€?/span>

3.     扩展匚w…åQŒå¦‚æž?/span>url最后一ŒDµåŒ…含扩展,容器ž®†ä¼šæ ÒŽ®æ‰©å±•选择合适的servlet。例子:servletAçš?/span>url-patternåQ?/span>*.action

4.     如果前面三条规则都没有找åˆîC¸€ä¸?/span>servletåQŒå®¹å™¨ä¼šæ ÒŽ®url选择对应的请求资源。如果应用定义了一ä¸?/span>default servletåQŒåˆ™å®¹å™¨ä¼šå°†è¯äh±‚丢给default servletåQˆä»€ä¹ˆæ˜¯default servletåQŸåŽé¢ä¼šè®ÔŒ¼‰ã€?/span>

     æ ÒŽ®˜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

http://www.javaeye.com/topic/39332?page=1

]]>
关于¾|‘页采集http://www.aygfsteel.com/NeonWay/archive/2006/11/15/81328.html王åžR锋的技术实è·?/dc:creator>王åžR锋的技术实è·?/author>Wed, 15 Nov 2006 09:24:00 GMThttp://www.aygfsteel.com/NeonWay/archive/2006/11/15/81328.htmlhttp://www.aygfsteel.com/NeonWay/comments/81328.htmlhttp://www.aygfsteel.com/NeonWay/archive/2006/11/15/81328.html#Feedback1http://www.aygfsteel.com/NeonWay/comments/commentRss/81328.htmlhttp://www.aygfsteel.com/NeonWay/services/trackbacks/81328.htmlhttp://www.aygfsteel.com/ekinglong/archive/2006/11/12/80704.html

http://www.aygfsteel.com/ekinglong/archive/2006/10/27/77688.html

]]>
摘:SQL Server 数据行大ž®?/title><link>http://www.aygfsteel.com/NeonWay/archive/2006/11/03/78863.html</link><dc:creator>王åžR锋的技术实è·?/dc:creator><author>王åžR锋的技术实è·?/author><pubDate>Fri, 03 Nov 2006 02:20:00 GMT</pubDate><guid>http://www.aygfsteel.com/NeonWay/archive/2006/11/03/78863.html</guid><wfw:comment>http://www.aygfsteel.com/NeonWay/comments/78863.html</wfw:comment><comments>http://www.aygfsteel.com/NeonWay/archive/2006/11/03/78863.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/NeonWay/comments/commentRss/78863.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/NeonWay/services/trackbacks/78863.html</trackback:ping><description><![CDATA[ <div class="wmqeeuq" id="articleContent"> <p> <font size="2">我们看到有些数据库表中有两个字段åQŒç±»åž‹åˆ†åˆ«äØ“ varchar(8000)、varchar(8000)åQŒæˆ‘们说˜q™ç§è®¾è®¡æ˜¯é”™è¯¯çš„åQŒäؓ什么呢åQ?/font> </p> <p> <font size="2">SQL Server 存储中有个“页”的概念åQŒä¸€ä¸ªâ€œé¡µâ€æ˜¯ 8K 大小åQŒè€Œä¸€ä¸ªæ•°æ®è¡ŒåQˆä¸€æ¡è®°å½•)必须存储在一个页中,不能拆开存储在多个页中,也就是说一个数据行åQˆä¸€æ¡è®°å½•)的大ž®æœ€å¤šæ˜¯ 8KåQŒå®žé™…上ç”׃ºŽ SQL Server 的页˜q˜å…·æœ‰é¡µå¤ß_¼ŒæŸäº›¾cÕdž‹çš„å­—ŒDµè¿˜è¦é¢å¤–占用一些空é—ß_¼Œ<strong>一个数据行åQˆä¸€æ¡è®°å½•)的最大大ž®å¸¸å¸æ€¹Ÿåªæœ‰ä¸ƒåƒå¤šå­—èŠ?/strong>ã€?/font> </p> <p> <font size="2">上述表设计中一个字ŒDµå°±è¾‘Öˆ°äº?8000 字节åQŒä¸è¦è¯´ä¸€ä¸ªæ•°æ®è¡ŒåQˆä¸€æ¡è®°å½•)了ã€?/font> </p> <p> <font size="2">有ähè¯ß_¼Œæˆ‘虽然指定的æ˜?8000 字节åQŒä½†æˆ‘存储时不存储满æ€Õd¯ä»¥äº†å§ã€‚技术上是允许的åQŒä½†æ—¢ç„¶æˆ‘们用不了那么多字节åQŒäؓ什么要写那么大呢?是不是考虑我们得用 text 字段åQŒæˆ–者修改一下表¾l“æž„ã€?/font> </p> <p> <font size="2">如果一个数据行åQˆä¸€æ¡è®°å½•)­‘›_¤Ÿçš„小åQŒä¸€ä¸ªé¡µž®±å¯ä»¥å­˜å‚¨æ›´å¤šçš„æ•°æ®è¡Œï¼ˆè®°å½•åQ‰ï¼ŒSQL Server 查询时就不用¾˜Õd¤ªå¤šçš„™åµï¼ŒæŸ¥è¯¢èµäh¥ž®×ƒ¼šæ›´å¿«ã€?br /><br />引用地址åQ?a >http://www.cftea.com/c/2006/10/TNRWRCF871NS33K4.asp</a></font> </p> </div> <img src ="http://www.aygfsteel.com/NeonWay/aggbug/78863.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/NeonWay/" target="_blank">王åžR锋的技术实è·?/a> 2006-11-03 10:20 <a href="http://www.aygfsteel.com/NeonWay/archive/2006/11/03/78863.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 转-SQL Server开发äh员应聘常被问的问题妙解汇æ€?/title><link>http://www.aygfsteel.com/NeonWay/archive/2006/11/01/78415.html</link><dc:creator>王åžR锋的技术实è·?/dc:creator><author>王åžR锋的技术实è·?/author><pubDate>Wed, 01 Nov 2006 02:00:00 GMT</pubDate><guid>http://www.aygfsteel.com/NeonWay/archive/2006/11/01/78415.html</guid><wfw:comment>http://www.aygfsteel.com/NeonWay/comments/78415.html</wfw:comment><comments>http://www.aygfsteel.com/NeonWay/archive/2006/11/01/78415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/NeonWay/comments/commentRss/78415.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/NeonWay/services/trackbacks/78415.html</trackback:ping><description><![CDATA[ <div style="MARGIN-TOP: 1px; MARGIN-LEFT: 15px"> <span id="wmqeeuq" class="dark_c" style="FONT-WEIGHT: bold; FONT-SIZE: 14pt">转-SQL Server开发äh员应聘常被问的问题妙解汇æ€?</span> </div> <div style="MARGIN-TOP: 5px; MARGIN-LEFT: 15px"> <b>关键å­?</b> 工作        </div> <div style="MARGIN-TOP: 10px; MARGIN-LEFT: 15px"> <table width="100%"> <tbody> <tr> <td> <p> <br />目前在职åœÞZ¸­å¾ˆé𾿉‘Öˆ°éžå¸¸åˆæ ¼çš„æ•°æ®åº“开发äh员。我的一个同事曾¾lè¯´˜q?“SQL开发是一门语­a€åQŒå®ƒå¾ˆå®¹æ˜“å­¦åQŒä½†æ˜¯å¾ˆéš¾æŽŒæ¡ã€‚â€?/p> <p>  在面试应聘的SQL Server数据库开发äh员时åQŒæˆ‘˜qç”¨äº†ä¸€å¥—标准的基准技术问题。下面这些问题是我觉得能够真正有助于淘汰不合格应聘者的问题。它们按照从易到隄¡š„™åºåºæŽ’列。当您问到关于主键和外键的问题时åQŒåŽé¢çš„问题都十分有隑ֺ¦åQŒå› ä¸ºç­”案可能会更难解释和说明,ž®¤å…¶æ˜¯åœ¨é¢è¯•的情形下ã€?/p> <p>  您能向我½Ž€è¦å™˜qîC¸€ä¸‹SQL Server 2000中ä‹É用的一些数据库对象å?</p> <p>  您希望听到的½{”案包括˜q™æ ·ä¸€äº›å¯¹è±?表格、视图、用户定义的函数åQŒä»¥åŠå­˜å‚¨è¿‡½E?如果他们˜q˜èƒ½å¤Ÿæåˆ°åƒè§¦å‘器这æ ïLš„对象ž®±æ›´å¥½äº†ã€‚如果应聘者不能回½{”这个基本的问题åQŒé‚£ä¹ˆè¿™ä¸æ˜¯ä¸€ä¸ªå¥½å…†å¤´ã€?/p> <p>  什么是索引?SQL Server 2000里有什么类型的索引?</p> <p>  ä»ÖM½•有经验的数据库开发äh员都应该能够很轻易地回答˜q™ä¸ªé—®é¢˜ã€‚一些经验不太多的开发äh员能够回½{”这个问题,但是有些地方会说不清楚ã€?/p> <p>  ½Ž€å•地è¯ß_¼Œç´¢å¼•是一个数据结构,用来快速访问数据库表格或者视å›ùN‡Œçš„æ•°æ®ã€‚在SQL Server里,它们有两¿UåÅžå¼?聚集索引和非聚集索引。聚集烦引在索引的叶¾U§ä¿å­˜æ•°æ®ã€‚这意味着不论聚集索引里有表格的哪ä¸?或哪äº?字段åQŒè¿™äº›å­—ŒDµéƒ½ä¼šæŒ‰™åºåºè¢«ä¿å­˜åœ¨è¡¨æ ¼ã€‚由于存在这¿UæŽ’序,所以每个表格只会有一个聚集烦引。非聚集索引在烦引的叶çñ”有一个行标识½W¦ã€‚这个行标识½W¦æ˜¯ä¸€ä¸ªæŒ‡å‘磁盘上数据的指针。它允许每个表格有多个非聚集索引ã€?/p> <p>  NULL是什么意æ€?</p> <p>  NULL(½I?˜q™ä¸ªå€¼æ˜¯æ•°æ®åº“世界里一个非帔Rš¾¾~ çš„东西åQŒæ‰€ä»¥æœ‰ä¸å°‘应聘者会在这个问题上跌跟头您也不要觉得意外ã€?/p> <p>  NULL˜q™ä¸ªå€ÆD¡¨½CºUNKNOWN(未知):它不表示“â€?½Iºå­—½W¦ä¸²)。假设您的SQL Server数据库里有ANSI_NULLSåQŒå½“然在默认情况下会有,对NULL˜q™ä¸ªå€¼çš„ä»ÖM½•比较都会生äñ”一个NULL倹{€‚您不能把ä“Q何å€ég¸Žä¸€ä¸?UNKNOWN倯D¿›è¡Œæ¯”较,òq¶åœ¨é€»è¾‘上希望获得一个答案。您必须使用IS NULL操作½W¦ã€?/p> <p>  什么是主键?什么是外键?</p> <p>  主键是表格里çš?一个或多个)字段åQŒåªç”¨æ¥å®šä¹‰è¡¨æ ¼é‡Œçš„è¡?主键里的值æ€ÀL˜¯å”¯ä¸€çš„。外键是一个用来徏立两个表æ ég¹‹é—´å…³¾pȝš„¾U¦æŸã€‚è¿™¿Uå…³¾pÖM¸€èˆ¬éƒ½æ¶‰åŠä¸€ä¸ªè¡¨æ ¼é‡Œçš„主键字ŒDµä¸Žå¦å¤–一个表æ ?ž®½ç®¡å¯èƒ½æ˜¯åŒä¸€ä¸ªè¡¨æ ?里的一¾pÕdˆ—相连的字ŒDüc€‚那么这些相˜qžçš„字段ž®±æ˜¯å¤–é”®ã€?/p> <p>  什么是触发å™?SQL Server 2000有什么不同类型的触发å™?</p> <p>  让未来的数据库开发äh员知道可用的触发器类型以及如何实现它们是非常有益的ã€?/p> <p>  触发器是一¿Uä¸“用类型的存储˜q‡ç¨‹åQŒå®ƒè¢«æ†¾l‘到SQL Server 2000的表格或者视图上。在SQL Server 2000里,有INSTEAD-OFå’ŒAFTER两种触发器。INSTEAD-OF触发器是替代数据操控语言(Data Manipulation LanguageåQŒDML)语句对表格执行语句的存储˜q‡ç¨‹ã€‚例如,如果我有一个用于TableAçš„INSTEAD-OF-UPDATE触发器,同时对这个表格执行一个更新语句,那么INSTEAD-OF-UPDATE触发器里的代码会执行åQŒè€Œä¸æ˜¯æˆ‘执行的更新语句则不会执行操作ã€?/p> <p>  AFTER触发器要在DML语句在数据库里ä‹É用之后才执行。这些类型的触发器对于监视发生在数据库表格里的数据变化十分好用ã€?/p> <p>  您如何确一个带有名为Fld1字段的TableB表格里只å…ähœ‰Fld1字段里的那些å€û|¼Œè€Œè¿™äº›å€¼åŒæ—¶åœ¨åäØ“TableA的表格的Fld1字段é‡?</p> <p>  ˜q™ä¸ªä¸Žå…³¾pȝ›¸å…³çš„问题有两个可能的½{”案。第一个答æ¡?而且是您希望听到的答æ¡?是ä‹É用外键限制。外键限制用来维护引用的完整性。它被用来确保表格里的字ŒDµåªä¿å­˜æœ‰å·²¾låœ¨ä¸åŒçš?或者相同的)表格里的另一个字ŒDµé‡Œå®šä¹‰äº†çš„倹{€‚这个字ŒDµå°±æ˜¯å€™é€‰é”®(通常是另外一个表格的主键)ã€?/p> <p>  另外一¿Uç­”案是触发器。触发器可以被用来保证以另外一¿Uæ–¹å¼å®žçŽîC¸Žé™åˆ¶ç›¸åŒçš„作用,但是它非帔Rš¾è®„¡½®ä¸Žç»´æŠ¤ï¼Œè€Œä¸”性能一般都很糟¾p•。由于这个原因,微èÊY廸™®®å¼€å‘äh员ä‹É用外键限制而不是触发器来维护引用的完整性ã€?/p> <p>对一个投入ä‹É用的在线事务处理表格有过多烦引需要有什么样的性能考虑?</p> <p>  您正在寻找进行与数据操控有关的应聘äh员。对一个表格的索引­‘Šå¤šåQŒæ•°æ®åº“引擎用来更新、插入或者删除数据所需要的旉™—´ž®Þp¶Šå¤šï¼Œå› äؓ在数据操控发生的时候烦引也必须要维护ã€?/p> <p>  您可以用什么来¼‹®ä¿è¡¨æ ¼é‡Œçš„字段只接受特定范围里的å€?</p> <p>  ˜q™ä¸ªé—®é¢˜å¯ä»¥ç”¨å¤š¿Uæ–¹å¼æ¥å›žç­”åQŒä½†æ˜¯åªæœ‰ä¸€ä¸ªç­”案是“好”答案。您希望听到的回½{”是Check限制åQŒå®ƒåœ¨æ•°æ®åº“表格里被定义åQŒç”¨æ¥é™åˆ¶è¾“入该列的倹{€?/p> <p>  触发器也可以被用来限制数据库表格里的字段能够接受的å€û|¼Œä½†æ˜¯˜q™ç§åŠžæ³•è¦æ±‚è§¦å‘å™¨åœ¨è¡¨æ ¼é‡Œè¢«å®šä¹‰åQŒè¿™å¯èƒ½ä¼šåœ¨æŸäº›æƒ…况下媄响到性能。因此,微èÊY廸™®®ä½¿ç”¨Check限制而不是其他的方式来限制域的完整性ã€?/p> <p>  ˜q”回参数和OUTPUT参数之间的区别是什ä¹?</p> <p>  如果应聘者能够正¼‹®åœ°å›žç­”˜q™ä¸ªé—®é¢˜åQŒé‚£ä¹ˆä»–的机会就非常大了åQŒå› ä¸ø™¿™è¡¨æ˜Žä»–们å…ähœ‰ä½¿ç”¨å­˜å‚¨˜q‡ç¨‹çš„经验ã€?/p> <p>  ˜q”回参数æ€ÀL˜¯ç”±å­˜å‚¨è¿‡½E‹è¿”回,它用来表½Cºå­˜å‚¨è¿‡½E‹æ˜¯æˆåŠŸ˜q˜æ˜¯å¤ÞpÓ|。返回参数æ€ÀL˜¯INT数据¾cÕdž‹ã€?/p> <p>  OUTPUT参数明确要求由开发äh员来指定åQŒå®ƒå¯ä»¥˜q”回其他¾cÕdž‹çš„æ•°æ®ï¼Œä¾‹å¦‚字符型和数值型的倹{€?可以用作输出参数的数据类型是有一些限制的ã€?您可以在一个存储过½E‹é‡Œä½¿ç”¨å¤šä¸ªOUTPUT参数åQŒè€Œæ‚¨åªèƒ½å¤Ÿä‹É用一个返回参数ã€?/p> <p>  什么是相关子查è¯?如何使用˜q™äº›æŸ¥è¯¢?</p> <p>  ¾léªŒæ›´åŠ ä¸°å¯Œçš„å¼€å‘äh员将能够准确地描˜q°è¿™¿Uç±»åž‹çš„æŸ¥è¯¢ã€?/p> <p>  相关子查询是一¿UåŒ…含子查询的特ŒDŠç±»åž‹çš„æŸ¥è¯¢ã€‚查询里包含的子查询会真正请求外部查询的å€û|¼Œä»Žè€ŒåŞ成一个类ä¼égºŽå¾ªçŽ¯çš„çŠ¶å†üc€?/p> <p>  关于面试˜q‡ç¨‹çš„æ€è€?/p> <p>  ˜q™äº›é—®é¢˜åªä¸˜q‡æ˜¯¼‹®å®šä¸€ä¸ªSQL Server数据库开发äh员是否合格的èµïL‚¹ã€‚根据应聘者对上面˜q™äº›é—®é¢˜çš„回½{”情况,我可能会要求他们参加我的TSQL¾~–程考试åQŒè¿™ä¸€èˆ¬æ˜¯ä¸€å¥—根据不同情况进行的10åˆ?2个数据库查询ã€?/p> <p>  您需要自己决定将要雇用的开发äh员具有什么样的专业技能。然后,需要通过自己的经验、判断以及在面试时对应聘者的感受(来做最¾lˆå†³å®?ã€?/p> <p>  您在面试数据库开发äh员时一般会问哪些问题呢?让我们一èµäh¥è®¨è®ºä¸€ä¸‹å§ã€?/p> <p>  Tim Chapman是肯塔基州èµ\易维ž®”市一安™“¶è¡Œçš„SQL Server数据库管理员åQŒä»–有超˜q?òq´çš„行业¾léªŒã€‚ä»–˜q˜é€šè¿‡äº†å¾®è½¯SQL Server 2000å’ŒSQL Server 2005的认证ã€?</p> </td> </tr> </tbody> </table> </div>引:<a >http://jaaacky.javaeye.com/blog/31571</a><img src ="http://www.aygfsteel.com/NeonWay/aggbug/78415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/NeonWay/" target="_blank">王åžR锋的技术实è·?/a> 2006-11-01 10:00 <a href="http://www.aygfsteel.com/NeonWay/archive/2006/11/01/78415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> Ö÷Õ¾Ö©Öë³ØÄ£°å£º <a href="http://" target="_blank">ʯÃÞÏØ</a>| <a href="http://" target="_blank">ÐÂÖ£ÊÐ</a>| <a href="http://" target="_blank">Íþº£ÊÐ</a>| <a href="http://" target="_blank">»ÆÆÖÇø</a>| <a href="http://" target="_blank">ÊÙÄþÏØ</a>| <a href="http://" target="_blank">ºéÔóÏØ</a>| <a href="http://" target="_blank">ÄÒÇ«ÏØ</a>| <a href="http://" target="_blank">ͨÁÉÊÐ</a>| <a href="http://" target="_blank">³¤Í¡ÏØ</a>| <a href="http://" target="_blank">ɳÑóÏØ</a>| <a href="http://" target="_blank">ä¯ÑôÊÐ</a>| <a href="http://" target="_blank">ʦ×ÚÏØ</a>| <a href="http://" target="_blank">³¤Ñô</a>| <a href="http://" target="_blank">¾°Äþ</a>| <a href="http://" target="_blank">ãòË®ÏØ</a>| <a href="http://" target="_blank">ÇàÉñÏØ</a>| <a href="http://" target="_blank">ÖñÏªÏØ</a>| <a href="http://" target="_blank">ͨÖÝÊÐ</a>| <a href="http://" target="_blank">Â¡Ò¢ÏØ</a>| <a href="http://" target="_blank">ÄϽ§</a>| <a href="http://" target="_blank">¼½ÖÝÊÐ</a>| <a href="http://" target="_blank">½­×ÎÏØ</a>| <a href="http://" target="_blank">°Í¶«ÏØ</a>| <a href="http://" target="_blank">˳²ýÏØ</a>| <a href="http://" target="_blank">лͨÃÅÏØ</a>| <a href="http://" target="_blank">ÕØÇìÊÐ</a>| <a href="http://" target="_blank">ÖîôßÊÐ</a>| <a href="http://" target="_blank">ÆæÌ¨ÏØ</a>| <a href="http://" target="_blank">¶´¿ÚÏØ</a>| <a href="http://" target="_blank">ÐÂÓªÊÐ</a>| <a href="http://" target="_blank">äųØÏØ</a>| <a href="http://" target="_blank">ÌÁ¹ÁÇø</a>| <a href="http://" target="_blank">×ÊÐËÊÐ</a>| <a href="http://" target="_blank">¹±¾õÏØ</a>| <a href="http://" target="_blank">°¢¶ûɽÊÐ</a>| <a href="http://" target="_blank">ÈýÃÅÏ¿ÊÐ</a>| <a href="http://" target="_blank">»ªÍ¤ÏØ</a>| <a href="http://" target="_blank">±õº£ÏØ</a>| <a href="http://" target="_blank">ÐóÇÏØ</a>| <a href="http://" target="_blank">ÆÕÀ¼ÏØ</a>| <a href="http://" target="_blank">¹±É½</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>