目录:V1.0
1.旧时的痛
2.光明来临前的黑暗
3.欢迎救世主
注:可自由转载,转载时需说明出处并请保持原样。
1.旧时的痛
为什么说配制无限制的Spring事务管理呢,估计肯定有哪位高手看过标题之后就会奇怪,配制事务管理还要有什么限制吗?
当然对您这样的高手当然是运用自如。但是还是和很多初识者甚至有很长的工作经验的朋友的老鸟对Spring配制只停留在spring1.x
阶段,并且仅限于配制Spring+Hibernate的事务管理。
最经典的Spring+Hibernate的配制是这样的:
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@192.168.0.150:1521:cisfedb"/>
<property name="username" value="draftsa"/>
<property name="password" value="draftsa"/>
<property name="maxActive" value="100"/>
<property name="maxIdle" value="30"/>
<property name="maxWait" value="1000"/>
<property name="defaultAutoCommit" value="true"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="60"/>
</bean>
<!-- 工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="lobHandler">
<ref bean="lobHandler"/>
</property>
<property name="mappingResources">
<list>
<value>com/ecds/hibernate/EcdAuthlistdata.hbm.xml</value>
<value>com/ecds/hibernate/PcdRediscountwithcb.hbm.xml</value>
</list>
</bean>
<!-- 事务管理,用的hibernate 的 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!-- 事务代理,由spring 接管,配置性事务,aop 应用 -->
<bean id="baseTxProxy" lazy-init="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
在使用时为每个service加入事务模版,其实这种方式已经很方便了,
但是限制了使用者的视野,让很多初学者误认为Spring的事务只针对Hibernate准备的。
这是Spring1.0时代的产物,深深的留下了持久层框架的烙印。
<bean id="commonService" parent="baseTxProxy">
<property name="target">
<bean class="com.ecds.service.common.impl.CommonServiceImpl">
<property name="icommonDao">
<ref bean="icommonDao"/>
</property>
</bean>
</property>
</bean>
2.光明来临前的黑暗
实际上Spring提供了多种事务管理器以供使用,而其中的一种才是Hibernate的,如下:
事务管理器的实例 |
目标 |
Org.springframwork.jdbc.datasource.DataSourceTransactionManager |
用DBC的 DataSource 去管理事务 |
Org.springframwork.orm.hibernate.HibernateTransactionManager |
当持久机制是Hibernate时的事务管理器 |
Org.springframework.orm.jdoTransactionManager |
当持久机制是JDO时的事务管理器 |
Org.springframework.transaction.jta.JtaTransactionManager |
用JTA管理事务 |
Org.springframwork.orm.ojb.PersistenceBrokerTransactionManager |
当持久机制是apache的OJB时的事务管理器 |
也就是说以下配制中的class使用不同的事务管理器可以应用在不同的持久层机制上,其中的
DataSourceTransactionManager是最为通用的管理器。
有很多人在论坛里问:在Hibernate中是这样配制事务管理的,那么在某某下是如何配制呢,问的人不深问题的本身,而是只注重于解决事情的方式上。
当然这时用数据源的方式不是用sessionFactory,这种情况下就是在Spring1.x下的通用方式。
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
3.欢迎救世主
下面来介绍一下在Spring2.x达到相同的通用方式,并且配制起来更简洁和灵活的方式,当然和上面一样通用的方式就要使用通用的数据源(
DataSource管理器)。
<!-- 数据源 -->
<bean id="vbank_ds_master" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${vbank.master.jdbc.driverClassName}"/>
<property name="url" value="${vbank.master.jdbc.url}"/>
<property name="username" value="${vbank.master.jdbc.username}"/>
<property name="password" value="${vbank.master.jdbc.password}"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="10"/>
<property name="maxWait" value="1000"/>
<property name="defaultAutoCommit" value="true"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="60"/>
<property name="logAbandoned" value="false"/>
<property name="testOnBorrow" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="validationQuery" value="select 1"/>
<property name="poolPreparedStatements" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="3600000"/>
<property name="minEvictableIdleTimeMillis" value="18000000"/>
</bean>
<!-- AOP: Configuration and Aspects -->
<aop:config>
<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="0"/>
</aop:config>
<!-- 默认时自动注入id为transactionManager的事务管理器,否则需指定事务管理器id名称 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" rollback-for="Exception,DataAccessException"/>
</tx:attributes>
</tx:advice>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="vbank_ds_master"/>
</bean>
你会发现根本不需要事务模版了,由正则表达式来限定对Service的事务管理:pointcut="execution(* *..service.*Manager.*(..))"
这样的方式是不是使你忘记了Spring中使用了什么持久层框架,是的,这时你就自由了!~
是不是想问我用了什么框架,我可以很负责任的告诉你是iBatis,你是不是没有看出来呢
下面是Service的配制,在Service中注入Dao,在Dao中注入SqlMapClientFactoryBean。
<!-- Service -->
<bean id="userAccountManager" class="com.m312.vbank.service.impl.UserAccountManagerImpl">
<property name="genericMasterDao">
<bean class="com.m312.vbank.dao.ibatis.UserAccountDaoiBatis" parent="writeDao"/>
</property>
<property name="genericSlaveDao">
<bean class="com.m312.vbank.dao.ibatis.UserAccountDaoiBatis" parent="readDao"/>
</property>
</bean>
<!-- Dao -->
<bean id="readDao" class="com.m312.vbank.dao.ibatis.GenericDaoiBatis" abstract="true">
<!-- <property name="dataSource" ref="vbank_ds_slave"/> -->
<property name="sqlMapClient" ref="vbank_sqlmap_slave"/>
<property name="sqlExecutor" ref="sqlExecutor"/>
</bean>
<!-- ibatis Factory -->
<bean id="vbank_sqlmap_master" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="vbank_ds_master"/>
<property name="configLocation" value="classpath:/sqlmap-vbank.xml"/>
</bean>
<!-- 方言 -->
<bean id="sqlExecutor"
class="com.m312.database.ibatis.LimitSqlExecutor">
<property name="dialect">
<bean class="com.m312.database.ibatis.MySQLDialect"/>
</property>
</bean>
由于个人的技术和知识水平有限,难免有疏漏之处,请指正!