使用“简单文件共享”一点不简单!

因为懒惰,所以一直没有解决一个问题。我的苹果一直不能访问家里的台式机,但是家里的台式机实际上是我家的文件中心,在已经卸下两块硬盘的情况下,这台机器上还有320X2+250+120=1010G的硬盘空间。我从用笔记本看电影的时候希望可以访问Windows的共享目录,但是却每次都提示您没有权限访问文件共享。可是我已经为苹果设好特别的帐号了,非常费解。但是在苹果上访问别的Windows电脑却正常。
百思不得其解,但是最终还是解决了。不废话,说方法,我的是Windows XP SP2:
1、去Windows上,在我的电脑的工具-设置里面,取消“使用简单文件共享(推荐)”这个选项。
2、这个时候再去共享目录或者驱动器根的时候你就可以选择帐户和连接数了。选择你要使用的帐户,加入到授权访问的帐户列表中去,即使里面已经有Everyone了。
3、去苹果上在浏览器(如Safari)里面输入smb:\\192.168.1.x,或者直接在Finder里面选择相应的主机名。这个时候会询问你帐号和密码,然后输入你在Windows上面的帐号就可以了。

怀疑原因是我的Windows正好出了什么毛病,我的新帐户可能也许不在Everyone里面,虽然不应该,但是不管它了,你完全可以将目录的访问授权只给特定的用户,如我的电脑上有个mac用户,使用密码保护,这样可能更加明确。
那么,反正这次的麻烦就归在倒霉的“简单文件共享”上免了,它一点也不简单!

硬盘容量的变迁

这两天收拾硬盘,发现以前的分区方式已经不能满足我了。
此时,我已经有120G x 3,和80G x 1了,再加上单位暂借的160G,组成比较大的硬盘阵营了,不过显然过气了。还好我有Promise Ultra 100的IDE卡,否则虽然总容量不算大,但是硬盘量可不少了。
原先的120G分别有5、4、3个分区,而新的160G则只有1个分区。现在的数据有很多ISO,容量巨大,再加上Mp3的爆炸,多个小分区不好用了,所以这两天花了不少时间整理这些硬盘,把该合并整理的都处理了。
然后就是腾空、重新分区,我对PQ的PargitionMagic有心理阴影,不要推荐这类软件给我。整理的成果让我很满足,我渐渐变得有条理了,紊乱会被消灭的。
瓦卡卡!

生活的效率,累的是谁?

发现MSN Spaces升级了,满好玩的,不过好像是有Bug的,目前带着自己的信息给别人留言还有问题。
如何提高效率呢?
1、最好要有一个可以移动的工作平台。或者自己总结一个回复工作平台的步骤。自己经常对自己所做的事情做记录,并分享。
2、关于信息的获取,除了使用搜索引擎,还可以考虑订阅RSS。通过FeedDeamon这样的Rss阅读器,可以定义自己的频道,在里面收藏关注的站点(尤其是技术Blog),如此通过适时的跟踪,可以保证信息获取的及时。
3、使用一个文章收藏工具,如CyberArticle(网文快捕)。通过它的分类收藏功能,可以将自己关注或者有用的技术文章保存下来,并且可以方便的制作电子书。它的最大优点是可以将你所有的技术文章(网页)保存为一个统一的book文件,方便管理和备份。
4、掌握一个拿手的编辑器。用Windows的朋友可能习惯使用NotePad(记事本),但是它并不怎么好用。推荐习惯UltraEdit或者EditPlus这样的强大的编辑器的功能,使用批量替换,字符显示,文件编码等问题的解决(如果感兴趣,用UltraEdit的16进制编辑功能可以帮你发现更多的隐藏的编码问题)。我偏好EditPlus……
5、这个年代要掌握eMule和BT的基本使用方法。BT对于获得流行的资源非常有帮助,而eMule则对获得非流行的资源(如eBook、冷门mp3等)非常重要。注意不少eMule Client有积分,注意积攒,对排队有效。
6、如果你还没有Blog,最好有一个,可以催促你积累和共享你的收获。
祝大家新春快乐,狗年吉祥!

java中的String的encoding和下载文件的jsp例子

