Hibernate Sharding Example

It is a simple implementation of Hibernate Sharding in java. In this we are using two databases i.e. shard1 and shard2.
All data related to "India" goes to shard1 where as others go to shard2.

Project Contents:

File Name
Use
DatabaseCreator.java
Used to create tables in databases named shard1 and shard2.
User.java
POJO class.
User.hbm.xml
Mapping file. Used to map POJO to database tables.
hibernate0.cfg.xml
Hibernate configuration file for database named shard1
hibernate1.cfg.xml
Hibernate configuration file for database named shard2
IdGenerator.java
Class for Id generation
HibernateShardUtil.java
Class for loading hiberante session factory.
UserShardResolutionStrategy.java
Class for implementing shard resolution strategy.
UserShardSelectionStrategy.java
Class for implementing shard selection strategy.
Main.java
Client class to execute the whole process.


DatabaseCreator.java

package test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class DatabaseCreator
{
    public static void main(String args[]) throws Exception
    {
        String url = "jdbc:mysql://localhost/shard1";
        String dbusr = "root";
        String dbpwd = "root";
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection(url, dbusr, dbpwd);
        Statement statement = connection.createStatement();
        String query;
        query = "drop table s_usr";
        statement.executeUpdate(query);
        query = "create table s_usr(usr_kid integer primary key, usr_name varchar(50)," +
        "usr_gender varchar(10),usr_country varchar(20))";
        statement.executeUpdate(query);
        statement.close();
        connection.close();
        url = "jdbc:mysql://localhost/shard2";
        connection = DriverManager.getConnection(url, dbusr, dbpwd);
        statement = connection.createStatement();
        query = "drop table s_usr";
        statement.executeUpdate(query);
        query = "create table s_usr(usr_kid integer primary key, usr_name varchar(50)," +
        "usr_gender varchar(10),usr_country varchar(20))";
        statement.executeUpdate(query);
        statement.close();
        connection.close();
    }
}


User.java

