Preparation
1. Based on the Hibernate Shards data horizontal and vertical cutting (I)-Hibernate test environment project
2. Hibernate Shards uses commons logging to download the latest release version of a project. The version used here is 1.1.1.
3. in the horizontal and vertical cutting of Hibernate Shards data (I)-In the Hibernate test environment, we established an hbshards database in mysql. In order to test shards, we created another hbshards2 database, the contact table has the same structure.
4. Put the hibernate-shards.jar in the Hibernate Shards release package to the lib directory
Add hibernate-shards.jar to project reference
Put the commons-logging-1.1.1.jar in the commons logging release package to the lib directory
Add hibernate-shards.jar, commons-logging-1.1.1.jar in CLASSPATH
Hibernate Shards test project
For the sake of structure, define a ShardableEntity interface and let ContactEntity implement this interface:
public interface ShardableEntity { public String getIdentifier();}public class ContactEntity implements ShardableEntity { public String getIdentifier(){ return this._id; } //other code omitted is the same with previous post}
The conting file ContactEntity. hbm. xml is the same as the one in the previous article.
Because we need to store the contact data in two databases as slices, We need to configure the information of these two databases. Hibernate Shards solves this problem by defining two hibernate configuration files:
Shard0.hibernate. cfg. xml:
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
Shard1.hibernate. cfg. xml:
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
Shard0.hibernate. cfg. xml is the main configuration file. The SessionFactory object created for each shard comes from shard0.hibernate. cfg. xml in addition to the configuration of database connection information.
For the SessionFactory created for each other shard, the database connection information is stored in the corresponding configuration file (for example, shard1.hibernate. cfg. xml). The read content includes connection. url, connection. username, connection. password, connection. datasource. In order to load other shard configuration files by hibernate without throwing an exception, we still write the necessary configuration attributes in other shard configuration files.
The hibernate. connection. shard_id attribute defines an id for each shard and must have a shard whose shard_id is 0. Other shard_ids can be defined as any integer.
We assume that the contact id is an 8-bit string consisting of digits.
A simple cut policy for a contact is defined as: store the first character of the contact id 0-4 to shard0, and store the first character 5-9 to shard1.
To implement this policy, we need to implement two interfaces of hibernate shards.
Implementation of the ShardResolutionStrategy interface:
import java.util.List;import java.util.ArrayList;import org.hibernate.shards.strategy.resolution.ShardResolutionStrategy;import org.hibernate.shards.strategy.selection.ShardResolutionStrategyData;import org.hibernate.shards.ShardId;/* * a simple ShardResolutionStrategy implementation for our ContactEntity */public class MyShardResolutionStrategy implements ShardResolutionStrategy { private List<ShardId> _shardIds; public MyShardResolutionStrategy(List<ShardId> shardIds){ this._shardIds = shardIds; } public List selectShardIdsFromShardResolutionStrategyData( ShardResolutionStrategyData arg0){ List ids = new ArrayList(); String id = (String)arg0.getId(); if(id==null || id.isEmpty()) ids.add(this._shardIds.get(0)); else{ //our shard selection is identified by the //first char(number) in contact id //0-4 => shards0, 5-9 => shards1 Integer i = new Integer(id.substring(0, 1)); ids.add(this._shardIds.get(i/5)); } return ids; }}
Implementation of the ShardSelectionStrategy interface:
import java.util.List;import org.hibernate.shards.ShardId;import org.hibernate.shards.strategy.selection.ShardSelectionStrategy;/* * a simple ShardSelectionStrategy implementation for our ContactEntity */public class MyShardSelectionStrategy implements ShardSelectionStrategy { private List<ShardId> _shardIds; public MyShardSelectionStrategy(List<ShardId> shardIds){ this._shardIds=shardIds; } public ShardId selectShardIdForNewObject(Object obj) { if(obj instanceof ShardableEntity) { String id = ((ShardableEntity)obj).getIdentifier(); if(id==null || id.isEmpty()) return this._shardIds.get(0); Integer i = new Integer(id.substring(0, 1)); //our shard selection is identified by the //first char(number) in contact id //0-4 => shards0, 5-9 => shards1 return this._shardIds.get(i/5); } //for non-shardable entities we just use shard0 return this._shardIds.get(0); }}
The next step is how to use the test code of hibernate shards:
Import java. util. iterator; import java. util. list; import java. util. arrayList; import org. hibernate. session; import org. hibernate. sessionFactory; import org. hibernate. transaction; import org. hibernate. cfg. configuration; import org. hibernate. shards. *; import org. hibernate. shards. cfg. *; import org. hibernate. shards. strategy. *; import org. hibernate. shards. strategy. access. *; import org. hibernate. shards. strategy. resolution. *; import org. hibernate. shards. strategy. selection. *;
Public class Main {public static void main (String [] args) {HibernateShardsTest (args);} private static SessionFactory createSessionFactory () {// load the master configuration file, when you create a SessionFactory object for each shard, // use it as the prototype Configuration prototypeCfg = new Configuration (). configure ("shard0.hibernate. cfg. xml "); // List of configuration files for each shard <ShardConfiguration> shardCfgs = new ArrayList <ShardConfiguration> (); shardCfgs. add (buildShardConfig ("Shard0.hibernate. cfg. xml "); shardCfgs. add (buildShardConfig ("shard1.hibernate. cfg. xml "); // The factory object ShardStrategyFactory strategyFactory = buildShardStrategyFactory (); ShardedConfiguration shardedConfig = new ShardedConfiguration (prototypeCfg, shardCfgs, strategyFactory ); // return a ShardedSessionFactory object return shardedConfig. buildShardedSessionFactory ();} private static ShardStrategyFactory B UildShardStrategyFactory () {ShardStrategyFactory = new ShardStrategyFactory () {// factory class public ShardStrategy newShardStrategy (List <ShardId> shardIds) of the Custom Data slicing policy for testing) {ShardSelectionStrategy ss = new MyShardSelectionStrategy (shardIds); ShardResolutionStrategy rs = new MyShardResolutionStrategy (shardIds); ShardAccessStrategy as = new shard (); return new ShardStrategyImp L (ss, rs, as) ;}}; return factory ;}private static ShardConfiguration buildShardConfig (String configFile) {Configuration config = new Configuration (). configure (configFile); return new ConfigurationToShardConfigurationAdapter (config);} private static void HibernateShardsTest (String [] args) {String loginId = "RicCC@cnblogs.com"; String password = "123 "; if (args! = Null & args. length = 2) {loginId = args [0]; password = args [1];} SessionFactory = null; try {factory = createSessionFactory (); ShardsTestCreate (factory ); shardsTestLogin (factory, loginId, password); ShardsTestDelete (factory);} catch (Exception e) {System. out. println (e. getMessage (); e. printStackTrace ();} finally {if (factory! = Null) factory. close () ;}} private static void ShardsTestCreate (SessionFactory factory) {Session session = null; Transaction transaction = null; System. out. println ("= Create Contacts ="); try {session = factory. openSession (); transaction = session. beginTransaction (); session. save (new ContactEntity ("01111111", "RicCC@cnblogs.com", "123", "Richie", "RicCC@cnblogs.com"); session. save (new ContactEn Tity ("91111111", "a@cnblogs.com", "123", "AAA", "a@cnblogs.com"); session. save (new ContactEntity ("81111111", "B @cnblogs.com", "123", "BBB", "B @cnblogs.com"); session. save (new ContactEntity ("31111111", "c@cnblogs.com", "123", "CCC", "c@cnblogs.com"); transaction. commit ();} catch (Exception e) {if (transaction! = Null) transaction. rollback (); System. out. println (e. getMessage (); e. printStackTrace () ;} finally {if (session! = Null) session. close () ;}} private static void ShardsTestLogin (SessionFactory factory, String loginId, String password) {Session session = null; ContactEntity c = null; System. out. println ("\ n === Login Test ="); try {session = factory. openSession (); List contacts = session. createQuery ("from ContactEntity where LoginId =: loginId "). setString ("loginId", loginId ). list (); if (contacts. isEmpty () System. Out. println ("Contact \" "+ loginId +" \ "not found! "); Else {c = (ContactEntity) contacts. get (0); if (c. getPassword (). equals (password) System. out. println ("Contact \" "+ loginId +" \ "login successful"); else System. out. println ("Password is incorrect (shocould be:" + c. getPassword () + ", but is:" + password + ")");} System. out. println ("\ n === Get Contact by Id ="); c = (ContactEntity) session. get (ContactEntity. class, "81111111"); System. out. println (c. ToString (); c = (ContactEntity) session. get (ContactEntity. class, "31111111"); System. out. println (c. toString ();} catch (Exception e) {System. out. println (e. getMessage (); e. printStackTrace ();} finally {if (session! = Null) session. close () ;}} private static void ShardsTestDelete (SessionFactory factory) {Session session = null; Transaction transaction = null; System. out. println ("\ n === Delete Contacts ="); try {session = factory. openSession (); transaction = session. beginTransaction (); List contacts = session. createQuery ("from ContactEntity "). list (); Iterator it = contacts. iterator (); while (it. hasNext () {sessio N. delete (it. next () ;}transaction. commit () ;}catch (Exception e) {if (transaction! = Null) transaction. rollback (); System. out. println (e. getMessage (); e. printStackTrace () ;} finally {if (session! = Null) session. close ();}}}
Project Structure:
Run the test
Compile the class file with Eclipse to generate all the class files and related configuration and ing files.
Copy to the lib directory and run Main. class. The result is as follows:
D: \ Work \ research \ Java \ Hibernate-Test \ lib> java Main
=== Create Contacts ===
Hibernate: insert into CONTACT (EMAIL, NAME, LOGIN_ID, PASSWORD, ID) values (?,?, ?, ?, ?)
Hibernate: insert into CONTACT (EMAIL, NAME, LOGIN_ID, PASSWORD, ID) values (?,?, ?, ?, ?)
Hibernate: insert into CONTACT (EMAIL, NAME, LOGIN_ID, PASSWORD, ID) values (?,?, ?, ?, ?)
Hibernate: insert into CONTACT (EMAIL, NAME, LOGIN_ID, PASSWORD, ID) values (?,?, ?, ?, ?)
=== Login Test ====
Hibernate: select contactent0 _. ID as ID0 _, contactent0 _. EMAIL as EMAIL0 _, contactent0 _. NAME as NAME0 _, contactent0 _. LOGIN_ID as LOGIN4_0 _, contactent0 _. PASSWORD as PASSWORD0 _ from CONTACT contactent0 _ where contactent0 _. LOGIN_ID =?
Hibernate: select contactent0 _. ID as ID0 _, contactent0 _. EMAIL as EMAIL0 _, contactent0 _. NAME as NAME0 _, contactent0 _. LOGIN_ID as LOGIN4_0 _, contactent0 _. PASSWORD as PASSWORD0 _ from CONTACT contactent0 _ where contactent0 _. LOGIN_ID =?
Contact "RicCC@cnblogs.com" login successful
=== Get Contact by Id ===
Hibernate: select contactent0 _. ID as ID0_0 _, contactent0 _. EMAIL as EMAIL0_0 _, contactent0 _. NAME as NAME0_0 _, contactent0 _. LOGIN_ID as LOGIN4_0_0 _, contactent0 _. PASSWORD as PASSWORD0_0 _ from CONTACT contactent0 _ where contactent0 _. ID =?
{Id = "81111111", LoginId = "B @cnblogs.com", Name = "BBB", EMail = "B @cnblogs.com "}
Hibernate: select contactent0 _. ID as ID0_0 _, contactent0 _. EMAIL as EMAIL0_0 _, contactent0 _. NAME as NAME0_0 _, contactent0 _. LOGIN_ID as LOGIN4_0_0 _, contactent0 _. PASSWORD as PASSWORD0_0 _ from CONTACT contactent0 _ where contactent0 _. ID =?
{Id = "31111111", LoginId = "c@cnblogs.com", Name = "CCC", EMail = "c@cnblogs.com "}
=== Delete Contacts ===
Hibernate: select contactent0 _. ID as ID0 _, contactent0 _. EMAIL as EMAIL0 _, contactent0 _. NAME as NAME0 _, contactent0 _. LOGIN_ID as LOGIN4_0 _, contactent0 _. PASSWORD as PASSWORD0 _ from CONTACT contactent0 _
Hibernate: select contactent0 _. ID as ID0 _, contactent0 _. EMAIL as EMAIL0 _, contactent0 _. NAME as NAME0 _, contactent0 _. LOGIN_ID as LOGIN4_0 _, contactent0 _. PASSWORD as PASSWORD0 _ from CONTACT contactent0 _
Hibernate: delete from CONTACT where ID =?
Hibernate: delete from CONTACT where ID =?
Hibernate: delete from CONTACT where ID =?
Hibernate: delete from CONTACT where ID =?
1. When an object is loaded by id, hibernate shards uses ShardSelectionStrategy to determine the shard from which data should be loaded.
2. When adding data, hibernate shards uses ShardResolutionStrategy to determine the shard to which the data should be inserted.
Why can't ShardSelectionStrategy be used here? Because it is related to the id generation mechanism, for example, you can let the database generate the id (native method in hibernate), such as auto-increment id, in the shard Application Scenario, each shard can be simply given a starting and ending range, but the specific algorithm must be used to determine the shard to which the data is inserted, in this case, ShardSelectionStrategy cannot be used. For similar id generation mechanisms such as assigned, ShardSelectionStrategy can still be applied.
3. When performing a hql or Criteria query, use ShardAccessStrategy to query data from shard.
In the buildShardStrategyFactory method in the preceding example, we use the SequentialShardAccessStrategy policy provided by the hibernate shards project. This policy executes query statements one by one in all shards and then merges the results.
Based on the above points, we can explain the output after the test run:
Two SQL queries are generated when hql is used. This is because SequentialShardAccessStrategy is used. The two shard statements we define Execute SQL queries respectively, the merged result set is returned to the caller.
Comment out the delete statement in the test code and query the database after running the test. You can confirm that the data is correctly inserted in the corresponding shard.
Summary
The above demonstrates the basic usage of hibernate shards. In general, it is very simple to use. You only need to use ShardedSessionFactory provided by hibernate shards for the shard entity.
There are also some restrictions on using hibernate shards, but most of them are some design requirements after using shards, or the constraints on shards design in the current IT technology background, in the next article, I will describe this content in detail.
The source file of the test project used in this article is downloaded here. The referenced jar file needs to be downloaded from the relevant project website.