这里做了一个简单的, 对主要部分的翻译, 算是一个笔记
原文: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事务, 数据共享, 测试等, 这里不做一一展开
分享到:
相关推荐
该压缩包文件包含了一个基于SpringMVC、Hibernate和Spring框架的权限管理系统完整项目,适合学习和实战。这个项目的核心目标是实现对用户权限的有效管理,包括用户登录、角色分配、资源权限控制等功能。以下是关于...
《使用Hibernate Shards对数据进行切分》 在大规模分布式系统中,数据库的扩展性问题一直是开发者关注的重点。Hibernate Shards是Hibernate框架的一个扩展,它提供了数据库分片(Sharding)的功能,帮助解决高并发...
在"struts+hibernate+spring 对数据库进行增删改查"的场景中,Struts会扮演前端控制器的角色,解析用户的请求,将数据传递给业务层进行处理。 **Hibernate** 是一个对象关系映射(ORM)框架,它简化了Java应用程序...
"spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...
SpringMVC4.3+Spring+HIbernate4.3简单数据库实例 亲测可用 新建数据库 ssh_person,运行后表自动创建 jdk 8 ,tomcat 8, eclipse 访问 http://localhost:8080/SpringMVC_Spring_Hibernate/
Spring是一个全面的Java企业级应用开发框架,而Hibernate则是一个优秀的对象关系映射(ORM)工具,它简化了数据库操作。本文将深入探讨如何将Spring与Hibernate整合,以实现对数据库的简单添加记录功能,这对于初学...
在Java领域,Spring框架通过与ORM工具如Hibernate的集成,使得开发者能够在不直接编写SQL语句的情况下实现数据库操作。 **场景示例**:假设我们需要创建一个DAO(Data Access Object)接口,该接口接收一个模糊匹配...
用到知识是webwork做表现层 spring的事务层,IOC AOP hibernate 数据库的映射 Model view control传说中的三层+service 数据库是sqlserver 2005 更重要的是提供所有的.jar框架包
接下来,Hibernate作为ORM工具,它将Java对象与数据库表进行映射,使得开发者可以使用面向对象的方式来操作数据库,而无需关心SQL的具体细节。在整合中,Spring可以帮助管理Hibernate的SessionFactory和Session,...
总的来说,"拍卖系统(Struts1+Spring+Hibernate)Mysql数据库"是一个典型的Java Web项目,涉及到了前端、后端以及数据库的设计和开发,对于学习和理解SSH框架以及Mysql数据库的使用具有很高的参考价值。通过深入...
6. **编写实体类**:根据数据库表结构,创建对应的Java实体类,并使用Hibernate的注解(如@Entity、@Table、@Id等)进行ORM映射。 7. **DAO和Service层**:创建DAO接口和实现类,利用Hibernate的Session进行数据库...
`spring-context.xml`配置文件中通常会包含`<bean>`标签来定义DataSource,使用`ojdbc.jar`驱动,并通过`HibernateSessionFactoryBean`配置Hibernate的相关设置,如`hibernate.dialect`、`hibernate.show_sql`等。...
Spring作为一个全面的开发框架,提供了依赖注入、AOP(面向切面编程)、事务管理等核心功能,而Hibernate则是一个优秀的对象关系映射(ORM)框架,使得Java开发者可以更加方便地操作数据库。在本案例中,我们将探讨...
在IT行业中,开发高效、可维护的Web应用程序是至关重要的,而Tapestry、Hibernate和Spring框架的结合使用,能够帮助我们实现这一目标。本文将深入探讨如何在实际项目中运用这三个技术,以及它们如何协同工作,以实现...
3. 实现DAO:创建数据访问对象(DAO),使用Hibernate Session进行数据库操作。DAO接口可以由Spring管理,通过@Autowired注解实现自动注入。 4. 编写Service:定义业务服务层,封装业务逻辑,同样由Spring管理。...
Hibernate是一个对象关系映射(ORM)工具,它简化了数据库操作,而Spring则是一个全面的企业级应用框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性。将Hibernate与Spring整合可以充分...
Hibernate是一个对象关系映射(Object-Relational Mapping,ORM)框架,它允许开发者使用面向对象的方式操作数据库。Hibernate简化了数据库操作,通过XML或注解方式将Java类与数据库表进行映射,实现了数据的透明...
Hibernate是一款优秀的ORM框架,能够连接并操作数据库,包括保存和修改数据。Spring MVC是Java的web框架,能够将Hibernate集成进去,完成数据的CRUD。Hibernate使用方便,配置响应的XML文件即可。由于spring3.x,基于...
- DAO(数据访问对象)类:使用Hibernate API与数据库进行交互。 - 实体类:对应数据库表的Java对象,包含getter和setter方法。 通过分析和学习这个SSH-test项目,开发者可以深入理解SSH框架的工作原理和实际应用,...