`

使用hibernate, spring做数据库水平切分

阅读更多
这里做了一个简单的, 对主要部分的翻译, 算是一个笔记

原文:http://www.jroller.com/kenwdelong/entry/horizontal_database_partitioning_with_spring

这里以user表为例来做水平切分, 将与user相关的信息(如user的profile, user创建的内容等)放在同一个分区中, 同时使用GLUD(user的主键和分区id的组合)来作为定位一条user记录的key值
这里是一种解决方案(类似Hibernate Shards):
一个hibernate session factory对应一个数据库, 比如有user1, user2两个数据库, 则有两个session factory, 以此类推. 最后会创建两个ProfileService实例来对应不同的数据源, 在调用ProfileService前, 将通过一个Spring拦截器获取user的主键, 然后通过GLUD来确定该user存储在哪个数据库中, 最后决定调用哪个ProfileService实例
其实Spring也有一种解决方案, 那就是使用AbstractRoutingDataSource, 该方案只需要一个SessionFatory和一个ProfileService, 它通过借助Spring的AbstractRoutingDataSource和一些规则自动定位到指定的DataSource上.
下面来说说Hibernate Shards的一些缺点, 首先这个项目还比较新, 也不是很活跃, 稳定性有待考量, 此外一个datasource对应一个session factory灵活性很差, 比如数据库服务器达到myspace这种规模, 创建session factory消耗的资源几乎是不可想象的.还有一点,就是在与Spring集成方面, 它的文档也是含糊不清, 因为它没法和LocalSessionFactoryBean一起工作, 因此要利用Spring的事务管理,还得自己去实现一个类似ShardsSessionFactoryBean的bean, 这个也是我非所愿的
经过比较之后, 下面是我们的实现
首先创建一个GLUD数据库, 它包含有主库(master)的user表(master_user), 该表保存了用户的主键和email信息(也可以是唯一标识一条user记录的其他信息), 另一个是partition_map表, 也就是分区表id, 通过对user的主键hash之后能映射到某个分区id, 这样当你拿到一个user的pk值或者任意的唯一标识值之后, 就可以确定该记录存放在那个分区中.
通过写了一个Spring AOP的拦截器来获取记录所在的分区, 所有要使用分区数据库的service都会被该拦截器路由到指定的分区中, 同时规定, 使用分区数据的Service的所有方法的第一个参数必须为: 一个user 对象, 一个user的pk, 或者其他能唯一标识一条user记录的值, 拦截器代码如下:
public Object selectExistingPartitionWithUser(ProceedingJoinPoint jp, LocatePreexistingUser annotation, User user) throws Throwable 
    {
        GludEntry gludEntry = getGludService().getGludEntryForExistingUser(user);
        int partitionNumber = gludEntry.getDatabasePartition();
        datasourceNumberCache.set(partitionNumber);
        Object returnValue = null;
        try
        {
            returnValue = jp.proceed();
        }
        finally
        {
            datasourceNumberCache.remove();
        }
        return returnValue;
    }


其中datasourceNumberCache是一个用来保存分区id的ThreadLocal<Integer>变量
为了处理各种情况, 这里还用到了annocations,
在所有需要使用拦截的方法加上如下声明:
    @Around(value="@annotation(annotation) && args(user, ..)", argNames="annotation,user")

LocatePreexistingUser的定义如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LocatePreexistingUser
{
    public UserIdentifier userIdentifier() default USER_OBJECT;
    
    public boolean userUpdate() default false;
}

UserIdentifier是一个枚举类型, 其值为:USER_OBJECT, EMAIL, and USER_PK.当对唯一标识字段值修改时(比如, 修改email), 需要做如下设置:
@LocatePreexistingUser(userUpdate=true)
public void updateEmail(User user, String newEmail) 
{ ... }

而在拦截器中需要做如下设置:
if(annotation.userUpdate)
{
    // tell GLUD service to update its master_user record
}

当hibernate在访问数据库的时候, 将通过datasource取得一个connection, PartitionRoutingDataSource(AbstractRoutingDataSource实现类) 将通过ThreadLocal取得分区id,然后取得记录所在的DataSource:
protected Object determineCurrentLookupKey()
    {
        Integer datasourceNumber = DatasourceSwitchingAspect.datasourceNumberCache.get();
        return datasourceNumber;
    }

datasource bean xml配置如下:
<bean id="userDataSource" class="PartitionRoutingDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.Integer">
                <entry key="1" value-ref="user1DataSource"/>
                <entry key="2" value-ref="user2DataSource"/>
            </map>
        </property>
    </bean>

hibernate session factory xml配置:
<bean id="userSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="userDataSource"/>
        etc etc
    </bean>

从上面的配置可以看出, 对分区进行扩展将会非常简单, 但是还有一个问题, 在spring中开启一个事务之前必须获取分区的id, 因此分区服务拦截器必须在事务拦截器之前被执行, 因此还需要做如下设置:
<aop:config>
        <aop:pointcut id="profileServicePointcut" expression="execution(* *..ProfileService.*(..))"/>
        <aop:advisor advice-ref="userTxAdvice" pointcut-ref="profileServicePointcut" order="2"/>        
    </aop:config>

 
在使用spring, hibernate做分区处理的时候还有一些地方需要注意, 比如, 二级缓存, jta事务, 数据共享, 测试等, 这里不做一一展开
分享到:
评论
1 楼 lz_cleaner 2009-12-07  
存在这样的一个疑问,我怎么样把user1和user2中符合条件的user都取出来并按一个字段排序呢?

是分别取出来再合并么,那样的话怎么解决排序的问题呢?

希望你能解答一二吧,这个问题困扰好几天了。

相关推荐

    权限管理系统springmvc hibernate spring 完整项目带数据库

    该压缩包文件包含了一个基于SpringMVC、Hibernate和Spring框架的权限管理系统完整项目,适合学习和实战。这个项目的核心目标是实现对用户权限的有效管理,包括用户登录、角色分配、资源权限控制等功能。以下是关于...

    使用 Hibernate Shards 对数据进行切分

    《使用Hibernate Shards对数据进行切分》 在大规模分布式系统中,数据库的扩展性问题一直是开发者关注的重点。Hibernate Shards是Hibernate框架的一个扩展,它提供了数据库分片(Sharding)的功能,帮助解决高并发...

    struts+hibernate+spring 对数据库进行增删改查

    在"struts+hibernate+spring 对数据库进行增删改查"的场景中,Struts会扮演前端控制器的角色,解析用户的请求,将数据传递给业务层进行处理。 **Hibernate** 是一个对象关系映射(ORM)框架,它简化了Java应用程序...

    spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目

    "spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...

    SpringMVC4.3+Spring+HIbernate4.3简单数据库实例 亲测可用

    SpringMVC4.3+Spring+HIbernate4.3简单数据库实例 亲测可用 新建数据库 ssh_person,运行后表自动创建 jdk 8 ,tomcat 8, eclipse 访问 http://localhost:8080/SpringMVC_Spring_Hibernate/

    spring+hibernate整合实现简单数据库添加记录

    Spring是一个全面的Java企业级应用开发框架,而Hibernate则是一个优秀的对象关系映射(ORM)工具,它简化了数据库操作。本文将深入探讨如何将Spring与Hibernate整合,以实现对数据库的简单添加记录功能,这对于初学...

    spring和数据库层的结合

    在Java领域,Spring框架通过与ORM工具如Hibernate的集成,使得开发者能够在不直接编写SQL语句的情况下实现数据库操作。 **场景示例**:假设我们需要创建一个DAO(Data Access Object)接口,该接口接收一个模糊匹配...

    webwork hibernate spring 实现留言板,远程登录

    用到知识是webwork做表现层 spring的事务层,IOC AOP hibernate 数据库的映射 Model view control传说中的三层+service 数据库是sqlserver 2005 更重要的是提供所有的.jar框架包

    struts hibernate spring增删查改

    接下来,Hibernate作为ORM工具,它将Java对象与数据库表进行映射,使得开发者可以使用面向对象的方式来操作数据库,而无需关心SQL的具体细节。在整合中,Spring可以帮助管理Hibernate的SessionFactory和Session,...

    拍卖系统 (struts1+spring+hibernate) Mysql数据库

    总的来说,"拍卖系统(Struts1+Spring+Hibernate)Mysql数据库"是一个典型的Java Web项目,涉及到了前端、后端以及数据库的设计和开发,对于学习和理解SSH框架以及Mysql数据库的使用具有很高的参考价值。通过深入...

    springmvc+spring+hibernate

    6. **编写实体类**:根据数据库表结构,创建对应的Java实体类,并使用Hibernate的注解(如@Entity、@Table、@Id等)进行ORM映射。 7. **DAO和Service层**:创建DAO接口和实现类,利用Hibernate的Session进行数据库...

    基于注解的springMVC+hibernate+oracle包含数据库查询

    `spring-context.xml`配置文件中通常会包含`&lt;bean&gt;`标签来定义DataSource,使用`ojdbc.jar`驱动,并通过`HibernateSessionFactoryBean`配置Hibernate的相关设置,如`hibernate.dialect`、`hibernate.show_sql`等。...

    现有Mysql数据库,写Spring + Hibernate的配置文件

    Spring作为一个全面的开发框架,提供了依赖注入、AOP(面向切面编程)、事务管理等核心功能,而Hibernate则是一个优秀的对象关系映射(ORM)框架,使得Java开发者可以更加方便地操作数据库。在本案例中,我们将探讨...

    tapestry hibernate Spring应用及组件的使用

    在IT行业中,开发高效、可维护的Web应用程序是至关重要的,而Tapestry、Hibernate和Spring框架的结合使用,能够帮助我们实现这一目标。本文将深入探讨如何在实际项目中运用这三个技术,以及它们如何协同工作,以实现...

    Struts2 hibernate spring 整合案例

    3. 实现DAO:创建数据访问对象(DAO),使用Hibernate Session进行数据库操作。DAO接口可以由Spring管理,通过@Autowired注解实现自动注入。 4. 编写Service:定义业务服务层,封装业务逻辑,同样由Spring管理。...

    hibernate与spring整合demo

    Hibernate是一个对象关系映射(ORM)工具,它简化了数据库操作,而Spring则是一个全面的企业级应用框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性。将Hibernate与Spring整合可以充分...

    Spring mvc hibernate spring 开发所需jar包

    Hibernate是一个对象关系映射(Object-Relational Mapping,ORM)框架,它允许开发者使用面向对象的方式操作数据库。Hibernate简化了数据库操作,通过XML或注解方式将Java类与数据库表进行映射,实现了数据的透明...

    Spring hibernate SpringMVC整合对数据库操作

    Hibernate是一款优秀的ORM框架,能够连接并操作数据库,包括保存和修改数据。Spring MVC是Java的web框架,能够将Hibernate集成进去,完成数据的CRUD。Hibernate使用方便,配置响应的XML文件即可。由于spring3.x,基于...

    struts2 hibernate spring 项目

    - DAO(数据访问对象)类:使用Hibernate API与数据库进行交互。 - 实体类:对应数据库表的Java对象,包含getter和setter方法。 通过分析和学习这个SSH-test项目,开发者可以深入理解SSH框架的工作原理和实际应用,...

Global site tag (gtag.js) - Google Analytics