晚上跟zh等同志一起看了下文件下载的中文问题,问题解决,并且收获不小:
1、java的char类型是16bit,而不是c/c++中的8bit,所以char和byte之间的转换会造成严重的精度损失。而Java的char是Unicode的。
2、java中String是基于char[]的,也就是说这个String天生就可以表示Unicode。所以如果从byte[]创建一个String就会涉及到一个严重的策略问题,是一个byte转一个String字还是两个byte转一个String字。
3、所以我们常用的java转码中的语句somestr = new String(somestr.getBytes(),"ISO-8859-1")与somestr = new String(somestr.getBytes(),"GB2312")之间是有很大区别的,它们关系到从一个byte变两个byte或反过来。
4、所以,对于单精度的"ISO-8859-1"与双精度的GB2312、GBK、utf-8处理的时候一定要分清,而且它也可以解决很多的问题。而如果你好好了解GB2312与GBK的效果其实很类似,他们只有部分的编码覆盖度上的区别,大部分字符是通用的,可是"ISO-8859-1"却与他们完全不同。
5、还有一个有意思的地方:java.io.Writer与java.io.InputStream下面的东西有个明显的区别,前者接受char[],而后者接受byte[]。其实理解一下,他们之间的转换其实正好需要String的单字节编码与双字节编码的区别,我们可以用它们完成有意思的转换。在它们的沟通过程中我们如果使用buffer,则需要String作为中间者进行转换,算个小trick吧。
6、从这里,我们引出今天解决的中文文件下载的问题中的有意思的地方:
<%@ page language="java" import="java.io.PrintWriter"
%><%
String filename = (String)request.getAttribute("downloadFileName");
String filepath = (String)request.getAttribute("downloadFileUrl");

filename = new String(filename.getBytes(),"ISO-8859-1");
if(filename != null && filepath != null) {
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename + "\"");
java.io.FileInputStream fileInputStream =
new java.io.FileInputStream(filepath);

java.io.File file = new java.io.File(filepath);
response.setContentLength((new Long(file.length()).intValue()));
PrintWriter pw = response.getWriter();
byte[] charArray = new byte[4096];
int len;
while ((len=fileInputStream.read(charArray)) != -1) {
 String s = new String(charArray,"ISO-8859-1");
 pw.write(s);
}
pw.flush();
pw.close();
fileInputStream.close();
}
%>

webork2与spring的autowire配合的trick

今天,又看了下上面这个例子里面的starter那个例子,发现:
它使用了Spring的自动装配,以下两段代码效果相同:
java代码: 

<beans default-autowire="autodetect">
        <bean id="personManager" class="com.acme.PersonManager"/>
</beans>

java代码: 

<beans>
        <bean id="personManager" class="com.acme.PersonManager"/>
        <bean id="listPeople" class="com.acme.ListPeople">
                <property name="personManager" >
                        <ref local="personManager" />
                </property>
        </bean>
        <bean id="createPserson" class="com.acme.CreatePerson">
                <property name="personManager">
                        <ref local="personManager" />
                </property>
        </bean>
</beans>

如果这样使用的话,如果在xwork里面配制好action的class,然后连这个class的bean都不用在spring里面声明了,其依赖也通过名字匹配自动装配了。
真简单啊,想知道spring的autowire有没有性能损耗,如果每次装配都反射会不会性能很差?

webwork 2.2 中如何给Collection赋值

原本javaeye有这么一篇帖子“在WebWork2 Action中如何自动设置Array、List、Map”,是moxie大哥写的。
http://forum.javaeye.com/viewtopic.php?t=8770

但是已经是2004年11月的文章了,在webwork 2.2 b4中,XWorkList和XWorkMap已经是deprecated状态了,当时我就一头雾水,也没找到什么好的线索。
去java.net下载了XWork的最新代码,看到了其中的注释,说这个工作已经可以自动完成了。
又几经周折,才算搞明白先在如何让List、Map等工作起来:

下面简单介绍一下:
1、如果要将值映射到pojo的collection,则需要使用conversion功能。
如我又一个Action,叫testAction:
public class testAction extends ActionSupport {
 private Collection smoeAttrs = null;(使用webwork自动负值,应有对应getter和setter)
 private IDeptJgzTjkEcoAttDAO ecoAttDAO = null;(改DAO使用Spring注入,应有相应setter)

     public String execute() throws Exception {
         if (log.isDebugEnabled()) {
   log.debug("performing execute() method!");
         }

  //持久化collection里面的pojo
  for (Iterator iterator = smoeAttrs.iterator(); iterator.hasNext();) {
              SomeAttr someAttr = (SomeAttr) iterator.next();
              ecoAttDAO.saveOrUpdate(someAttr, someAttr.getId());
         }

         return Action.SUCCESS;
     }
}

