java

位置:IT落伍者 >> java >> 浏览文章

Spring事务管理高级应用难点剖析(2)


发布日期:2020年12月16日
 
Spring事务管理高级应用难点剖析(2)

应用分层的迷惑

WebService及DAO三层划分就像西方国家的立法行政司法三权分立一样被奉为金科玉律甚至有开发人员认为如果要使用Spring事务管理就一定先要进行三层的划分这个看似荒唐的论调在开发人员中颇有市场更有甚者认为每层必须先定义一个接口然后再定义一个实现类其结果是一个很简单的功能也至少需要个接口个类再加上视图层的JSP和JS等打牌都可以转上两桌了这种误解贻害不浅

对将面向接口编程奉为圭臬认为放之四海而皆准的论调笔者深不以为然是的面向接口编程是MartinFowlerRodJohnson这些大师提倡的行事原则如果拿这条原则去开发架构开发产品怎么强调都不为过但是对于我们一般的开发人员来说做的最多的是普通工程项目往往最多的只是一些对数据库增改的功能此时面向接口编程除了带来更多的类文件外看不到更多其它的好处

Spring框架提供的所有附加的好处(AOP注解增强注解MVC等)唯一的前提就是让POJO的类变成一个受Spring容器管理的Bean除此以外没有其它任何的要求下面的实例用一个POJO完成所有的功能既是Controller又是Service还是DAO

清单MixLayerUserServicejava

packageusermixlayer;

importorgspringframeworkbeansfactoryannotationAutowired;

importorgsprireJdbcTemplate;

importorgspringframeworkstereotypeController;

importorgspringframeworkwebbindannotationRequestMapping;

//①将POJO类通过注解变成SpringMVC的Controller

@Controller

publicclassMixLayerUserService{

//②自动注入JdbcTemplate

@Autowired

privateJdbcTemplatejdbcTemplate;

//③通过SpringMVC注解映URL请求

@RequestMapping(/logondo)

publicStringlogon(StringuserNameStringpassword){

if(isRightUser(userNamepassword)){

Stringsql=UPDATEt_useruSETuscore=uscore+?WHEREuser_name=?;

jdbcTemplateupdate(sqluserName);

returnsuccess;

}else{

returnfail;

}

}

privatebooleanisRightUser(StringuserNameStringpassword){

//dosth

returntrue;

}

}

通过@Controller注解将MixLayerUserService变成Web层的Controller同时也是Service层的服务类此外由于直接使用JdbcTemplate访问数据所以MixLayerUserService还是一个DAO来看一下对应的Spring配置文件

清单applicationContextxml

<?xmlversionxmlversion=encoding=UTF?>

<beansxmlnsbeansxmlns=

xmlns:xsi=instance

xmlns:context=

xmlns:p=

xmlns:aop=

xmlns:tx=

xsi:schemaLocation=

beansxsd

contextxsd

aopxsd

txxsd>

<context:componentscanbasepackagecontext:componentscanbasepackage=usermixlayer/>

<beanclassbeanclass=orgspringframeworkwebservletmvcannotation

AnnotationMethodHandlerAdapter/>

<beanclassbeanclass=orgspringframeworkwebservletview

InternalResourceViewResolver

pp:prefix=/WEBINF/jsp/p:suffix=jsp/>

<beanidbeanid=dataSource

class=monsdbcpBasicDataSource

destroymethod=close

p:driverClassName=oraclejdbcdriverOracleDriver

p:url=jdbc:oracle:thin:@localhost::orcl

p:username=test

p:password=test/>

<beanidbeanid=jdbcTemplate

class=orgsprireJdbcTemplate

p:dataSourceref=dataSource/>

<beanidbeanid=jdbcManager

class=orgspringframeworkjdbcdatasourceDataSourceTransactionManager

p:dataSourceref=dataSource/>

<aop:configproxytargetclassaop:configproxytargetclass=true>

<aop:pointcutidaop:pointcutid=serviceJdbcMethod

expression=execution(public*usermixlayerMixLayerUserService*())/>

<aop:advisorpointcutrefaop:advisorpointcutref=serviceJdbcMethod

adviceref=jdbcAdviceorder=/>

</< span>aop:config>

