Spring的事务管理难点剖析(2):应用分层的迷惑

http://stamen.iteye.com/blog/1441767

    Web、Service及DAO三层划分就像西方国家的立法、行政、司法三权分立一样被奉为金科玉律,甚至有的开发人员认为如果要使用Spring的事务管理就一定要先进行三层的划分。这个看似荒唐的论调在开发人员中颇有市场。更有甚者,认为每层必须先定义一个接口,然后再定义一个实现类。其结果是:一个很简单的功能,也至少需要3个接口和3个类,再加上视图层的JSP和JS等,打牌都可以围上两桌了,这种误解贻害不浅。 
   对将“面向接口编程”奉为圭臬,认为放之四海而皆准的论调,笔者深不以为然。是的,“面向接口编程”是Martin Fowler、Rod Johnson这些大师提倡的行事原则。如果拿这条原则去开发框架和产品,怎么强调都不为过。但是,对于我们一般的开发人员来说,做的最多的是普通工程项目,往往只是一些对数据库增、删、查、改的功能。此时,“面向接口编程”除了带来更多的类文件外,看不到更多其他的好处。 
  Spring框架所提供的各种好处(如AOP、注解增强、注解MVC等)的唯一前提就是让POJO的类变成一个受Spring容器管理的Bean,除此以外没有其他任何的要求。下面的实例用一个POJO完成所有的功能,既是Controller,又是Service,还是DAO: 
Java代码    收藏代码
  1. package com.baobaotao.mixlayer;  
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.jdbc.core.JdbcTemplate;  
  5. import org.springframework.stereotype.Controller;  
  6. import org.springframework.web.bind.annotation.RequestMapping;  
  7.   
  8. //①将POJO类通过注解变成Spring MVC的Controller  
  9. @Controller  
  10. public class MixLayerUserService {  
  11.   
  12.     //②自动注入JdbcTemplate  
  13.     @Autowired  
  14.     private JdbcTemplate jdbcTemplate;  
  15.   
  16.     //③通过Spring MVC注解映射成为处理HTTP请求的函数,同时作为一个拥有事务性的方法  
  17.     @RequestMapping("/logon.do")  
  18.     @Transactional  
  19.     public String logon(String userName,String password){  
  20.         if(isRightUser(userName,password)){  
  21.             String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?";  
  22.             jdbcTemplate.update(sql,20,userName);  
  23.             return "success";  
  24.         }else{  
  25.             return "fail";  
  26.         }  
  27.     }  
  28.       
  29.     private boolean isRightUser(String userName,String password){  
  30.         //do sth  
  31.         return true;  
  32.     }  
  33. }  

   通过@Controller注解将MixLayerUserService变成Web层的Controller,同时也是Service层的服务类。此外,由于直接使用JdbcTemplate访问数据,所以MixLayerUserService还是一个DAO。来看一下对应的Spring配置文件:
Xml代码    收藏代码
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:context="http://www.springframework.org/schema/context"  
  5.        xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"  
  6.        xmlns:tx="http://www.springframework.org/schema/tx"  
  7.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  8.     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">  
  9.     …  
  10.     <!--①事务管理配置->  
  11.     <bean id="transactionManager"  
  12.           class="org.springframework.jdbc.datasource.DataSourceTransactionManager"  
  13.           p:dataSource-ref="dataSource"/>  
  14.     <tx:annotation-driven/>  
  15.   
  16.           
  17.     <!--②启动Spring MVC的注解功能-->  
  18.     <bean class="org.springframework.web.servlet.mvc.annotation.  
  19.                   AnnotationMethodHandlerAdapter"/>  
  20.     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"  
  21.           p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>  
  22. </beans>  

   在①处,通过事务注解驱动使MixLayerUserService的logon()工作于事务环境下,②处配置了Spring MVC的一些基本设施。要使程序能够运行起来还必须进行web.xml的相关配置: 
Xml代码    收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  5.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  6.     <context-param>  
  7.         <param-name>contextConfigLocation</param-name>  
  8.         <param-value>classpath:com/baobaotao/mixlayer/applicationContext.xml</param-value>  
  9.     </context-param>  
  10.     <context-param>  
  11.         <param-name>log4jConfigLocation</param-name>  
  12.         <param-value>/WEB-INF/classes/log4j.properties</param-value>  
  13.     </context-param>  
  14.   
  15.     <listener>  
  16.         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
  17.     </listener>  
  18.     <listener>  
  19.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  20.     </listener>  
  21.   
  22.     <servlet>  
  23.         <servlet-name>user</servlet-name>  
  24.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  25.         <init-param>  
  26.             <param-name>contextConfigLocation</param-name>  
  27.             <param-value>classpath:com/baobaotao/mixlayer/applicationContext.xml</param-value>  
  28.         </init-param>  
  29.         <load-on-startup>1</load-on-startup>  
  30.     </servlet>  
  31.     <servlet-mapping>  
  32.         <servlet-name>user</servlet-name>  
  33.         <url-pattern>*.do</url-pattern>  
  34.     </servlet-mapping>  
  35. </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的开发者应该是无拘无束的:从实际应用出发,去除那些所谓原则性的接口,去掉强制分层的束缚,简单才是硬道理。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值