??xml version="1.0" encoding="utf-8" standalone="yes"?> spring自徏事务理模块。而且q个事务理是一个抽象设计,可以应用到很多场合,包括普通的DataSourceQjtaQjms和hibernate上?/p> 要正用spring的事务,首先需要了解spring在事务设计上的一些概? PlatformTransactionManager直译q来是q_相关事务Q这里的q_指的是“事务源”,包括刚才我说的DataSourceQjta{等。这些无一不是一个事务源。广义的_凡是可以完成事务性操作的对象Q都可以设计出相对应的PlatformTransactionManagerQ只要这个事务源支持commitQrollback和getTransaction语意?/p> 查看spring代码Q可以发现这些manager实现事务Q就是调用事务源的事务操作方?/p> 比如 HibernateTransactionManager jdbc 的DataSourceTransactionManager 那么PlatformTransactionManager以什么依据处理事务呢Q? ȝ上面所说的Qspring的事务由PlatformTransactionManager理Qmanager最后调用事务源的方法来实现一个事务过E。而manager通过TransactionStatus 来决定如何实现? TransactionTemplate其实和spring中其他的template的作用类|起到化简代码的作用,不要被它那么长的名字吓倒了Q事实上q个templateq不是什么非常核心的对象。如果比较学I派的,可以ȝ看template设计模式Q在此就不再Ҏ赘述了? 先来看看spring reference中的一D代? 同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要Q如果利用TransactionTemplateQ那么他不管你扔Z么异帔R会回滚事务,但是回滚的是哪个事务呢?l箋挖代? 特别是在一些多事务源的E序里,q点千万不能搞错。如果多个事务源之间要完成全局事务Q还是老老实实用分布式事务管理服务吧QjtaQ?/p> 那么TransactionInterceptor是干什么的Q这个是spring 的声明式事务的支持方式。因为用TransactionTemplate要硬~码Q而且调整事务{略很麻烦(不是说不能调。D个例子原来程序抛出异常A需要回滚,现在不需要要Q我可以把a catch吃掉。这时候template׃会回滚了。但是每ơ调整都要重写编码。)而用TransactionInterceptor可以将q些调整写在配置中。我们再来挖TransactionInterceptor的代?/p> 所以用spring的事务管理需要作q些? 一、创建?br /> 好了Q知道String是非可变cM后,我们可以q一步了解String的构造方式了。创Z个Stirng对象Q主要就有以下两U方式: 虽然两个语句都是q回一个String对象的引用,但是jvm对两者的处理方式是不一L。对于第一U,jvm会马上在heap中创Z个String对象Q然后将该对象的引用q回l用戗对于第二种Qjvm首先会在内部l护的strings pool中通过String?equels Ҏ查找是对象池中是否存放有该String对象Q如果有Q则q回已有的String对象l用P而不会在heap中重新创Z个新的String对象Q如果对象池中没有该String对象Qjvm则在heap中创建新的String对象Q将其引用返回给用户Q同时将该引用添加至strings pool中。注意:使用W一U方法创建对象时Qjvm是不会主动把该对象放到strings pool里面的,除非E序调用 String的internҎ。看下面的例子: 再看下面的例子: Z么jvm可以q样处理String对象呢?是因ؓString的非可变性。既然所引用的对象一旦创建就怸更改Q那么多个引用共用一个对象时互不影响?/p> 三、String的长?br /> 我们可以使用串接操作W得C个长度更长的字符Ԍ那么QString对象最多能容纳多少字符呢?查看String的源代码我们可以得知cString中是使用?count 来记录对象字W的数量Q而count 的类型ؓ intQ因此,我们可以推测最长的长度?2^32Q也是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的Qnullg用两个字节来表示Q因此只剩下 65536Q?2 Q?65534个字节。也正是变体UTF-8的原因,如果字符串中含有中文{非ASCII字符Q那么双引号中字W的数量会更(一个中文字W占用三个字节)。如果超个数量,在编译的时候编译器会报错?/p>
abstract class和interface是Java语言中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于abstract class和interface的选择昑־比较随意。其实,两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据。?
理解抽象c?
abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?
在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的。?
在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在。?
从语法定义层面看abstract class和interface
在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式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方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class。?
从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的。?
首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个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很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了。?
同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。?
从设计理念层面看abstract class和interface
上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在。?
前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d?is a"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?is a"关系的大幅深入的论qͼ有兴的读者可以参考)。对于interface 来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明。?
考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:
使用abstract class方式定义DoorQ?
abstract class Door {
abstract void open();
abstract void close()Q?
}
使用interface方式定义DoorQ?
interface Door {
void open();
void close();
}
其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别。?
如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract 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反了面向对象设计中的一个核心原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ"报警?q个概念的改变(比如Q修改alarmҎ的参敎ͼ而改变,反之依然。?
解决Ҏ二:
既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都用abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义。?
昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明。?
如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义。?
如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是"is a"关系。所以对于Doorq个概念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"关系Qinterface表示的是"like a"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来了。 ?/font>
]]>
l观spring事务Q围l着两个核心PlatformTransactionManager和TransactionStatus
是TransactionStatus
查看api发现q个接口有三个方?
isNewTransaction() QisRollbackOnly()QsetRollbackOnly()
PlatformTransactionManager是Ҏ前两个方法决定是否要创徏一个新事务Q是要递交q是回滚。至于第三个Ҏ是改变事务当前状态的Q很多地斚w要用刎ͼ偏偏PlatformTransactionManager自n好像不怎么用,毕竟事务状态的改变是由E序员代码决定的Q不需要一个manager多管闲事?/p>
接下去说spring事务中的TransactionTemplate和TransactionInterceptor
Z么要有TransactionTemplateQ先来看看如果没有TransactionTemplateQ我们的代码该怎么?/p>
q是直接使用transactionManager的例子,可以看到真正执行business logic 的地Ҏ在try当中那段Q前后的代码都是Z完成事务理的。如果每个business logic都要写上那么一D,我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码
真相大白Q是对template所持有的某个transactionManagerq行回滚。所以如果你的应用代码用的是事务源a的一些资源,比如到服务器a的一个datasourceQ但是你的transactionManager理的是另一些资源,比如服务器b的一个datasourceQ代码铁定不会正常运?
万变不离其宗?
1Q设|好事务源,比如DataSourceQhibernate的session。如果有多个事务源要考虑他们之间是否有全局事务Q如果有Q老老实实用jtaQ否则就需要自己写一个manager?
2Q设|managerQ根据你的事务源选择对应的PlatformTransactionManager
3Q选择实现事物的方式,用templateq是interceptor。用template代码直观点,但是template所辖的manager和你应用代码所用的事务源要一致。如果用interceptor千万注意Q一定要调用interceptor那个beanQ而不是原始的那个target。在坛子上我已经看到臛_有两个朋友说spring事物不v作用Q从配置和代码上看都正确Q这时要好好查查Q调用的bean是哪一个?
4Q这个是设计问题了,推荐事务处于一个较高层ơ,比如service上的某个函数Q而底层的dao可以不考虑事务Q否则可能会出现事务嵌套Q增加程序复杂度?/p>
要理?java中String的运作方式,必须明确一点:String是一个非可变c(immutableQ。什么是非可变类呢?单说来,非可变类的实例是不能被修改的Q每个实例中包含的信息都必须在该实例创徏的时候就提供出来Qƈ且在对象的整个生存周期内固定不变。javaZ么要把String设计为非可变cdQ你可以问问 james Gosling Q)。但是非可变cȝ实有着自n的优势,如状态单一Q对象简单,便于l护。其ơ,该类对象对象本质上是U程安全的,不要求同步。此外用户可以共享非可变对象Q甚臛_以共享它们的内部信息。(详见 《Effective java》item 13Q。Stringcdjava中被大量q用Q甚臛_class文g中都有其w媄Q因此将其设计ؓ单轻便的非可变类是比较合适的?
二、串接(ConcatenationQ?br /> javaE序员应该都知道滥用String的串接操作符是会影响E序的性能的。性能问题从何而来呢?归根l底是Stringcȝ非可变性。既然String对象都是非可变的Q也是对象一旦创Z׃能够改变其内在状态了Q但是串接操作明显是要增长字W串的,也就是要改变String的内部状态,两者出C矛盾。怎么办呢Q要l护String的非可变性,只好在串接完成后新徏一个String 对象来表C新产生的字W串了。也是_每一ơ执行串接操作都会导致新对象的生,如果串接操作执行很频J,׃D大量对象的创建,性能问题也就随之而来了?br /> Z解决q个问题Qjdk为StringcL供了一个可变的配套c,StringBuffer。用StringBuffer对象Q由于该cL可变的,串接时仅仅时改变了内部数据结构,而不会创建新的对象,因此性能上有很大的提高。针对单U程Qjdk 5.0q提供了StringBuilderc,在单U程环境下,׃不用考虑同步问题Q用该cM性能得到q一步的提高?/p>
解惑 spring 嵌套事务
/**
* @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点QPROPAGATION_REQUIRED 已经说得很明?
如果当前U程中已l存在事? Ҏ调用会加入此事务, 果当前没有事务,新Z个事? 所?ServiceB#methodB() 的事务只要遵循最普通的规则配置?PROPAGATION_REQUIRED 卛_, 如果 ServiceB#methodB (我们UC为内部事? Z文打下基) 抛了异常, 那么 ServiceA#methodA(我们UC为外部事? 如果没有Ҏ配置此异常时事务提交 (?+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值的地方, 它vC分支执行的效? 如果 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-patternq是有一些文章在里面的,ȝ了一些东西,攑և来供大家参考,以免遇到问题又要费旉?/span> 一Q?/font>servlet容器?/span>url的匹配过E:
Ҏq个规则表,p很清楚的知道servlet的匹配过E,所以定?/span>servlet的时候也要考虑url-pattern的写法,以免出错?/span> 对于filterQ不会像servlet那样只匹配一?/span>servletQ因?/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 |
我们看到有些数据库表中有两个字段Q类型分别ؓ varchar(8000)、varchar(8000)Q我们说q种设计是错误的Qؓ什么呢Q?/font>
SQL Server 存储中有个“页”的概念Q一个“页”是 8K 大小Q而一个数据行Q一条记录)必须存储在一个页中,不能拆开存储在多个页中,也就是说一个数据行Q一条记录)的大最多是 8KQ实际上׃ SQL Server 的页q具有页_某些cd的字D还要额外占用一些空_一个数据行Q一条记录)的最大大常怹只有七千多字?/strong>?/font>
上述表设计中一个字D就辑ֈ?8000 字节Q不要说一个数据行Q一条记录)了?/font>
有h_我虽然指定的?8000 字节Q但我存储时不存储满d以了吧。技术上是允许的Q但既然我们用不了那么多字节Qؓ什么要写那么大呢?是不是考虑我们得用 text 字段Q或者修改一下表l构?/font>
如果一个数据行Q一条记录)_的小Q一个页可以存储更多的数据行(记录Q,SQL Server 查询时就不用d多的,查询h׃更快?br />
引用地址Q?a >http://www.cftea.com/c/2006/10/TNRWRCF871NS33K4.asp
在面试应聘的SQL Server数据库开发h员时Q我q用了一套标准的基准技术问题。下面这些问题是我觉得能够真正有助于淘汰不合格应聘者的问题。它们按照从易到隄序排列。当您问到关于主键和外键的问题时Q后面的问题都十分有隑ֺQ因为答案可能会更难解释和说明,其是在面试的情形下?/p> 您能向我要叙qC下SQL Server 2000中用的一些数据库对象? 您希望听到的{案包括q样一些对?表格、视图、用户定义的函数Q以及存储过E?如果他们q能够提到像触发器这L对象更好了。如果应聘者不能回{这个基本的问题Q那么这不是一个好兆头?/p> 什么是索引?SQL Server 2000里有什么类型的索引? M有经验的数据库开发h员都应该能够很轻易地回答q个问题。一些经验不太多的开发h员能够回{这个问题,但是有些地方会说不清楚?/p> 单地_索引是一个数据结构,用来快速访问数据库表格或者视N的数据。在SQL Server里,它们有两UŞ?聚集索引和非聚集索引。聚集烦引在索引的叶U保存数据。这意味着不论聚集索引里有表格的哪?或哪?字段Q这些字D都会按序被保存在表格。由于存在这U排序,所以每个表格只会有一个聚集烦引。非聚集索引在烦引的叶有一个行标识W。这个行标识W是一个指向磁盘上数据的指针。它允许每个表格有多个非聚集索引?/p> NULL是什么意? NULL(I?q个值是数据库世界里一个非帔R~的东西Q所以有不少应聘者会在这个问题上跌跟头您也不要觉得意外?/p> NULLq个DCUNKNOWN(未知):它不表示“?I字W串)。假设您的SQL Server数据库里有ANSI_NULLSQ当然在默认情况下会有,对NULLq个值的M比较都会生一个NULL倹{您不能把Q何g一?UNKNOWND行比较,q在逻辑上希望获得一个答案。您必须使用IS NULL操作W?/p> 什么是主键?什么是外键? 主键是表格里?一个或多个)字段Q只用来定义表格里的?主键里的值L唯一的。外键是一个用来徏立两个表g间关pȝU束。这U关pM般都涉及一个表格里的主键字D与另外一个表?管可能是同一个表?里的一pd相连的字Dc那么这些相q的字段是外键?/p> 什么是触发?SQL Server 2000有什么不同类型的触发? 让未来的数据库开发h员知道可用的触发器类型以及如何实现它们是非常有益的?/p> 触发器是一U专用类型的存储q程Q它被捆l到SQL Server 2000的表格或者视图上。在SQL Server 2000里,有INSTEAD-OF和AFTER两种触发器。INSTEAD-OF触发器是替代数据操控语言(Data Manipulation LanguageQDML)语句对表格执行语句的存储q程。例如,如果我有一个用于TableA的INSTEAD-OF-UPDATE触发器,同时对这个表格执行一个更新语句,那么INSTEAD-OF-UPDATE触发器里的代码会执行Q而不是我执行的更新语句则不会执行操作?/p> AFTER触发器要在DML语句在数据库里用之后才执行。这些类型的触发器对于监视发生在数据库表格里的数据变化十分好用?/p> 您如何确一个带有名为Fld1字段的TableB表格里只hFld1字段里的那些|而这些值同时在名ؓTableA的表格的Fld1字段? q个与关pȝ关的问题有两个可能的{案。第一个答?而且是您希望听到的答?是用外键限制。外键限制用来维护引用的完整性。它被用来确保表格里的字D只保存有已l在不同?或者相同的)表格里的另一个字D里定义了的倹{这个字D就是候选键(通常是另外一个表格的主键)?/p> 另外一U答案是触发器。触发器可以被用来保证以另外一U方式实C限制相同的作用,但是它非帔R讄与维护,而且性能一般都很糟p。由于这个原因,微Y开发h员用外键限制而不是触发器来维护引用的完整性?/p> 对一个投入用的在线事务处理表格有过多烦引需要有什么样的性能考虑? 您正在寻找进行与数据操控有关的应聘h员。对一个表格的索引多Q数据库引擎用来更新、插入或者删除数据所需要的旉p多,因ؓ在数据操控发生的时候烦引也必须要维护?/p> 您可以用什么来保表格里的字段只接受特定范围里的? q个问题可以用多U方式来回答Q但是只有一个答案是“好”答案。您希望听到的回{是Check限制Q它在数据库表格里被定义Q用来限制输入该列的倹{?/p> 触发器也可以被用来限制数据库表格里的字段能够接受的|但是q种办法要求触发器在表格里被定义Q这可能会在某些情况下媄响到性能。因此,微Y使用Check限制而不是其他的方式来限制域的完整性?/p> q回参数和OUTPUT参数之间的区别是什? 如果应聘者能够正地回答q个问题Q那么他的机会就非常大了Q因表明他们h使用存储q程的经验?/p> q回参数L由存储过E返回,它用来表C存储过E是成功q是p|。返回参数LINT数据cd?/p> OUTPUT参数明确要求由开发h员来指定Q它可以q回其他cd的数据,例如字符型和数值型的倹{?可以用作输出参数的数据类型是有一些限制的?您可以在一个存储过E里使用多个OUTPUT参数Q而您只能够用一个返回参数?/p> 什么是相关子查?如何使用q些查询? l验更加丰富的开发h员将能够准确地描q这U类型的查询?/p> 相关子查询是一U包含子查询的特D类型的查询。查询里包含的子查询会真正请求外部查询的|从而Ş成一个类g循环的状c?/p> 关于面试q程的思?/p> q些问题只不q是定一个SQL Server数据库开发h员是否合格的L。根据应聘者对上面q些问题的回{情况,我可能会要求他们参加我的TSQL~程考试Q这一般是一套根据不同情况进行的10?2个数据库查询?/p> 您需要自己决定将要雇用的开发h员具有什么样的专业技能。然后,需要通过自己的经验、判断以及在面试时对应聘者的感受(来做最l决??/p> 您在面试数据库开发h员时一般会问哪些问题呢?让我们一h讨论一下吧?/p> Tim Chapman是肯塔基州\易维市一安行的SQL Server数据库管理员Q他有超q?q的行业l验。他q通过了微软SQL Server 2000和SQL Server 2005的认证? |