<tx:adviceidtx:adviceid=jdbcAdvicetransactionmanager=jdbcManager>

<tx:attributes>

<tx:methodnametx:methodname=*/>

</< span>tx:attributes>

</< span>tx:advice>

</< span>beans>

在①处我们定义配置了AnnotationMethodHandlerAdapter以便启用SpringMVC的注解驱动功能而②和③处通过Spring的aop及tx命名空间以及Aspject的切点表达式语法进行事务增强的定义对MixLayerUserService的所有公有方法进行事务增强要使程序能够运行起来还必须进行webxml的相关配置

清单webxml

<?xmlversionxmlversion=encoding=GB?>

<webappversionwebappversion=xmlns=

xmlns:xsi=instance

xsi:schemaLocation=

app__xsd>

<contextparam>

<paramname>contextConfigLocation</< span>paramname>

<paramvalue>classpath*:user/mixlayer/applicationContextxml</< span>paramvalue>

</< span>contextparam>

<contextparam>

<paramname>logjConfigLocation</< span>paramname>

<paramvalue>/WEBINF/classes/logjproperties</< span>paramvalue>

</< span>contextparam>

<listener>

<listenerclass>

springframeworkwebutilLogjConfigListener

</< span>listenerclass>

</< span>listener>

<listener>

<listenerclass>

sprntextContextLoaderListener

</< span>listenerclass>

</< span>listener>

<servlet>

<servletname>user</< span>servletname>

<servletclass>

springframeworkwebservletDispatcherServlet

</< span>servletclass>

<initparam>

<paramname>contextConfigLocation</< span>paramname>

<paramvalue>classpath:user/mixlayer/applicationContextxml</< span>paramvalue>

</< span>initparam>

<loadonstartup></< span>loadonstartup>

</< span>servlet>

<servletmapping>

<servletname>user</< span>servletname>

<urlpattern>*do</< span>urlpattern>

</< span>servletmapping>

</< span>webapp>

这个配置文件很简单唯一需要注意的是DispatcherServlet的配置默认情况下SpringMVC根据Servlet的名字查找WEBINF下的servletxml作为SpringMVC的配置文件在此我们通过contextConfigLocation参数显式指定SpringMVC配置文件的确切位置

将orgspringframeworkjdbc及orgspringframeworktransaction的日志级别设置为DEBUG启动项目并访问应用MixLayerUserService#logon方法将作出响应查看后台输出日志

清单执行日志

::DEBUG(AbstractPlatformTransactionManagerjava:)

Creatingnewtransactionwithname

[usermixlayerMixLayerUserServicelogon]:PROPAGATION_REQUIREDISOLATION_DEFAULT

::DEBUG(DataSourceTransactionManagerjava:)

AcquiredConnection[monsdbcpPoolableConnection@ecbf]

forJDBCtransaction

::DEBUG(DataSourceTransactionManagerjava:)

SwitchingJDBCConnection

[monsdbcpPoolableConnection@ecbf]tomanualcommit

::DEBUG(JdbcTemplatejava:)

ExecutingpreparedSQLupdate

::DEBUG(JdbcTemplatejava:)

ExecutingpreparedSQLstatement

[UPDATEt_useruSETuscore=uscore+?WHEREuser_name=?]

::DEBUG(JdbcTemplatejava:)

SQLupdateaffectedrows

::DEBUG(AbstractPlatformTransactionManagerjava:)

Initiatingtransactioncommit

::DEBUG(DataSourceTransactionManagerjava:)

CommittingJDBCtransactiononConnection

[monsdbcpPoolableConnection@ecbf]

::DEBUG(DataSourceTransactionManagerjava:)

ReleasingJDBCConnection[monsdbcpPoolableConnection@ecbf]

aftertransaction

::DEBUG(DataSourceUtilsjava:)

ReturningJDBCConnectiontoDataSource

日志中粗体部分说明了MixLayerUserService#logon方法已经正确运行在事务上下文中Spring框架本身不应该是复杂化代码的理由使用Spring的开发者应该是无拘无束的从实际应用出发去除掉那些所谓原则性的接口去除掉强制分层的束缚简单才是硬道理

               

上一篇:迎接Eclipse 3.5(Galileo):新特性

下一篇:如何在JBOSS Server上发布EJB