精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (3)
|
|
---|---|
作者 | 正文 |
发表时间:2012-03-08
最后修改:2012-03-09
引述:Spring给我们带来的最大的一个便利是透明地实现事务管理,但是一般开发者仅仅是了解如何配置,在实际应用过程中却往往遇到很多问题,存在很多困惑。有有鉴于此,我特意总结了各种实际应用中遇到的Spring事务管理的困惑,这些文章摘自于我的《Spring 3.x企业应用开发实战》的第10章,我将通过连载的方式,陆续在此发出。欢迎大家讨论。 -------------------------------------------------------------------------------------------------------------------------- Web、Service及DAO三层划分就像西方国家的立法、行政、司法三权分立一样被奉为金科玉律,甚至有的开发人员认为如果要使用Spring的事务管理就一定要先进行三层的划分。这个看似荒唐的论调在开发人员中颇有市场。更有甚者,认为每层必须先定义一个接口,然后再定义一个实现类。其结果是:一个很简单的功能,也至少需要3个接口和3个类,再加上视图层的JSP和JS等,打牌都可以围上两桌了,这种误解贻害不浅。 对将“面向接口编程”奉为圭臬,认为放之四海而皆准的论调,笔者深不以为然。是的,“面向接口编程”是Martin Fowler、Rod Johnson这些大师提倡的行事原则。如果拿这条原则去开发框架和产品,怎么强调都不为过。但是,对于我们一般的开发人员来说,做的最多的是普通工程项目,往往只是一些对数据库增、删、查、改的功能。此时,“面向接口编程”除了带来更多的类文件外,看不到更多其他的好处。 Spring框架所提供的各种好处(如AOP、注解增强、注解MVC等)的唯一前提就是让POJO的类变成一个受Spring容器管理的Bean,除此以外没有其他任何的要求。下面的实例用一个POJO完成所有的功能,既是Controller,又是Service,还是DAO: package com.baobaotao.mixlayer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; //①将POJO类通过注解变成Spring MVC的Controller @Controller public class MixLayerUserService { //②自动注入JdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; //③通过Spring MVC注解映射成为处理HTTP请求的函数,同时作为一个拥有事务性的方法 @RequestMapping("/logon.do") @Transactional public String logon(String userName,String password){ if(isRightUser(userName,password)){ String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?"; jdbcTemplate.update(sql,20,userName); return "success"; }else{ return "fail"; } } private boolean isRightUser(String userName,String password){ //do sth return true; } } 通过@Controller注解将MixLayerUserService变成Web层的Controller,同时也是Service层的服务类。此外,由于直接使用JdbcTemplate访问数据,所以MixLayerUserService还是一个DAO。来看一下对应的Spring配置文件: <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> … <!--①事务管理配置-> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <tx:annotation-driven/> <!--②启动Spring MVC的注解功能--> <bean class="org.springframework.web.servlet.mvc.annotation. AnnotationMethodHandlerAdapter"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/> </beans> 在①处,通过事务注解驱动使MixLayerUserService的logon()工作于事务环境下,②处配置了Spring MVC的一些基本设施。要使程序能够运行起来还必须进行web.xml的相关配置: <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:com/baobaotao/mixlayer/applicationContext.xml</param-value> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/classes/log4j.properties</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>user</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:com/baobaotao/mixlayer/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>user</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app> 这个配置文件很简单,唯一需要注意的是DispatcherServlet的配置。默认情况下Spring MVC根据Servlet的名字查找WEB-INF下的<servletName>-servlet.xml作为Spring MVC的配置文件,在此,我们通过contextConfigLocation参数显式指定Spring MVC配置文件的确切位置。 将org.springframework.jdbc及org.springframework.transaction的日志级别设置为DEBUG,启动项目,并访问http://localhost:8088/chapter10/logon.do?userName=tom应用,MixLayerUserService#logon方法将作出响应,查看后台输出日志,如下所示: 引用 Returning cached instance of singleton bean 'transactionManager'
Creating new transaction with name [com.baobaotao.mixlayer.MixLayerUserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' (DataSourceTransactionManager.java:204) - Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction (DataSourceTransactionManager.java:221) - Switching JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] to manual commit (JdbcTemplate.java:810) - Executing prepared SQL update (JdbcTemplate.java:569) - Executing prepared SQL statement [UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?] (JdbcTemplate.java:819) - SQL update affected 0 rows (AbstractPlatformTransactionManager.java:752) - Initiating transaction commit (DataSourceTransactionManager.java:264) - Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] 日志中红色部分说明了MixLayerUserService#logon方法已经正确运行在事务上下文中。 Spring框架本身不应是代码复杂化的理由,使用Spring的开发者应该是无拘无束的:从实际应用出发,去除那些所谓原则性的接口,去掉强制分层的束缚,简单才是硬道理。 注:以上内容摘自《Spring 3.x企业应用开发实战》 Spring的事务管理难点剖析(2):应用分层的迷惑 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-03-08
很希望看大哥的文章,不知能否从第一章开始进行连载?
|
|
返回顶楼 | |
发表时间:2012-03-08
最后修改:2012-03-08
jinnianshilongnian 写道 很希望看大哥的文章,不知能否从第一章开始进行连载?
呵呵,我选择了一些自认为对大家比较有帮助的,象IOC、AOP、SSH 由于已经论坛上已经有比较多这些内容,所以载的话怕对大家也没有多大的用处。 事务管理这些都是我个人实际应用中的具体总结,希望对大家有用,共7篇,会陆续在论坛中发出。 |
|
返回顶楼 | |
发表时间:2012-03-09
看不出来这样做有啥好处,倘若反对每个层都接口+实现类,这片文章也没有举出特别优秀的实践例子,只是简单的把mvc的m和c何二唯一,,个人认为这种实践还不如直接在jsp中写业务来的更快!!
|
|
返回顶楼 | |
发表时间:2012-03-09
那你多人来做,以后让别人怎么维护你这种自以为是的东西。。。。。。。
|
|
返回顶楼 | |
发表时间:2012-03-09
楼主说别人走了极端,然后自己走了另外一个极端,对于新人一点帮助没有,并存在一定的误导
|
|
返回顶楼 | |
发表时间:2012-03-09
最后修改:2012-03-09
各位误解了,我这里不是说分层不好。由于我们基本上都是在Service层实施事务管理,所以有些人会有误认为Spring的事务管理的前提就一定要分层,我这边就是想指出这种观点的错误,得出以下的事实:
Spring的事务管理和分层没有必然的联系,事务管理完全可以脱离分层而存在!。 至于应用是否要分层,如何分层都不是我这个帖子讨论的内容。 |
|
返回顶楼 | |
发表时间:2012-03-09
是否可以总结为:
>在内部实现上:“分层”和“事务管理” 正交! >在实际应用中,“事务管理”和“分层” 相交! |
|
返回顶楼 | |
发表时间:2012-03-09
javakatty 写道 是否可以总结为:
>在内部实现上:“分层”和“事务管理” 正交! >在实际应用中,“事务管理”和“分层” 相交! 我说的正是这个! |
|
返回顶楼 | |
发表时间:2012-03-09
基本上都是按着书配置Spring的事务,然后就不管了,所以在看楼主的帖前,我也一直有这个误解.
|
|
返回顶楼 | |