<< 我收藏的链接(32) | 首页 | 在Windows上安装Trac并集成SVN >>

使用Hibernate Shards来访问多个水平分区数据库

Hibernate Shards is a framework that is designed to encapsulate and minimize this complexity by adding support for horizontal partitioning to Hibernate Core.

即,Shards可以帮助程序透明地访问网络上多个水平划分数据库(分片)。下面主要介绍使用Hibernate Shards来访问多个水平分区数据库的配置。Shards的功能:

Hibernate Shards key features:

  • Standard Hibernate programming model - Hibernate Shards allows you to continue using the Hibernate APIs you know and love: SessionFactory, Session, Criteria, Query. If you already know how to use Hibernate, you already know how to use Hibernate Shards.
  • Flexible sharding strategies - Distribute data across your shards any way you want. Use one of the default strategies we provide or plug in your own application-specific logic.
  • Support for virtual shards - Think your sharding strategy is never going to change? Think again. Adding new shards and redistributing your data is one of the toughest operational challenges you will face once you've deployed your shard-aware application. Hibernate Sharding supports virtual shards, a feature designed to simplify the process of resharding your data.
  • Free/open source - Hibernate Shards is licensed under the LGPL (Lesser GNU Public License)

Shards配置

 You'll be pleased to know that the process of configuring your application to use Hibernate Shards is not radically different. The main difference is that we're providing connectivity information for multiple datasources, and we're also describing our desired sharding behavior via a ShardStrategyFactory. Let's look at some sample configuration code for our weather report application, which we're going to run with 3 shards.

1     public SessionFactory createSessionFactory() {
2         Configuration prototypeConfig = new Configuration().configure("shard0.hibernate.cfg.xml");
3         prototypeConfig.addResource("weather.hbm.xml");
4         List<ShardConfiguration> shardConfigs = new ArrayList<ShardConfiguration>();
5         shardConfigs.add(buildShardConfig("shard0.hibernate.cfg.xml"));
6         shardConfigs.add(buildShardConfig("shard1.hibernate.cfg.xml"));
7         shardConfigs.add(buildShardConfig("shard2.hibernate.cfg.xml"));
8         ShardStrategyFactory shardStrategyFactory = buildShardStrategyFactory();
9         ShardedConfiguration shardedConfig = new ShardedConfiguration(
10            prototypeConfig,
11            shardConfigs,
12            shardStrategyFactory);
13        return shardedConfig.buildShardedSessionFactory();
14    }
15
16    ShardStrategyFactory buildShardStrategyFactory() {
17        ShardStrategyFactory shardStrategyFactory = new ShardStrategyFactory() {
18            public ShardStrategy newShardStrategy(List<ShardId> shardIds) {
19                RoundRobinShardLoadBalancer loadBalancer = new RoundRobinShardLoadBalancer(shardIds);
20                ShardSelectionStrategy pss = new RoundRobinShardSelectionStrategy(loadBalancer);
21                ShardResolutionStrategy prs = new AllShardsShardResolutionStrategy(shardIds);
22                ShardAccessStrategy pas = new SequentialShardAccessStrategy();
23                return new ShardStrategyImpl(pss, prs, pas);
24            }
25        };
26        return shardStrategyFactory;
27    }
28
29    ShardConfiguration buildShardConfig(String configFile) {
30        Configuration config = new Configuration().configure(configFile);
31        return new ConfigurationToShardConfigurationAdapter(config);
32    }
  

 

So what's going on here? First, you'll notice that we're actually allocating four Configurations. The first Configuration we allocate (line 2) is the prototype Configuration. The ShardedSessionFactory we eventually construct (line 13) will contain references to 3 standard SessionFactory objects. Each of these 3 standard SessionFactory objects will have been constructed from the prototype configuration. The only attributes that will differ across these standard SessionFactory objects are:

  • connection.url

  • connection.user

  • connection.password

  • connection.datasource

  • cache.region_prefix

The three ShardConfiguration objects we're loading (lines 5 - 7) will be consulted for the shard-specific database url, database user, database password, datasource identifier, cache region prefix, and that's all. (For a discussion of what these properties are and how they are used, please consult the Hibernate Core documentation.) This means that if you change the connection pool parameters in shard1.hibernate.cfg.xml, those parameters will be ignored. If you add another mapping file to the Configuration loaded with the properties defined in shard2.hibernate.cfg.xml, that mapping will be ignored. With the exception of the properties listed above, the configuration of our shard-aware SessionFactory comes entirely from the prototype Configuration. This may seem a bit strict, but the sharding code needs to assume that all shards are identically configured.

