京山游侠

专注技术,拒绝扯淡
posts - 50, comments - 868, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

在SpringSide2.0中使用多个数据库

Posted on 2008-02-01 22:49 京山游侠 阅读(4162) 评论(4)  编辑  收藏 所属分类: SpringSide开发实战
为了提高网站将来向外扩展的能力,我是用了数据分割的架构,这就要求我的网站能够灵活的访问多个数据库,如果是直接操作JDBC,这根本就不成问题。但是在SpringSide2.0中,由于集成了Hibernate,所以对数据的访问大部分时候都是通过配置实现的。

要想在SpringSide2.0中使用多个数据库,最简单的办法就是配置多个sessionFactory,下面是我的探索步骤。

首先,要修改src/resources/config目录下的jdbc.properties文件,定义多个数据库的连接,如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.urlYumDaysIndex
=jdbc:mysql://localhost:3306/YumDaysIndex?useUnicode=true&characterEncoding=utf8
jdbc.urlYumDays001
=jdbc:mysql://localhost:3306/YumDays001?useUnicode=true&characterEncoding=utf8

然后,修改src/resources/spring目录下的dataAccessContext-hibernate.xml文件,定义多个数据源,它们之间只有url属性不同:
    <!-- 数据源定义,使用Apache DBCP 连接池 -->
    
<bean id="dataSourceYumDaysIndex" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName" value="${jdbc.driverClassName}"/>
        
<property name="url" value="${jdbc.urlYumDaysIndex}"/>
        
<property name="username" value="${jdbc.username}"/>
        
<property name="password" value="${jdbc.password}"/>
    
</bean>
    
    
<!-- 数据源定义,使用Apache DBCP 连接池 -->
    
<bean id="dataSourceYumDays001" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName" value="${jdbc.driverClassName}"/>
        
<property name="url" value="${jdbc.urlYumDays001}"/>
        
<property name="username" value="${jdbc.username}"/>
        
<property name="password" value="${jdbc.password}"/>
    
</bean>

然后,还是修改这个文件,定义多个sessionFactory,它们之间只有数据源的属性不同:
    <!--Hibernate SessionFatory-->
    
<bean id="sessionFactoryIndex" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        
<property name="dataSource" ref="dataSourceYumDaysIndex"/>
        
<property name="annotatedClasses">
            
<list>
                
<value>com.yumdays.model.Catalog</value>
                
<value>com.yumdays.model.Statistic</value>
            
</list>
        
</property>
        
<property name="hibernateProperties">
            
<props>
              
<!-- see /components/orm/hibernate/meta/dialect.properties for all Dialect -->
                
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                
<prop key="hibernate.show_sql">true</prop>
                
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                
<prop key="hibernate.cache.use_query_cache">true</prop>
            
</props>
        
</property>
    
</bean>
    
    
<!--Hibernate SessionFatory-->
    
<bean id="sessionFactory001" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        
<property name="dataSource" ref="dataSourceYumDays001"/>
        
<property name="annotatedClasses">
            
<list>
            
</list>
        
</property>
        
<property name="hibernateProperties">
            
<props>
              
<!-- see /components/orm/hibernate/meta/dialect.properties for all Dialect -->
                
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                
<prop key="hibernate.show_sql">true</prop>
                
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                
<prop key="hibernate.cache.use_query_cache">true</prop>
            
</props>
        
</property>
    
</bean>

再然后,还是修改这个文件,定义多个不同的事务管理器,它们之间只有sessionFactory属性不同,如下:
    <!--Hibernate TransactionManager-->
    
<bean id="transactionManagerIndex" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        
<property name="sessionFactory" ref="sessionFactoryIndex"/>
    
</bean>
    
<bean id="transactionManager001" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        
<property name="sessionFactory" ref="sessionFactory001"/>
    
</bean>

以上的这些修改是最基本的,就是把sessionFactory和事务管理器都定义为多份的,以后,在要使用到这些东西的时候,就不能使用Spring提供的自动按照name匹配的方便了,必须得自己指定。
利用SpringSide2.0,只需要编写表示Model的POJO,就可以很容易得到数据访问层的代码,比如,我的网站有一个表示文章分类的数据表,其对应的Model如下:
package com.yumdays.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name
="catalogs")
public class Catalog implements Serializable {
    
private String id;
    
private String name;
    
    @Id
    @GenericGenerator(name
="system-uuid",strategy="uuid")
    
public String getId() {
        
return id;
    }
    
public void setId(String id) {
        
this.id = id;
    }
    
public String getName() {
        
return name;
    }
    
public void setName(String name) {
        
this.name = name;
    }
}

那么,其DAO层的代码如下:
package com.yumdays.service;

import org.springside.core.dao.HibernateEntityDao;
import com.yumdays.model.Catalog;