对应一个pojo:
package org.tin.test;

public class SomeAttr implements Serializable {

 /** The composite primary key value. */
 private java.lang.Long id;

 private java.lang.Float fild1;
 private java.lang.String fild2;
 private java.util.Date fild3;

 /*
  ….
  对应的getter和setter
 */
}

可以看到,上面的Action声明的时候没有任何涉及到XWorkList的地方(moxie介绍的那种风格),也就是说现在webwork并不知道Collection里面放的pojo的类型。这就是Webwork目前的高明之处,这样的代码非常干净。但是如果要自动设定Collection的值,访问到这些Pojo,则一定要知道Pojo的类型,Webwork如何做呢?
通过-conversion配置。
需要在对应该才那个testAction.java的相同目录写一个testAction-conversion.properties文件(格式就是Action名字+“-conversion.properties”)。
文件里面注明:
Element_someAttrs = org.tin.test.SomeAttr (以前版本曾经用过Collection、Map分开,但是现在不管什么类型,都用Element)
格式就是“Element_”+Action中Collection的名字+“=”+你的pojo的完整类名

如此配置后,自动设置值的时候就可以知道你的pojo的类型了,很干净。

下面一小段由于我接触Webwork不久,所以是个很初级的经验,如果需要则自取:
回忆moxie帖子中的重要的部分,在post到相应action的页面的form中,input要遵循这样的命名:
对应刚才所说的那个pojo:
<form>
 <input  name="someAttrs[0].fild1" value="45555.6" id="xxx11" />
 <input  name="someAttrs[0].fild2" value="test" id="xxx12" />
 <input  name="someAttrs[0].fild3" value="2006-01-05" id="xxx13" />
 <input  name="someAttrs[1].fild1" value="45555.6" id="xxx21" />
 <input  name="someAttrs[1].fild2" value="test" id="xxx22" />
 <input  name="someAttrs[1].fild3" value="2006-01-05" id="xxx23" />
 <input  name="someAttrs[2].fild1" value="45555.6" id="xxx31" />
 <input  name="someAttrs[2].fild2" value="test" id="xxx32" />
 <input  name="someAttrs[2].fild3" value="2006-01-05" id="xxx33" />
</form>

如何输出?很简单,在列表页中:
<ww:iterator value="someAttrs" status="someAttrsIter">
<tr>
 <td>
  <ww:hidden name="someAttrs[%{#someAttrsIter.index}].id" value="%{id}"/>
  <ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild1" value="%{fild1}"/></td>
 <td><ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild2 value="%{fild2}"/></td>
 <td><ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild3" value="%{fild3}"/></td>
</tr>
</ww:iterator>

即可以,因为iteratror这个tag支持iteratroStatus这个东西,用它可以获取index、isOdd等信息,很方便。

配合
<action name="saveAction" class="testAction">
 <result name="success" type="redirect">/loadByInf.action?id=${someAttrOwner.id}</result>
</action>

则很容易的实现对Collection的CRUD。正好用到了ONGL的集中基本访问方式:#、%{}、${}

以上内容,错漏难免。因为今天终于可以偷闲,赶紧结绳记之。欢迎大家讨论更简便的方法。

eXtremeComponent在中文环境下的使用

不知道大家是否使用过eXtremeComponent,我刚才在java eye没有搜索到。
最早知道eXtremeComponent是从www.open-open.com,去年就在用了,感觉明显比display-tag要好用多了。
它使用jstl,所以与webwork集成也很方便,不象display-tag那样需要把hibernate返回的collection复制一遍再访问。

具体的使用方法参考官方网站好了:
官方网站在这里:
http://www.extremecomponents.org/extremesite/welcome.jsp
最新的版本是1.0.1-M4-A14,可以到这里下载:
http://www.extremecomponents.org/extremesite/public/download/
或者直接下载:
http://www.extremecomponents.org/extremesite/public/download/extremecomponents-1.0.1-M4-A14.zip
但是这个snapshot版本没有依赖lib和资源文件等,推荐去这里下一个完整版本备用,目前最新的Production Release包是eXtremeComponents-1.0.1-M3-with-dependencies.zip:
https://sourceforge.net/project/showfiles.php?group_id=108168
最新版本的说明书在这里,说明书用的doc book格式,写的也很清楚:
http://www.extremecomponents.org/extremesite/public/download/eXtremeComponents.pdf
很多人都对他使用的doc book声称doc感兴趣,spring和hibernate都用doc book,可是一般看不到源文件。作者很慷慨将doc book的源文件也分享了,是学习是学习使用doc book的好东西:
http://www.extremecomponents.org/extremesite/public/download/generate-docs.zip