If you're looking at this code and thinking it seems a bit silly to provide fully-formed configuration documents that, save a couple special properties, are ignored, rest assured we've looked at this code and thought the same thing. That's why the ShardedConfiguration constructor takes a List<ShardConfiguration> as opposed to a List<Configuration>. ShardConfiguration is an interface so you can make the shard-specific configuration data available any way you'd like. In our example we're using an implementation of this interface that wraps a standard Configuration (line 31) just to avoid introducing any unfamiliar configuration mechanisms.

Once we've built our Configuration objects we need to put together a ShardStrategyFactory (line 8). A ShardStrategyFactory is an object that knows how to create the 3 types of strategies that programmers can use to control the sharding behavior of the system. For more information on these strategies please see the chapters titled Sharding Strategies.

Once we've instantiated our ShardStrategyFactory we can construct a ShardedConfiguration (line 9), and once we've constructed our ShardedConfiguration we can ask it to create a ShardedSessionFactory (line 13). It's important to note that ShardedSessionFactory extends SessionFactory. This means we can return a standard SessionFactory (line 1). Our application's Hibernate code doesn't need to know that it's interacting with sharded data.

Now let's take a look at the configuration and mapping files that we loaded in. You'll definitely recognize them, but there are a few key additions and modifications related to sharding.

 1    <!-- Contents of shard0.hibernate.cfg.xml -->
 2    <hibernate-configuration>
 3      <session-factory name="HibernateSessionFactory0"> <!-- note the different name -->
 4        <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
 5        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
 6        <property name="connection.url">jdbc:mysql://dbhost0:3306/mydb</property>
 7        <property name="connection.username">my_user</property>
 8        <property name="connection.password">my_password</property>
 9        <property name="hibernate.connection.shard_id">0</property> <!-- new -->
 10      <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property> <!-- new -->
 11    </session-factory>
 12  </hibernate-configuration>
                

 

 1    <!-- Contents of shard1.hibernate.cfg.xml -->
 2    <hibernate-configuration>
 3      <session-factory name="HibernateSessionFactory1"> <!-- note the different name -->
 4        <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
 5        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
 6        <property name="connection.url">jdbc:mysql://dbhost1:3306/mydb</property>
 7        <property name="connection.username">my_user</property>
 8        <property name="connection.password">my_password</property>
 9        <property name="hibernate.connection.shard_id">1</property> <!-- new -->
 10      <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property> <!-- new -->
 11    </session-factory>
 12  </hibernate-configuration>
                

We'll skip the contents of shard2.hibernate.cfg.xml because the pattern should by now be obvious. We're giving each session factory a unique name via the name attribute of the session-factory element, and we're associating each session factory with a different database server. We're also giving each session factory a shard id. This is required. If you try to configure a ShardedSessionFactory with a Configuration object that does not have a shard id you'll get an error. At the moment we require that the shard id of one of your session factories be 0. Beyond that, the internal representation of a shard id is a java.lang.Integer so all values within that range are legal. Finally, each shard that is mapped into a ShardedSessionFactory must have a unique shard id. If you have a duplicate shard id you'll get an error.

The other noteworthy addition is the rather verbose but hopefully descriptive "hibernate.shard.enable_cross_shard_relationship_checks." You can read more about this in the chapter on limitations.

Now let's still see how the mapping file has changed.

<hibernate-mapping package="org.hibernate.shards.example.model">
    <class name="WeatherReport" table="WEATHER_REPORT">
        <id name="reportId" column="REPORT_ID" type="long">
            <generator class="org.hibernate.shards.id.ShardedTableHiLoGenerator"/>
        </id>
        <property name="continent" column="CONTINENT"/>
        <property name="latitude" column="LATITUDE"/>
        <property name="longitude" column="LONGITUDE"/>
        <property name="temperature" column="TEMPERATURE"/>
        <property name="reportTime" type="timestamp" column="REPORT_TIME"/>
    </class>
</hibernate-mapping>
                

The only meaningful change in the mapping file from the non-sharded version is in our selection of a shard-aware id generator. We'll cover id generation in more detail in the chapter on Shard Strategies.

 




发表评论 发送引用通报