数据库分片(shard)是一种在数据库的某些表变得特别大的时候采用的一种技术。mysql
经过按照必定的维度将表切分,可使该表在经常使用的检索中保持较高的效率,而那些不经常使用的记录则保存在低访问表中。好比:销售记录按照时间来切分。(横向切分)git
也能够根据地域进行拆分,使得每一个地区访问本身的表从而进行负载均衡。(纵向切分)github
也能够纵横切分,使表拆的更细致。sql
也能够分库,让不一样的数据存放在不一样的服务器上,从而进一步均衡负载。数据库
当遇到这样的事情的时候,若是不是采用了MongoDB这种自动拆表的工具,通常来讲,都要本身实现一下切表的策略。其实,Hibernate中已经提供了一个很好用的包:服务器
Hiberante Shard,该包是Google贡献给Hibernate社区的。根据其资料显示,如今这个包仍是有些限制的。session
好比:不可以进行跨表的order by,不能实现跨表的distinct,不能采用基础数据类型(如int)做为ID的类型。app
可是它能够支持跨表的惟一ID,跨表的查询,跨表的累计...负载均衡
并且它彷佛只要少许的代码和简单的配置就可使用,看来它真的是一个很好的工具。值得一试。ide
很不幸,网上的例子太少了,只找到了一段例子代码:
这段代码下载以后运行了,因为数据量太少,而且生成在同一个表中,没法证实Hibernate Shards的做用。
官方网站的资料彷佛也是惜墨如金,没有解释的很是详细。
Shards如何配置,如何使用呢?
一个工程里,有的表要切分,有的没必要,如何作?
Shard和ebean如何结合使用呢?
带着这些课题,我开始了对Hibernate Shard的调查和研究。
Hibernate是一种ORM的包,它要有来自mapping.xml的“原型”,来自Java的Entity才可以造成ORMapping,还有一个数据库的表,它们的关系是一对一。
而若是采用分片技术,那么应该是一个原型,一个Entity,对应数据库的若干个结构相同的表。
在Hibernate Shard中,经过一个叫作“策略”的东西来完成这样的过程。
它容许经过定义不一样的策略,来将不一样分类的数据存放在不一样的表(乃至库)中,而这个要经过一组和hibernate.cfg.xml结构同样的配置文件来定义。就像下面这样:
1 <?xml version='1.0' encoding='utf-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 8 <property name="connection.url">jdbc:mysql://localhost/test</property> 9 <property name="connection.username">root</property> 10 <property name="connection.password">root</property> 11 <property name="connection.pool_size">10</property> 12 <property name="show_sql">true</property> 13 <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> 14 <property name="hbm2ddl.auto">validate</property> 15 <property name="hibernate.connection.shard_id">0</property> 16 <property name="hibernate.shard.enable_cross_shard_relationship_checks">false</property> 17 18 19 <mapping resource="ContactEntity.hbm.xml" /> 20 </session-factory> 21 22 </hibernate-configuration>
而后在生成SessionFactory的时候采用这样的代码:
1 private static SessionFactory createSessionFactory() { 2 Configuration prototypeCfg = new Configuration() 3 .configure("shard0.hibernate.cfg.xml"); 4 List<ShardConfiguration> shardCfgs = new ArrayList<ShardConfiguration>(); 5 shardCfgs.add(buildShardConfig("shard0.hibernate.cfg.xml")); 6 shardCfgs.add(buildShardConfig("shard1.hibernate.cfg.xml")); 7 ShardStrategyFactory strategyFactory = buildShardStrategyFactory(); 8 ShardedConfiguration shardedConfig = new ShardedConfiguration( 9 prototypeCfg, shardCfgs, strategyFactory); 10 return shardedConfig.buildShardedSessionFactory(); 11 }
而策略则分为三种:
ShardAccessStrategy
ShardSelectionStrategy
ShardResolutionStrategy
咱们须要上述三种策略才可以构建Hibernate的SessionFactory,就像下面这样。
1 private static ShardStrategyFactory buildShardStrategyFactory() { 2 return new ShardStrategyFactory() { 3 public ShardStrategy newShardStrategy(List<ShardId> shardIds) { 4 ShardSelectionStrategy ss = new MyShardSelectionStrategy(shardIds); 5 ShardResolutionStrategy rs = new MyShardResolutionStrategy(shardIds); 6 ShardAccessStrategy as = new SequentialShardAccessStrategy(); 7 return new ShardStrategyImpl(ss, rs, as); 8 } 9 }; 10 }
那么这三种策略都是什么,应该怎么配置呢?
这三种策略的文档说明和代码说明不怎么一致。(说实在的,这段文档真的没怎么看懂,幸运的是,它是OpenSource的)
ShardAccessStrategy 文档说,切片访问策略,它定义了Hibernate如何和多个Shard之间进行访问。
幸运的是,Hibernate已经为咱们建立了两个定义好了的ShardAccessStrategy,它们是:
SequentialShardAccessStrategy (顺序切片访问策略) 和 ParallelShardAccessStrategy(并行切片访问策略)
顺序切片访问策略 如其名称所言,它按照顺序切片,资料显示,它有可能在访问无序数据时性能偏低,如果这种状况,官方建议使用LoadBalancedSequentialShardAccessStrategy。
并行切片访问策略 如其名称所言,它提供了并行访问的策略,因此它同时要求提供一个并行策略执行器。 —— 听起来挺可贵,并且,介绍资料说——这超纲了。
先无论这么多吧,假设咱们访问的数据是一种,按地区、按年份增加的数据,每一个城市个月增加量都在10万~1百万,那么咱们要在这里采用什么策略呢?
数据是按照时间排序的,因此,咱们能够采用SequentialShardAccessStrategy,按月分片,而且按照地区分片。
ShardSelectionStrategy 文档说定义了如何建立一个新对象。
代码上的注释说:Determine the specific shard on which this object should reside
也就是说,这个是定义哪一个领域用来存放这条数据的。
ShardResolutionStrategy 文档说是表示如何将数据进行分流的。好比咱们提到的按地区、按月分片。那么数据须要根据这些条件存放在不一样的表中。而ShardResolutionStrategy就是帮助咱们来完成这个动做的。
代码注释上说:Determine the shards on which an object might live
在ShardStrategyFactory的newShardStrategy方法中传入的参数List<ShardId> shardIds会帮助咱们进行选择区域动做。ShardId会定位对应的Continent。
我跟踪了一下那段例子代码,这里的shardIds表示有多少个hibernate.cfg.xml文件中的不一样的shard_id字段的值。而ShardSelectionStrategy在Insert的时候会执行,而ShardResolutionStrategy则会在Select的时候执行。(update/delete还没有尝试。)
咱们能够在ShardSelectionStrategy中创建本身的策略,好比,按照时间,按照地区来区分数据。从而把数据存放在不一样的库中。
由于shardx.hibernate.cfg.xml指定了不一样的数据库,因此,到这里能够实现分库了。
而对于那些没必要分表的直接return 0便可。
初版的测试代码在这里下载。
---------------
下一步我将研究一下,如何分表和如何结合Ebean。