资源就贴到这里,这里要提及作者Jeff Johnston人非常热情,论坛上四处可见他的身影,给他发信他也是每信必会、有求必应,承蒙他多次帮助。而且论坛中大家多次提及中文问题,他也很重视。

转入正题:
我贴一下一个例子:
 <ec:table
 items="ecoAttrs"
 action="/jgz/tjk/eco/listTjkAttByInfId.action"
 imagePath="${pageContext.request.contextPath}/css/table/zh_CN/*.gif"
 cellpadding="1"
 title="农村经济运行情况列表"
 locale="zh_CN"
 rowsDisplayed="30">
  <ec:export view="xls" fileName="jgz_zyjjzbwcqk.xls" tooltip="输出Excel文件"/>
  <ec:exportPdf fileName="jgz_zyjjzbwcqk.pdf" tooltip="输出PDF文件" headerColor="blue" headerBackgroundColor="red" headerTitle="密云县农村经济月份经济主要指标完成情况表"/>
  <ec:exportCsv fileName="jgz_zyjjzbwcqk.txt" tooltip="输出CSV文件" delimiter="|"/>
  <ec:row>
   <ec:column property="ofTown.name" title="乡镇名称"/>
   <ec:column property="ncJihua" title="农村计划"/>
   <ec:column property="ncWancheng" title="农村完成"/>
   <ec:column property="ncQunian" title="农村去年"/>
   <ec:column property="zongShouRuWCJH" title="完成计划%"/>
   <ec:column property="zongShouRuTB" title="同比+/-%"/>
  </ec:row>
 </ec:table>

其中ecoAttrs是一个collection,放入pojo。action里面写你这个页面的访问方法(如我的页面是一个action,其他的如.do或者.jsp什么的都可以)。rowsDisplayed是默认显示条数,它可以自动实现分页。
下面的三个<ec:export>是导出三种格式用的,不用的话可以不写(写了需要在web.xml配置相应的filter)。
<ec:column>里面放属性,property指向pojo的相应属性,而title是表头显示的信息,这个标签需要用<ec:row>包起来(1.0.1 m4以后)(抱歉pojo比较丑,出自同事之手)。

这里放一套我做的中文图标:
http://tiny.51.net/extremecomponent/zh_CN.rar
还有我该写了一下css,更适合使用中文,将字体该为%大小,可以定义.eXtremeTable里面的font-size,即影响所有eXtremeTable里面的字体大小,也方便写js来动态修改大小:
http://tiny.51.net/extremecomponent/extremecomponents.css

贴一下我在web.xml里面的配置:
<filter>
 <filter-name>eXtremeExport</filter-name>
 <filter-class>
  org.extremecomponents.table.filter.ExportFilter
 </filter-class>
</filter>

<filter-mapping>
 <filter-name>eXtremeExport</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

<taglib>
 <taglib-uri>/extremecomponents</taglib-uri>
 <taglib-location>/WEB-INF/tld/extremecomponents.tld</taglib-location><!– 别忘了把那个tld拷贝到相应目录去 –>
</taglib>

其实,那个filter只是在使用<ec:export>的时候才需要,不过这个功能还是很有用的。

export里面的excel和pdf默认不支持中文,需要手工修改源码,excel的比较简单:
修改org.extremecomponents.table.view.XlsView.java(我指的是1.0.1-M4-A14的相应代码)
102行:
HSSFCell hssfCell = hssfRow.createCell(cellnum);
hssfCell.setEncoding(HSSFCell.ENCODING_UTF_16);(就是添加这一行)
122行:
HSSFCell cell = row.createCell(cellnum);
cell.setEncoding(HSSFCell.ENCODING_UTF_16);(就是添加这一行)
这个在使用UTF-8时工作正常。如果其他Unicode环境可以尝试HSSFCell.ENCODING_COMPRESSED_UNICODE。

编译后将对应.class放到WEB-INF/classes相应目录就可以了。