package test;
import java.io.Serializable;
public class User implements Serializable
{
    protected int usr_kid;
    protected String name;
    protected String gender;
    protected String country;   
    public int getUsr_kid()    { 
        return usr_kid;
    }
    public void setUsr_kid(int usr_kid)    {
        this.usr_kid = usr_kid;
    }
    public String getName()    {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public String getCountry()    {
        return country;
    }   
    public void setCountry(String country) {
        this.country = country;
    }
    @Override
    public String toString() {
        return "User Id: "+ usr_kid + " , Username: " + name + " , Gender: " + gender + " , Country: " + country;   
    }
}


User.hbm.xml

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test">
    <class name="User" table="s_usr">
        <id name="usr_kid" column="usr_kid" type="integer">
          <generator class="test.IdGenerator"/>
        </id>
        <property name="name" column="usr_name"/>
        <property name="gender" column="usr_gender"/>
        <property name="country" column="usr_country"/>
    </class>
</hibernate-mapping>


hibernate0.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <property name="hibernate.connection.url">jdbc:mysql://localhost/shard1</property>
        <property name="hibernate.connection.username">root</property>
        <property name="connection.password">root</property>
        <property name="connection.pool_size">1</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.shard_id">0</property>
        <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property>
    </session-factory>
</hibernate-configuration>


hibernate1.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <property name="hibernate.connection.url">jdbc:mysql://localhost/shard2</property>
        <property name="hibernate.connection.username">root</property>
        <property name="connection.password">root</property>
        <property name="connection.pool_size">1</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.shard_id">1</property>
        <property name="hibernate.shard.enable_cross_shard_relationship_checks">true</property>
    </session-factory>
</hibernate-configuration>


IdGenerator.java

package test;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
public class IdGenerator implements IdentifierGenerator
{
    static Integer id;
    static
    {
        id = 0;
        String url = "jdbc:mysql://localhost/shard1";
        String dbusr = "root";
        String dbpwd = "root";
        try 
        {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection(url, dbusr, dbpwd);
            Statement stmt = con.createStatement();
            String query = "select max(usr_kid) from s_usr";
            ResultSet rset = stmt.executeQuery(query);
            if(rset.next()) {
                int tempid = rset.getInt(1);
                if(id<tempid)
                    id = tempid;
            }
            stmt.close();
            con.close();
            url = "jdbc:mysql://localhost/shard2";
            con = DriverManager.getConnection(url, dbusr, dbpwd);
            stmt = con.createStatement();
            query = "select max(usr_kid) from s_usr";
            rset = stmt.executeQuery(query);
            if(rset.next()) {
                int tempid = rset.getInt(1);
                if(id<tempid)
                    id = tempid;
            }
            System.out.println(id);
            stmt.close();
            con.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public Serializable generate(SessionImplementor arg0, Object arg1) throws HibernateException {
        id = id +1;
        return id;
    }
}


HibernateShardUtil.java

package test;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.ShardedConfiguration;
import org.hibernate.shards.cfg.ConfigurationToShardConfigurationAdapter;
import org.hibernate.shards.strategy.ShardStrategy;
import org.hibernate.shards.strategy.ShardStrategyFactory;
import org.hibernate.shards.strategy.ShardStrategyImpl;
import org.hibernate.shards.strategy.access.SequentialShardAccessStrategy;
import org.hibernate.shards.strategy.access.ShardAccessStrategy;
import org.hibernate.shards.strategy.resolution.ShardResolutionStrategy;
import org.hibernate.shards.strategy.selection.ShardSelectionStrategy;
public class HibernateShardUtil
{
    private static SessionFactory sessionFactory;
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    static
    {
        try
        {
            Configuration config = new Configuration();
            config.configure("/test/hibernate0.cfg.xml");
            config.addResource("test/User.hbm.xml");
            List shardConfigs = new ArrayList();
            shardConfigs.add(new ConfigurationToShardConfigurationAdapter(new Configuration().configure("/test/hibernate0.cfg.xml")));
            shardConfigs.add(new ConfigurationToShardConfigurationAdapter(new Configuration().configure("/test/hibernate1.cfg.xml")));
            ShardStrategyFactory shardStrategyFactory = buildShardStrategyFactory();
            ShardedConfiguration shardedConfig = new ShardedConfiguration(config,shardConfigs,shardStrategyFactory);
            sessionFactory = shardedConfig.buildShardedSessionFactory();
        }
        catch (Throwable ex)
        {
            ex.printStackTrace();
            sessionFactory = null;
        }
    }
    static ShardStrategyFactory buildShardStrategyFactory()
    {
        ShardStrategyFactory shardStrategyFactory = new ShardStrategyFactory() {
            public ShardStrategy newShardStrategy(List<ShardId> shardIds) {
                ShardSelectionStrategy pss = new UserShardSelectionStrategy();
                ShardResolutionStrategy prs = new UserShardResolutionStrategy(shardIds);
                ShardAccessStrategy pas = new SequentialShardAccessStrategy();
                return new ShardStrategyImpl(pss, prs, pas);
            }
        };
        return shardStrategyFactory;
    }
}


UserShardResolutionStrategy.java

package test;
import java.util.List;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.strategy.resolution.AllShardsShardResolutionStrategy;
import org.hibernate.shards.strategy.selection.ShardResolutionStrategyData;
public class UserShardResolutionStrategy extends AllShardsShardResolutionStrategy
{
    public UserShardResolutionStrategy(List<ShardId> shardIds) {
        super(shardIds);
    }
    public List<ShardId> selectShardIdsFromShardResolutionStrategyData(     ShardResolutionStrategyData srsd) {
        return super.selectShardIdsFromShardResolutionStrategyData(srsd);
    }
}


UserShardSelectionStrategy.java

package test;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.strategy.selection.ShardSelectionStrategy;
public class UserShardSelectionStrategy implements ShardSelectionStrategy
{
    public ShardId selectShardIdForNewObject(Object obj) {
        if (obj instanceof User) {
            int shardId = 0;
            String country = ((User) obj).getCountry();
            if(country.equalsIgnoreCase("India"))
                shardId = 0;
            else
                shardId = 1;
            return new ShardId(shardId);
        }
        throw new IllegalArgumentException();
    }
}


Main.java

package test;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public class Main
{
    public void list()
    {
        SessionFactory sessionFactory = HibernateShardUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        List<User> userList = session.createQuery("from User").list();
        Iterator<User> iterator = userList.iterator();
        while(iterator.hasNext())
        {
            User user = (User) iterator.next();
            System.out.println(user);
        }
        session.close();
    }
    public void input()
    {
        SessionFactory sessionFactory = HibernateShardUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        try
        {
            transaction = session.beginTransaction();
            User user = new User();
            user.setName("Max");
            user.setCountry("U.S.A");
            user.setGender("Male");
            session.save(user);
            user = new User();
            user.setName("Hemant Kumar");
            user.setCountry("India");
            user.setGender("Male");
            session.save(user);
            transaction.commit();
        }
        catch (Exception e)
        {
            transaction.rollback();
            e.printStackTrace();
        }
        session.close();
    }
    public static void main(String[] args)
    {
        Main obj = new Main();
        obj.list();
        obj.input();
        obj.list();
    }
}

Download and attach the required jar files.

Comments

  1. A very useful article. It's very interesting that one can define their own strategies. This gives great flexibility to Hibernate Shards.

    ReplyDelete

Post a Comment

Popular posts from this blog

Index MySQL datadase table in Solr

Shallow Copy