随着业务的不断扩展数据库的压力越来越大,为了减少数据库的压力我们要从多方面考虑分析,并提出多个解决数据库压力大的问题,比如说根据业务分表、分库、增加缓存机制等等。如果是分库,如何做分布式呢?我就做分布式的库来讨论一下如何使用jta事务。
什么是jta网上有很多很详细的解释,我不在这里介绍。为了开发效率现在的传统行业的大部分中小企业还是采用SSH架构,那我们就从SSH+JTA的架构说一下如何使用jta。
使用JTA一般的需要容器的支持,如何摆脱容器的绑定呢?目前网上有两个开源的软件:Atomikos和JTOM。两个都是非常优秀的JTA两阶段提交事务的实现。查看JTOM的官网发现其最近的更新时间是2005年,并且spring3的已经放弃了对JTOM的集成。Atomikos的最近更新时间是2010年,并不是说他们的更新时间越晚越好好,实际上他们两个对事务的支持已经相当稳定。
下面我们就Atomikos来说明一下如何配置SSH+JTA。
首先下载Atomikos http://www.atomikos.com/
我下载的版本是:AtomiosTransactionEssentials-3.8.0
Spring 3.0.4
Hibernate 3.5.5
Struts 2
配置数据源
使用JTA要使用XA的数据源,流程的数据库都提供了XA的数据源的实现,比如我们使用mysql数据源,mysql的XA数据源:com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
DB2的XA数据源:com.ibm.db2.jcc.DB2XADataSource
我们需要在Spring的xml配置文件配置数据的多个数据源如下所示
<!—mysql数据源---> <bean id=”mysqlDataSource” class=”com.atomikos.jdbc.AtommikosDataSourceBean” init-method=”init” destroy-method=”close”> <property name=”uniqueResourceName”> <value> mysqlDataSource </value> </property> <property name=”xaDataSourceClassName”> <value> com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </value> </property> <property name=”xa properties”> <props> <prop key=”URL”>jdbc:mysql://192.168.1.45:3306/dbname?userUnicode=true&characterEncoding=utf-8&autoReconnect=true</prop> <prop key=”user”>root</prop> <prop key=”password”>root</prop> <prop key=”pinGlobalTxToPhysicalConnetion”>true</prop> </props> </property> </bean> <!—DB2数据源---> <bean id=”db2DataSource” class=”com.atomikos.jdbc.AtommikosDataSourceBean” init-method=”init” destroy-method=”close”> <property name=”uniqueResourceName”> <value> db2DataSource </value> </property> <property name=”xaDataSourceClassName”> <value> com.ibm.db2.jcc.DB2XADataSource </value> </property> <property name=”xa properties”> <props> <prop key=”serverName”> 192.168.1.45 </prop> <prop key=”portNumber”>50000 </prop> <prop key=”databseName”>dbname</prop> <prop key=”user”>root</prop> <prop key=”password”>root</prop> <prop key=”driverType”>4</prop> </props> </property> </bean> 对应的sessionFactory配置(Hibernate的): <bean id=”mysqlSessionFactory” class=“org.springframework.org.hibernate3.annotation.AnnotationSessionFactoryBean”> <!---采用注解扫描实体--> <property name=”packagesToScan” value=”com.zohan”/> <property name=”dataSource” ref=”mysqlDataSource”/> <property name=”jtaTransactionManager” ref=”atomikosTransactionManager”/> <!---hibernate 实体对应配置文件---> <property name=”mapppingResources”> <list> <value>xxx.xml</value> </list> </property> <!—hibernate 配置属性,可以参考Hibernate帮助文档这里只罗列和jta相关的配置--> <property name=”hibernateProperties”> <props> <prop key=”hibernate.current_session_context_class”>jta</prop> <prop key=”hibernate.transaction.factory_class”> Com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory </prop> <prop key=”hibernate.transcation.manager_lookup_class”> com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup </prop> <prop key=”hibernate.connection.release_mode”>after_statement</prop> </props> </property> </bean> Db2的session配置基本上和mysql的相同知识数据源的引用,这里就不列出了,下面我们进行jta的配置 <bean id=”atomikosTransactionManager” class=”com.atomikos.icatch.jta.UserTransactionManager” init-method=”init” destroy-method=”close”> <property name=”forceShutdown”><value>true</value></property> </bean> <bean id=”atomikosUserTransaction” class=”com.atomikos.icatch.jta.UserTransactionImp”> <property name=”transactionTimeout” value=”240”/> </bean> <bean id=”transactionManager” class=“org.springframework.transaction.jta.JtaTransactionManager”> <property name=”transactionManager” ref=”atomikosTransactionManager”/> <property name=”userTransaction” ref=”atomikosUserTransaction”/> <property name=”allowCustomIsolationLevels” value=”true” /> </bean> <!----> <aop:aspect-autoproxy proxy-target-class=”true”/> <!—扫描jar包中注解bean--> <context:component-scan base-package=”com.zohan.base”/> <!—事务的切入点配置---> <aop:config proxy-target-calss=”true”> <aop:advisor pointcut=”execution(* com.zohan..*ServiceImpl.*(..))” advice-ref=”txAdvice”/> </aop:config> <tx:annotation-driven proxy-target-class=”true” transaction-manager=”transactionManager”/> <tx:advice id=”txAdvice” transaction-manager=” transactionManager”> <tx:attributes> <tx:method name=”save*” /> <tx:method name=”get*” read-only=”true” /> </tx:attributes> </ tx:advice>
在dao层使用sessionFactory, 为实现dao层的读写分离,把dao层分离出读和写的方法抽象成不同的接口和实现类,分别注入不同的sessionFactory。
如何在dao层使用自定义的sessionFactory?这样的场景一般是特定的业务需要特定的数据库,可能是一是一个service层调用不同的dao方法。那这样的我们可以在dao层实现不同的数据库操作,一般的实现方式是在dao层注入sessionFactory,dao实现类继承HibernateDaoSupport,并实现initDao方法,在initDao方法使用使用setSessionFactory方法实现HibernateDaoSupport的sessionFactory的设置。
配置OpenSessionInViewFilter,在web.xml中针对每个sessionFactory配置OpenSessionInViewFilter。
总结:在传统业务中如果单纯的为了减少数据的压力而采读写分离,而采用分布式事务管理其实是不合适的。采用分布式事务管理因采用两阶段提交,增加了响应时间,无形的增加了应用的压力,因此鄙人认为这并不是一个好的减少数据库压力的解决方案。我们可以从其他方式来解决数据库的压力,比如缓存。