pdf view的比较麻烦,还没尝试,解决方法参照这个帖子:
http://extremecomponents.org/forum/viewtopic.php?t=139&highlight=chinese+filter
http://www-128.ibm.com/developerworks/cn/xml/x-ospdf/index.html

还有一小点:
升级到1.0.1-M4-A14以后两个图片改名了,如果用1.0.1-M3的对应gif则需要该如下两个文件名(我修改的那个ZH-CN已经重命名过了):
searchArrow.gif -> filterArrow.gif
search.gif -> filter.gif

说的比较罗嗦,主要是想让和我一样的非常初级水平的朋友能够比较容易上手。其实eXtremeComponent的文档很不错,用那个上手其实更好,我仅抛砖引玉,各位大虾多多包涵。

Webwork 2.2 b5中datapicker的本地化使用方法

仅作为记录,尽量简明:
1、我使用Weblogic 8.1 SP5+Webwork 2.2 beta 5。2.2b5的Webwork已经完全转向使用jscalendar作为datapicker的js,而不是以前的tigracalendar,因为tigracalendar不支持国际化。Web项目使用FilterDispatcher,本应改可以将/webwork/*的请求拦截下来,但是它工做不正常。所以我把webwork.jar里面的\com\opensymphony\webwork\static目录拷贝到Web根目录,并将static目录重名名为webwork。
此时,你的Web根目录下面应有一个名为webwork的目录,里面有jscalendar、dojo、niftycorners这几个文件加,如果不需要其它的,可以只保留jscalendar一个目录。
2、在需要显示datapicker的地方使用如下标记<ww:datepicker name="ecoInf.turninDate" id="ecoInf.turninDate" template="datepicker.ftl" language="cn_utf8" format="%Y-%m-%d %H:%M:%S" showstime="true" />。
其中template完全可以不写。而name标明你的数据的来源。id是方便javascript访问所保留的,可以和name相同(如果有重复name,如经过iterator,则需要区别其id,保持id在html dom中唯一)。
showstime标明是否可以选择时间,可以是"true","false","24","12"。
language决定jscalendar使用的语言,参照下面说明。
3、language指定的语言其实就对应jscalendar/lang下面的语言文件,格式就是calendar-语言名.js,默认的中文使用的是zh。但是其实j2ee项目经常面对中文乱码问题,最佳解决方案就是统一使用UTF-8。但是calendar-zh.js正好不是UTF-8的,所以如果直接使用zh语言则datapicker没法正常工作。
我的解决方法是将webwork附带的jscalendar 1.0的lang里面的cn_utf8.js改名为calendar-cn_utf8.js,然后将language="cn_utf8"就工作正常了。
4、关于时间的显示格式。其实cn_utf8.js里面已经制定了时间的标准显示格式是%Y-%m-%d,符合我们的习惯。但是有时我们需要显示具体时间,参照他们网站的说明,使用format="%Y-%m-%d %H:%M:%S",这个也符合我们的习惯。
发个牢骚:
本来奇简单。但是很奇怪/webwork/*居然不能在Weblogic下自动映射,我一会而去试验下Tomcat,还有就是js解析utf-8出错造成整个js没法工作,浪费了半天时间,唉。

Spring 2.0和给贫血模型充血

Spring 2.0 vs. the Anemic Domain Model
原来是因为老马骂了贫血模型为反模式,说冲血模型才是最好的,能够真正的OO。
不过Spring 2.0的概念被骂了个体无完肤。
本身,我的立场从来就没有站在OO这一边,我是真的无所谓的人,什么过程、OO、FP我都很认同,当然能优雅些是最好的。
看了以后就想到WQH前两天就已经推荐给我的ajoo写的充血模型的问题,我才意识到QH大师又走在我们前头了!
看了下javaeye上贫血/充血的讨论,才豁然开朗。
知道为什么冲突就对了。关键点还是在争吵OO,而OO在领域模型方面有时适合充血有时适合贫血,当然贫血居多,所以举起例子总是两边倒,没有定论。
还好,抽出重要部分,对于基本CRUD,那么绝对是贫血模型就好了。而对于有复杂计算的领域模型,我们要建立一个完备的OO的领域模型则需要充血。
这提醒了我们,充血的确是需要的。不过给Hibernate下的POJO(明显贫血到死)充血并不容易,所以才有了更多的文章讨论这个问题。
记录下来,大家有兴趣一起研究:
TSS:Spring 2.0 vs. the Anemic Domain Model
http://www.theserverside.com/news/thread.tss?thread_id=38047
Javaeye论坛:贫血就贫血,咂地?
http://www.hibernate.org.cn/viewtopic.php?p=100045&sid=df2163b2c94afbb6b214da6b3be42d73
ajoo在javaeye的conflunce上写的:怎样给马丁的充血域对象注射依赖
ajoo一文的后篇:http://www.javaeye.com/display/ajoo/Dependency+Injection+For+Rich+Domain+Model
对程序员透明的非aop方法解决rich domain object的依赖注射
http://www.javaeye.com/display/ajoo/Transparent+Dependency+Injection+For+Rich+Domain+Model
Codehaus上的一个解决方案:Dependency Injection For Rich Domain Objects
http://docs.codehaus.org/display/YAN/Dependency+Injection+For+Rich+Domain+Objects
老马写的批评贫血模型的檄文:AnemicDomainModel
http://www.martinfowler.com/bliki/AnemicDomainModel.html
Spring Blog上的原文:Spring 2.0 vs. the Anemic Domain Model
http://jroller.com/page/habuma?entry=spring_2_0_vs_the
我个人认为POJO还有DTO都是简单的VO,而VO就是VO,要区别于Real Object。我们的domain里面大都是VO而不是RO。Hibernate也是基于VO的,EJB3同样。所以RO应该说是理想OO下的东西,我们真正要用的时候,还是可以自己选择是否要实现这种复杂的东西的。但是不用RO则我们的程序就变得过程化。所以老马也认为这是头疼的事,但又不要解决,只能放到他的TODO list里面了,哈哈。
哈哈,但是看完Spring的那个Blog,感觉Spring 2.0做好了解决多向以来的模型的方法是很不错的,当然是由解决给贫血模型充血引发的,但是我认为它还能解决其它问题,所以感觉不错。但是Spring 2.0再次强调Aop的好处,也的确能看到,所以有时间还要学习一下AspectJ。
而这个问题ajoo说了IoC和Aop都可以解决,感觉各有道理。IoC方式感觉代码容易读懂,也合理。而Aop则代码有点牵强,当然使用起来感觉很爽,尤其和Lazy-init结合,对生存周期的控制有它读到的地方,而且想明白了用Aop+Annotation感觉也很清楚优雅。

关于事务的满脑袋酱子,解惑:本地、JTA、CMT

传统上J2EE有两种事务管理策略:全局或者本地事务
全局的由app server保证,如JTA。而本地则是针对某种资源的,如JDBC连接的事务。
其中,全局事务是为了保证多种事务资源的共同工作。但是如果是用本地的事务,则容器(app server)无法保证跨资源的事务。
JTA是一种全局的事务。但是JTA是笨重的,且JTA的事务一般需要通过JNDI获得,所以JNDI和JTA一般联用。而且JTA代码一般不能跨App server,会受限于某种特定的容器。
所以更好的方式是使用EJB CMT(Container Managed Transaction),它的特点是使用声明性事务,而不是编码事务管理。
所以,虽然EJB天然结合了JNDI,但是并不受限于容器(声明性)。
但是CMT又依赖于JTA和App server环境(或者说支持EJB的App server,Tomcat这些Servlet容器就不行啦)。所以这种事务如果依赖于EJB或者EJB的装饰封装则要花不少资本投资App server(不是钱也至少要人,如JBoss)。
但是,我们还有更好的选择,如Spring,或者很多Aop实现,EJB3等等。
而本地的事务策略虽然实现容易,但是缺点显著。它不能在多资源间实现事务支持,并且这种事务对变成模型的侵入也很大(传统JDBC事务使用起来就是这样)。而且如JDBC连接也不能与其他JTA事务协同被管理。如你的JDBC和某个其它事务绑定(如两个JDBC Connection)起来,如果遇到一个失败你如何将两个rollback?(这个是我自己演绎的)
下面是广告:
Spring解决了这个问题。它提供了一个持续的模型,可以应用在大多数环境。也就是说你可以灵活的更换它支持的各种事务策略(你也可以自己扩展)。而且Spring两种方式的事务都支持(声明/编码),当然Spring推荐使用声明的(侵入小,灵活)。

MB,本来写了不少体会,结果倒霉没有保存,如果有时间我再考虑一下是否重写吧,损失惨重!