public class CatalogManager extends HibernateEntityDao<Catalog> {

}

相当的简洁,该CatalogManager类提供了非常完整的find、get、save等功能。下一步,将这个类是用Spring管理起来的时候,就必须自己指定sessionFactory了,因此,在src/resources/spring/目录下的serviceContext.xml文件中,配置的形式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-lazy-init="true" default-autowire="byName">
           
<bean id="catalogManager" class="com.yumdays.service.CatalogManager">
                   
<property name="sessionFactory" ref="sessionFactoryIndex"/>
           
</bean>
           
<bean id="statisticManager" class="com.yumdays.service.StatisticManager">
                   
<property name="sessionFactory" ref="sessionFactoryIndex"/>
           
</bean>
</beans>

至于事务管理器,是在配置事务的时候用到的,因此,修改src/resources/spring目录下的applicationContext.xml文件,如下:
    <!-- 以AspectJ方式 定义 AOP -->
    
<aop:config proxy-target-class="true">
        
<!-- 注意,请把第2个*号换为项目package -->
        
<aop:advisor pointcut="execution(* *..service.CatalogManager.*(..))" advice-ref="txAdviceIndex"/>
        
<aop:advisor pointcut="execution(* *..service.StatisticManager.*(..))" advice-ref="txAdviceIndex"/>
    
</aop:config>

    
<!-- 基本事务定义,使用transactionManager作事务管理,默认get*方法的事务为readonly,其余方法按默认设置.
             默认的设置请参考Spring文档事务一章. 
-->
    
<tx:advice id="txAdviceIndex" transaction-manager="transactionManagerIndex">
        
<tx:attributes>
            
<tx:method name="get*" read-only="true"/>
            
<tx:method name="find*" read-only="true"/>
            
<tx:method name="*"/>
        
</tx:attributes>
    
</tx:advice>

OK,快速启动项目,但是还是没有成功,报出的错误提示说没有定义name为transactionManager的bean。经过我这么一改,当然没有定义这个bean了,但是我也没有用它啊?我用的是transactionManagerIndex,经过多次排查,我仍然没有找出问题的症结所在。

此外,在web.xml文件中配置的org.springframework.orm.hibernate3.support.OpenSessionInViewFilter也起不到作用了,因为我不知道这个类能不能管理多个SessionFactory,似乎是不行的。

由此可见,使用默认值的地方太多了,也是会害死人的。我已经向SpringSide的老大江南白衣请教这个问题了,暂时还没有得到回复。

为了使我的项目能够顺利继续,我只有采取另外的变通方法,那就是把YumDaysIndex和YumDaysContent作为两个不同的项目分别开发。但是这样并不能够一劳永逸,将来当数据库的负载达到极限,需要让主从数据库服务器分开,主服务器只提供写操作,从服务器只提供读操作,我还得把写数据库和读数据库的代码分到不同的项目中进行开发。

评论

# re: 在SpringSide2.0中使用多个数据库  回复  更多评论   

2008-02-02 09:18 by 456
多个数据库之间的事务你怎么处理?
使用JTA是一个比较好的解决方法。

# re: 在SpringSide2.0中使用多个数据库  回复  更多评论   

2008-02-02 19:30 by 海边沫沫
JTA往往都是由商业的中间件厂商提供,价格很贵的。而且不同厂商提供的实现不一样,要根据使用什么样的中间件来配置,不具备通用性。

在一个使用WebLogic 7.0、8.1或更高版本的环境中,一般会优先选用特定于WebLogic的 WebLogicJtaTransactionManager 类来取代基础的 JtaTransactionManager 类。在WebLogic环境中,该类提供了对Spring事务定义的完全支持,超过了标准的JTA语义。它的特性包括:支持事务名,支持为每个事务定义隔离级别,以及在任何环境下正确地恢复事务的能力。

在WebSphere 5.1、5.0和4环境下,可以使用Spring的 WebSphereTransactionManagerFactoryBean 类。这是一个工厂类,通过WebSphere的 静态 访问方法获取到JTA TransactionManager 实例。(这些静态方法在每个版本的WebSphere中都不同。)一旦通过工厂bean获取到JTA TransactionManager 实例,就可以使用该实例装配一个Spring的 JtaTransactionManager bean,它封装了JTA UserTransaction,提供增强的事务语义。

# re: 在SpringSide2.0中使用多个数据库  回复  更多评论   

2008-02-17 12:43 by 93ttq
非常 不错的好

# re: 在SpringSide2.0中使用多个数据库  回复  更多评论   

2008-02-21 11:16 by zhangv
那就手动把你的trasactionmanager注入到相应的sessionfactory

只有注册用户登录后才能发表评论。


网站导航: