该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-04-13
事务代码尽量不要手动写,用Spring Aop的事务声明
就可以了.Spring的事务声明类试与ejb的, 有PROPAGATION_REQUIRED/ PROPAGATION_NEW等等,可以解决你的问题。 把Tx手动写到ThreadLocal里头我以前干过的, 会造成相互调用的困扰,比如别人已经写好了 addCost方法,他自己测试了正常,必然需要 在他的代码边界加上Tx begin/Tx commit, 可是我要是要调用他的代码,就会造成我的麻烦。 我们当时的解决方案是给Tx作一个WrapperTx tx.begin代码 depth++; if (depth == 1) { tx.begin(); } tx.commit代码 depth--; if (depth == 0) { tx.commit(); } 这样我外面的代码可以包他的代码,可是还是麻烦也不Elegant, 还是用aop解决的好。 |
|
返回顶楼 | |
发表时间:2004-04-13
只提一点关于DAO的,它有存在的必要,特别在一些用文件做临时数据库的时候.......而不会因为Hibernate的存在而可以不要了,甚至还有基于内存的数据库
只能说,可以根据项目的实际情况而定,其实用了Spring,就算用了DAO,也不过多了一个接口,一个配置文件而已,但却可以带来更多的灵活 |
|
返回顶楼 | |
发表时间:2004-04-13
robbin 写道 引用 那么我习惯把,abcde五个方法都写道DAO当中。
否则的话,重复的代码会比较多。 这些DAO也可以是Service。所以不会存在你说的重复代码的问题。 确实也可以看作service,除开你的各个Service之间没有代码重复,否则就要重写代码。我所遇到的各个service之间是有部分代码重复的。 robbin 写道 引用 事务中的方法需要递归调用,因为事务不能嵌套,所以不能service中的方法,递归调用自己-否则事务将嵌套。而被递归调用的方法必须写在dao层。
我觉得你这种做法实际上仍然有问题,因为很有可能出现Service调用其他几个Service的嵌套调用,那么仍然会出现你说的事务嵌套问题。解决办法就是把Transaction也放到ThreadLocal里面,向对待Session那样去处理,那么整个世界都清静了。 我就是为了避免避免service的嵌套调用,才搞DAO的,如果要嵌套,就在DAO中嵌套。 如果把tx放到threadlocal,这样有点违背了“事务”的原意,事务本来指一个“全有或者全无”的操作,代表一个业务动作的完成。然而,一个线程当中,我可能要完成几项业务,而这些业务之间并不要求“要么都完成,要么都不完成”。 |
|
返回顶楼 | |
发表时间:2004-04-13
引用 如果把tx放到threadlocal,这样有点违背了“事务”的原意,事务本来指一个“全有或者全无”的操作,代表一个业务动作的完成。然而,一个线程当中,我可能要完成几项业务,而这些业务之间并不要求“要么都完成,要么都不完成”。
当然不会咯。你一样可以在一个线程里面提交多次,切分出来好几个事务。 不过看起来手工方式还是没有上面描述的Spring控制方式优雅,我也倾向于Spring了。 |
|
返回顶楼 | |
发表时间:2004-04-14
just some quick reply, too tired today.
Quake Wang: 我们为每个entity自动生成对应的dao, 这样客户代码不需要cast. 对于查询的处理和你是一样的. 关于修改hardcode的属性名,有一个小tip: 把要更改的属性改为public, 然后用refactor的rename, IDEA自动修改字符串中的属性名(我们用的是IDEA). 我不明白为什么你认为从spring获得action listener要比在page class中直接实现listener方法要好? 我今天做了一个小例子, 完全可以从spring中得到action listener, 因为Tapestry的listener只是一个实现了IActionListener接口的对象而已. 这样作的结果是每一个action都要写一个类, 还要编辑相应的spring配置文件, 而且并不优于直接在page class中实现listener方法, 在page文件中配置navigation. (公司的邮件出了问题, 代码没有发回家, 只好明天详细说明了) 关于权限验证, 我想说明的是secure by hidding will not work! Service中的权限检查是必须的。 robbin的权限检查对我很有启发,我们可以作一个aop,检查访问Service方法的用户(登录用户用ThreadLocal保存)有没有足够的权限。 方法和权限的对应可以是放在配置文件中,也可以是放在数据库中。方法和权限的对应关系则是灵活的,即可以是不同方法对应不同权限,也可以是同一个Service的所有方法对应同一个权限,甚至一个方法的对应多个权限值,这些权限值之间是and或者or的关系。这样就足够灵活了。 其实在我们的架构里,service的方法对应着用例中的一步业务操作,是unit of work,也是事务处理的自然边界。使用Spring的Declarative Transaction Management,可以很优雅地处理事务,包括事务嵌套的问题。 dao对于service来说就是一个处理数据存储的helper类,基于speration of concern的原则,使用dao还是很有好处的,而且Spring对Hibernate DAO的支持非常之好,用了它之后很多数据访问都只是简单的一行代码,并且它会把HibernateException转化成一组定义得非常清晰的RuntimeException(因为数据库异常基本上是Service层无法恢复的),极大地简化异常处理。 工具问题是一件让我非常郁闷的事。我们对IDEA非常熟悉,也非常喜欢,但是IDEA没有想Spindle那样的插件,许多typo要在deploy之后才能发现,幸好Tapestry的错误提示信息异常的详细,甚至精确到某一行某一列,要不然我们就死定了:( 我们项目组没有熟悉Eclipse的成员,项目进展到这个时侯更换开发工具也是不现实的。或许等我有时间了,也作一个IDEA的Spindle:) |
|
返回顶楼 | |
发表时间:2004-04-14
magician 写道 只提一点关于DAO的,它有存在的必要,特别在一些用文件做临时数据库的时候.......而不会因为Hibernate的存在而可以不要了,甚至还有基于内存的数据库
只能说,可以根据项目的实际情况而定,其实用了Spring,就算用了DAO,也不过多了一个接口,一个配置文件而已,但却可以带来更多的灵活 呵呵,你说的很对,使用DAO的一个很大的好处就是我可以很方便地使用mockDAO代替真正的DAO,这样在单元测试和没有数据库连接的时侯,就会非常方便(前天我在给同事培训的时侯就没有数据库,直接使用mockDAO,一点问题没有)。而且mock和real之间的转换只需要修改一下Spring的配置文件即可,thanks to IOC。 |
|
返回顶楼 | |
发表时间:2004-04-14
cyberwing 写道 我们为每个entity自动生成对应的dao, 这样客户代码不需要cast. 对于查询的处理和你是一样的. 关于修改hardcode的属性名,有一个小tip: 把要更改的属性改为public, 然后用refactor的rename, IDEA自动修改字符串中的属性名(我们用的是IDEA). 嗯, 确实要多写cast的问题. 我从别人的代码看都是一个Entity对应一个自己的DAO, 但是这些DAO的create, update, delete代码又都是很类似的, 所以才会考虑用单个的DAO. 分开除了不用cast以外, 不知道还有没有其他好处. 关于属性的hardcode, Robbin也和我说过这个tip了, 可以用Eclipse的refactor功能, 让eclipse查找所有对应的字符串, , Thanks! cyberwing 写道 我不明白为什么你认为从spring获得action listener要比在page class中直接实现listener方法要好? 我今天做了一个小例子, 完全可以从spring中得到action listener, 因为Tapestry的listener只是一个实现了IActionListener接口的对象而已. 这样作的结果是每一个action都要写一个类, 还要编辑相应的spring配置文件, 而且并不优于直接在page class中实现listener方法, 在page文件中配置navigation. (公司的邮件出了问题, 代码没有发回家, 只好明天详细说明了) 我的意思是把所有Tapestry Page对象都纳入Spring管理, 而不是直接再写一个类. 这样做的好处是, 由于Page上每个listener method签名都是一样的: void abc(IRequestCycle cycle), 我们很容易就能够做拦截了, 利用AOP来做dirty job(Exception 处理, hit log等等). 但是由于Tapestry Page Listener的概念和Webwork, Structs的Action概念完全不一样, 随着对Tapestry的了解增多, 我发现可以用它良好的OO设计来解决, 比如重载Engine的activateExceptionPage方法做exception处理, 重载setupForRequest和cleanupAfterRequest做hit log, 不一定要赶AOP的时髦,. 准备等对AOP了解再多一些了, 再考虑这些问题. Spring封装的DAO和事务处理真的非常cool, 确实极大方便了开发. 再回头看看以前自己写的工具代码方法, 不免有一种遗憾: Spring早点出来就好了. cyberwing 写道 工具问题是一件让我非常郁闷的事。我们对IDEA非常熟悉,也非常喜欢,但是IDEA没有想Spindle那样的插件,许多typo要在deploy之后才能发现,幸好Tapestry的错误提示信息异常的详细,甚至精确到某一行某一列,要不然我们就死定了:( 我们项目组没有熟悉Eclipse的成员,项目进展到这个时侯更换开发工具也是不现实的。或许等我有时间了,也作一个IDEA的Spindle:) 很遗憾你们没有用Spindle, 它不仅仅解决typo的问题, 它的提示功能, 还免去了我查询component reference的烦恼. Create Page生成所有相关文件的功能非常体贴. IDEA的Spindle? plugin 开发好烦......, good luck! 另外问个问题, 有谁可以订阅Tapestry的邮件吗? 我发给它的订阅email地址都是time out, 无法送达, 不知道是什么原因. |
|
返回顶楼 | |
发表时间:2004-04-14
cyberwing 写道 工具问题是一件让我非常郁闷的事。我们对IDEA非常熟悉,也非常喜欢,但是IDEA没有想Spindle那样的插件,许多typo要在deploy之后才能发现,幸好Tapestry的错误提示信息异常的详细,甚至精确到某一行某一列,要不然我们就死定了:( 我们项目组没有熟悉Eclipse的成员,项目进展到这个时侯更换开发工具也是不现实的。或许等我有时间了,也作一个IDEA的Spindle:) 不会阿?Idea的xml支持很好的阿,在xml里头也会有很多自动完成/自动提示的,还有对xml的校验功能,按右键在弹出的快捷菜单里头选Validate就可以了 可以发现比如一个引用了Id为TestBean,而该Bean声明中错写为Tes?ean这样子的错误。 至于Idea对xml的自动完成/自动提示,需要取得该xml对应的dtd/schema, 如果Idea没有取得对应的dtd/schema,在开头xml开头的dtd引用会标红,比如http://www.springframework.org/dtd/spring-beans.dtd标红,你在 这里按Alter+Enter,他会问你要不要取该Resource,你选确定就ok了。 对于dtl声明只是网址类型,比如 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> 这样的,你在配置的Resources里头Configure External Resources: URI填http://java.sun.com/jstl/core,Path填你把那个dtd/tld拷贝到 本机的目录,他就找得到了。 我很喜欢Idea的,Idea的自己本身的Code 智能就作的很强大了,不过专门 针对Tapestry开发的Spindle的其他功能那Idea就可能没有了,所以打算玩玩Eclipse了~,研究研究 |
|
返回顶楼 | |
发表时间:2004-04-14
Quake Wang 写道 我的意思是把所有Tapestry Page对象都纳入Spring管理, 而不是直接再写一个类. 这样做的好处是, 由于Page上每个listener method签名都是一样的: void abc(IRequestCycle cycle), 我们很容易就能够做拦截了, 利用AOP来做dirty job(Exception 处理, hit log等等). 但是由于Tapestry Page Listener的概念和Webwork, Structs的Action概念完全不一样, 随着对Tapestry的了解增多, 我发现可以用它良好的OO设计来解决, 比如重载Engine的activateExceptionPage方法做exception处理, 重载setupForRequest和cleanupAfterRequest做hit log, 不一定要赶AOP的时髦,. 准备等对AOP了解再多一些了, 再考虑这些问题.
原来你是这个意思阿,还得我瞎忙了半天。不过也是有收获的,感觉基于action或是command模式的事件处理方法不如Tapestry这样把页面数据和事件处理方法放在同一个类中方便、自然。 关于hit log,看看Tapestry的IMoniter接口,就是用来做这个的。在没有使用OpenSessionInView时,还有人用IMoniter来管理Hibernate的Session. Quake Wang 写道 另外问个问题, 有谁可以订阅Tapestry的邮件吗? 我发给它的订阅email地址都是time out, 无法送达, 不知道是什么原因.
国内的信箱好像都不行,Yahoo和hotmail的帐号可以,网上也有use list的archiver阿。 |
|
返回顶楼 | |
发表时间:2004-04-14
femto 写道 不会阿?Idea的xml支持很好的阿,在xml里头也会有很多自动完成/自动提示的,还有对xml的校验功能,按右键在弹出的快捷菜单里头选Validate就可以了 可以发现比如一个引用了Id为TestBean,而该Bean声明中错写为Tes?ean这样子的错误。 至于Idea对xml的自动完成/自动提示,需要取得该xml对应的dtd/schema, 如果Idea没有取得对应的dtd/schema,在开头xml开头的dtd引用会标红,比如http://www.springframework.org/dtd/spring-beans.dtd标红,你在 这里按Alter+Enter,他会问你要不要取该Resource,你选确定就ok了。 对于dtl声明只是网址类型,比如 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> 这样的,你在配置的Resources里头Configure External Resources: URI填http://java.sun.com/jstl/core,Path填你把那个dtd/tld拷贝到 本机的目录,他就找得到了。 我很喜欢Idea的,Idea的自己本身的Code 智能就作的很强大了,不过专门 针对Tapestry开发的Spindle的其他功能那Idea就可能没有了,所以打算玩玩Eclipse了~,研究研究 呵呵,这些我都知道阿,我也觉得IDEA对XML文件编辑的支持要比Eclipse的强n倍(当然是指Eclipse基本的XML编辑支持)。但是它不能作到Tapestry aware。比如在定义component的时侯,它能自动发现有binding,static-binding, inherited-binding等等元素可用,但是它并不知道对应的component有那些参数可以设置,它不能提供name属性的可选值。 还有就是HTML中定义的component的jwcid和.page文件中定义的name,如果一不小心敲错了,两个不一致,这样的问题就只有在运行时才能发现了。而Spindle可以在build time就发现这种错误,可以节省相当多的时间和精力。 |
|
返回顶楼 | |