Spring整合sharding-jdbc实现分库分表

  1. 准备两台数据库服务器 192.168.18.179 和 192.168.18.180,如下图

  2. 对于不知道怎么在Linux服务器中安装MySQL的,可以参考 CentOS下安装MySQL5.7(图文)

  3. 在192.168.18.179中新建一个数据库mall_0,如下图

  4. 在192.168.18.180中新建一个数据库mall_1,如下图

  5. 在mall_0和mall_1中分别运行下面的sql脚本(在每个库中新建两张表分别为t_order_0,t_order_1)

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    DROP TABLE IF EXISTS `t_order_0`;
    CREATE TABLE `t_order_0`  (
      `order_id` bigint(20) NOT NULL,
      `user_id` int(11) NOT NULL,
      `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
      PRIMARY KEY (`order_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
    
    
    DROP TABLE IF EXISTS `t_order_1`;
    CREATE TABLE `t_order_1`  (
      `order_id` bigint(20) NOT NULL,
      `user_id` int(11) NOT NULL,
      `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
      PRIMARY KEY (`order_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
    
    
    SET FOREIGN_KEY_CHECKS = 1;
    
  6. 接下来新建一个maven工程 spring-shardingjdbc

  7. 在pom.xml文件中引入依赖

    <dependencies>
        <!-- sharding的核心包 -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
    
        <!-- sharding整合spring依赖 -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
    
        <!--spring的依赖包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
    
        <!--jdbc驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    
        <!--HikariCP数据库连接池-->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>3.2.0</version>
        </dependency>
    
        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    
  8. 在 main\resource 下新建一个spring配置文件applicationContext.xml,并配置spring与shardingJDBC整合的配置项

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:sharding="http://shardingsphere.apache.org/schema/shardingsphere/sharding"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://shardingsphere.apache.org/schema/shardingsphere/encrypt http://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd http://shardingsphere.apache.org/schema/shardingsphere/sharding http://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd">
    
        <!--数据库0-->
        <bean id="ds0" class="com.zaxxer.hikari.HikariDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://192.168.18.179:3306/mall_0?useSSL=false"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <!--数据库1-->
        <bean id="ds1" class="com.zaxxer.hikari.HikariDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://192.168.18.180:3306/mall_1?useSSL=false"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <!-- 数据的分库策略
         sharding-column  基于user_id进行分库
         如果user_id对2取余为0则将数据存放在ds0数据库
         如果user_id对2取余为1则将数据存放在ds1数据库
         -->
        <sharding:inline-strategy id="databaceStrategy" sharding-column="user_id"
                                  algorithm-expression="ds$->{user_id % 2}"/>
    
        <!-- 数据的分表策略
        sharding-column  基于order_id进行分表
        如果order_id对2取余为0则将数据存放在t_order_0表中
        如果order_id对2取余为1则将数据存放在t_order_1表中
        -->
        <sharding:inline-strategy id="orderTableStrategy" sharding-column="order_id"
                                  algorithm-expression="t_order_$->{order_id % 2}"/>
    
        <!-- 分片数据源,对JDBC进行了扩展和增强 -->
        <sharding:data-source id="shardingDataSource">
            <!-- sharding-rule  定义分库分表规则
                data-source-names="ds0,ds1"  说明有几个数据源
                sharding:table-rules  定义数据存储规则
                logic-table="t_order"  代表逻辑表名
                actual-data-nodes说明数据存放在ds0和ds1的t_order_0和t_order_1四张表中
                database-strategy-ref  数据的分库策略
                table-strategy-ref  数据的分表策略
    
                order_id     user_id
                1            2           ds0.t_order_1
                2            2           ds0.t_order_0
                3            1           ds1.t_order_1
                4            1           ds1.t_order_0
            -->
            <sharding:sharding-rule data-source-names="ds0,ds1"> <!-- 通知shardingJDBC一共有两个数据源 -->
                <sharding:table-rules>
                    <sharding:table-rule logic-table="t_order"
                        actual-data-nodes="ds$->{0..1}.t_order_$->{0..1}"
                                         database-strategy-ref="databaceStrategy"
                                         table-strategy-ref="orderTableStrategy"
                    />
                </sharding:table-rules>
            </sharding:sharding-rule>
        </sharding:data-source>
    </beans>
    
  9. 编写插入的测试代码

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
    public class ShardingTest {
    
        @Resource(name = "shardingDataSource")  //此处引入的是配置文件中定义的shardingDataSource
        private DataSource dataSource;
    
        @Test
        public void testInsert() throws SQLException {
            Connection connection = dataSource.getConnection();
            //t_order为逻辑表
            String sql = "insert into t_order(order_id, user_id, status) values(2, 2, 'N')";  
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();
            
            preparedStatement.close();
            connection.close();
        }
    }
    
  10. 插入数据测试一

    insert into t_order(order_id, user_id, status) values(1, 2, 'N')
    

    数据成功插入到了mall0的t_order_1表中

  11. 插入数据测试二

    insert into t_order(order_id, user_id, status) values(2, 2, 'N')
    

    数据成功插入到了mall0的t_order_0表中

    在这里插入图片描述

  12. 插入数据测试三

    insert into t_order(order_id, user_id, status) values(3, 1, 'N')
    

    数据成功插入到了mall1的t_order_1表中

  13. 插入数据测试四

    insert into t_order(order_id, user_id, status) values(4, 1, 'N')
    

    数据成功插入到了mall1的t_order_0表中

  14. 编写查询的测试代码

    @Test
    public void testQuery() throws SQLException {
        Connection connection = dataSource.getConnection();
        /**
        * select * from t_order 
        * 分解sql
        * select * from ds0.t_order_0
        * select * from ds0.t_order_1
        * select * from ds1.t_order_0
        * select * from ds1.t_order_1
        * 最后将结果合并
        */
        String sql = "select * from t_order order by order_id";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
            System.out.println("order_id: "+resultSet.getLong("order_id")
                               +", user_id: "+ resultSet.getLong("user_id")
                               + " status: "+resultSet.getString("status"));
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
    /**
    	测试结果(一次性将四张表中的数据都查询出来了)
    		order_id: 2, user_id: 2 status: N
    		order_id: 1, user_id: 2 status: N
    		order_id: 4, user_id: 1 status: N
    		order_id: 3, user_id: 1 status: N
    */
    
  15. 分库分表后,不能使用自动生成的主键,否则在查询的结果中会出现大量的重复的主键,所以在分库分表后需要使用分布式主键生成策略。

  16. 分布式主键生成策略为主键生成全局唯一的值,将主键放在任何一台数据库中都是唯一的。

  17. shardingsphere支持多种分布式主键生成策略,包括UUID,SNOWFLAKE(雪花算法,能保证不同进程的主键不重复,以及相同进程的主键的有序性),时钟回拨,LEAF(借助注册中心生成分布式自增主键)

  18. shardingJDBC整合SNOWFLAKE,在配置文件中加入

    <!-- 分布式主键生成策略(雪花算法) -->
    <sharding:key-generator id="orderKeyGenerator" type="SNOWFLAKE" column="order_id"/>
    
     <sharding:table-rule logic-table="t_order"
         actual-data-nodes="ds$->{0..1}.t_order_$->{0..1}"
         database-strategy-ref="databaceStrategy"
         table-strategy-ref="orderTableStrategy"
         key-generator-ref="orderKeyGenerator"
      />
    
  19. 新增分布式主键生成测试代码

    /**
    * 测试批量插入(分布式主键)
    * @throws SQLException
    */
    @Test
    public void testBatchInsert() throws SQLException {
        Connection connection = dataSource.getConnection();
        for (int i = 0; i < 10; i++) {
            String sql = "insert into t_order(user_id, status) values(?, 'N')";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setLong(1, i);
            preparedStatement.executeUpdate();
            preparedStatement.close();
        }
        connection.close();
    }
    /**
    	测试结果,发现所有的数据均匀的分布在两个库中
    */
    
  20. 具体的代码见 Spring整合sharding-jdbc实现分库分表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值