sharding-sphere學習(1)之-[raw-example]

發(fā)現(xiàn)夢想與現(xiàn)實的差距后搀军,堅持就越來越遠

前段時間在刷博客的時候抛猖,無意間刷到了一篇介紹數(shù)據(jù)庫分庫分表的框架,于是網(wǎng)上搜了一下啸罢,shardingjdbc 當當團隊網(wǎng)團隊開源的一個專做對于java開發(fā)在原生的jdbc層上封裝的一層輕量級中間件忍啤。我們看一下它的官網(wǎng)(http://shardingjdbc.io/index_zh.html)給的介紹:

sharding-sphere

對于shardingjdbc來說無非就是通過java代碼在原生的jdbc上封裝了一層腐宋,如果說自己去研發(fā)一個這樣的中間件也不是不可能。就是后期考慮到出現(xiàn)的bug檀轨、效率胸竞、性能等問題,沒有一個更好的前期規(guī)劃也很難完成参萄。定位上面這個輕量級的框架通過上面給的架構(gòu)圖來說卫枝,無非就是在jdbc層進行更好的封裝集成,從而形成一個加強版的JDBC連接數(shù)據(jù)庫的工具讹挎。沒有任何侵入性校赤,完全可以兼容任何的ORM框架,這一點確實是可以值得一用的筒溃。


sharding-jdbc

下面我們來看看sharding-jdbc為我們提供的功能有哪些马篮?官網(wǎng)也有具體的介紹:

  • 數(shù)據(jù)分片
    數(shù)據(jù)分片主要以分庫+分表的操作、支持的sql語句查詢方式以及分布式主鍵的處理方案等
  • 讀寫分離
    讀寫分離主要以一主多從怜奖、統(tǒng)一線程數(shù)據(jù)的一致性以及分庫分表時的讀寫分離操作等
  • 事物處理
    主要針對TCC分布式事物處理解決
  • 分布式治理
    主要一些熔斷措施浑测,以及配置中心的配置。

基本的說明就這些,后續(xù)將會沿著例子區(qū)找到源碼進行進一步的研究和探討迁央。接下來可以去github上將shardingjdbc-example(https://github.com/sharding-sphere/sharding-sphere-example)例子下載下來運行掷匠,如下圖,由于版本原因選擇branches版本下載:

分支

本機運行例子需要選擇master版本的岖圈,dev是開發(fā)版本讹语,暫時maven代碼庫還沒有更新上去。
master

可以直接下載zip也可以直接使用:

git clone https://github.com/sharding-sphere/sharding-sphere-example.git

直接下載下來蜂科。然后將下載下來的項目導入到IDEA中如下圖:

example運行例子

注意:當前我使用的sharding-jdbc版本是2.0.3顽决。git可能會是最新版本。應該都可以用的運行的导匣,只是目錄有點不一樣了擎值。

我們來看看官網(wǎng)給的例子,首先在每個項目模塊下面對java實現(xiàn)的每個ORM框架進行了組個demo演示逐抑,無論我們使用哪種框架,只需要導入所需的jar包便可以完美的和ORM框架結(jié)合屹蚊。
首先我們先來看看在與原生的jdbc結(jié)合的時候sharding-jdbc是怎么實現(xiàn)分庫分表的策略的厕氨。找到

sharding-jdbc-raw-jdbc-example
sharding-jdbc-raw-jdbc-example

該模塊下的

sharding-jdbc-raw-jdbc-java-example // 原生代碼與sharding-jdbc結(jié)合
/**僅讀寫分離操作*/
RawJdbcJavaMasterSlaveOnlyMain
/**讀寫分離+分庫分表操作*/
RawJdbcJavaShardingAndMasterSlaveMain
/**分庫分表操作*/
RawJdbcJavaShardingDatabaseAndTableMain
/**僅分庫操作*/
RawJdbcJavaShardingDatabaseOnlyMain
/**僅做分表操作*/
RawJdbcJavaShardingTableOnlyMain

注意:在運行demo前請先將基本的數(shù)據(jù)庫先初始化好,在每個模塊的根目錄下會有一個sql文件汹粤,是根據(jù)自己的業(yè)務來制定的建庫規(guī)則來創(chuàng)建對應的庫:


需要執(zhí)行的建庫sql

在創(chuàng)建好數(shù)據(jù)庫后將會有12個對應的數(shù)據(jù)庫命斧,待后續(xù)example會使用到:


初始化example的數(shù)據(jù)庫

下面將從分庫模塊學習使用入口:

/**僅分庫操作*/
RawJdbcJavaShardingDatabaseOnlyMain

使用到的庫:

  • demo_ds_0
  • demo_ds_1
    運行該example結(jié)果如下:
1.動態(tài)創(chuàng)建表成功--------------
2.插入數(shù)據(jù)成功--------------
3.打印 Equals 查詢結(jié)果--------------
order_item_id:1, order_id:207575701002387456, user_id:10
order_item_id:2, order_id:207575701472149504, user_id:10
order_item_id:3, order_id:207575701568618496, user_id:10
order_item_id:4, order_id:207575701669281792, user_id:10
order_item_id:5, order_id:207575701803499520, user_id:10
order_item_id:6, order_id:207575701950300160, user_id:10
order_item_id:7, order_id:207575702038380544, user_id:10
order_item_id:8, order_id:207575702118072320, user_id:10
order_item_id:9, order_id:207575702256484352, user_id:10
4.打印使用 In 查詢結(jié)果--------------
order_item_id:1, order_id:207575701405040640, user_id:11
order_item_id:2, order_id:207575701518286848, user_id:11
order_item_id:3, order_id:207575701623144448, user_id:11
order_item_id:4, order_id:207575701723807744, user_id:11
order_item_id:5, order_id:207575701899968512, user_id:11
order_item_id:6, order_id:207575701988048896, user_id:11
order_item_id:7, order_id:207575702080323584, user_id:11
order_item_id:8, order_id:207575702218735616, user_id:11
order_item_id:9, order_id:207575702290038784, user_id:11
order_item_id:1, order_id:207575701002387456, user_id:10
order_item_id:2, order_id:207575701472149504, user_id:10
order_item_id:3, order_id:207575701568618496, user_id:10
order_item_id:4, order_id:207575701669281792, user_id:10
order_item_id:5, order_id:207575701803499520, user_id:10
order_item_id:6, order_id:207575701950300160, user_id:10
order_item_id:7, order_id:207575702038380544, user_id:10
order_item_id:8, order_id:207575702118072320, user_id:10
order_item_id:9, order_id:207575702256484352, user_id:10
4.打印使用 Hint 查詢結(jié)果--------------
order_item_id:1, order_id:207575701405040640, user_id:11
order_item_id:2, order_id:207575701518286848, user_id:11
order_item_id:3, order_id:207575701623144448, user_id:11
order_item_id:4, order_id:207575701723807744, user_id:11
order_item_id:5, order_id:207575701899968512, user_id:11
order_item_id:6, order_id:207575701988048896, user_id:11
order_item_id:7, order_id:207575702080323584, user_id:11
order_item_id:8, order_id:207575702218735616, user_id:11
order_item_id:9, order_id:207575702290038784, user_id:11

數(shù)據(jù)庫中的表如圖所示:


分庫插入數(shù)據(jù)

基本執(zhí)行步驟如下:

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:15
     * @Description: 配置數(shù)據(jù)源
     */
    private static DataSource getShardingDataSource() throws SQLException {
        /**初始化sharding配置*/
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        /**添加創(chuàng)建主訂單表*/
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        /**添加創(chuàng)建訂單項表*/
        shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
        /**根據(jù)主訂單表中的user_id字段定位該筆訂單入庫規(guī)則,這里使用user_id的奇偶數(shù)來定位插庫入口*/
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "demo_ds_${user_id % 2}"));
        /**創(chuàng)建好數(shù)據(jù)源并加入配置中得到數(shù)據(jù)源配置*/
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap<String, Object>(), new Properties());
    }

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:20
     * @Description: 主訂單表規(guī)則的基本配置
     */
    private static TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        orderTableRuleConfig.setLogicTable("t_order");
        /**設(shè)置主鍵*/
        orderTableRuleConfig.setKeyGeneratorColumnName("order_id");
        return orderTableRuleConfig;
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:22 
     * @Description: 訂單項目表的配置規(guī)則
     */
    private static TableRuleConfiguration getOrderItemTableRuleConfiguration() {
        TableRuleConfiguration orderItemTableRuleConfig = new TableRuleConfiguration();
        orderItemTableRuleConfig.setLogicTable("t_order_item");
        return orderItemTableRuleConfig;
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:22 
     * @Description: 創(chuàng)建兩個動態(tài)數(shù)據(jù)源 demo_ds_0 嘱兼、 demo_ds_1
     */
    private static Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>(2, 1);
        result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0"));
        result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1"));
        return result;
    }

執(zhí)行的具體操作類關(guān)鍵實現(xiàn)如下:

    private final DataSource dataSource;
    
    /**初始化數(shù)據(jù)源*/
    public RawJdbcRepository(final DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public void demo() throws SQLException {
        /**創(chuàng)建表*/
        System.out.println("1.動態(tài)創(chuàng)建表--------------");
        this.createTable();
        /**插入數(shù)據(jù)*/
        System.out.println("2.插入數(shù)據(jù)--------------");
        this.insertData();
        /**打印查詢*/
        System.out.println("3.打印 Equals 查詢結(jié)果--------------");
        printEqualsSelect();
        System.out.println("4.打印使用 In 查詢結(jié)果--------------");
        printInSelect();
        System.out.println("4.打印使用 Hint 查詢結(jié)果--------------");
        printHintSimpleSelect();
//        dropTable();
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:24 
     * @Description: 動態(tài)創(chuàng)建表
     */
    public void createTable() throws SQLException {
        execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order (order_id BIGINT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id))");
        execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order_item (order_item_id BIGINT NOT NULL AUTO_INCREMENT, order_id BIGINT NOT NULL, user_id INT NOT NULL, PRIMARY KEY (order_item_id))");
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 刪除表
     */
    public void dropTable() throws SQLException {
        execute(dataSource, "DROP TABLE t_order_item");
        execute(dataSource, "DROP TABLE t_order");
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 插入數(shù)據(jù)
     */
    public void insertData() throws SQLException {
        for (int i = 1; i < 10; i++) {
            long orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (10, 'INIT')");
            this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 10)", orderId));
            orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (11, 'INIT')");
            this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 11)", orderId));
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 使用 Equals 查詢數(shù)據(jù)
     */
    public void printEqualsSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=?";
        try (
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            preparedStatement.setInt(1, 10);
            printSimpleSelect(preparedStatement);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:26 
     * @Description: 使用 In 查詢數(shù)據(jù)
     */
    public void printInSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id IN (?, ?)";
        try (
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            preparedStatement.setInt(1, 10);
            preparedStatement.setInt(2, 11);
            printSimpleSelect(preparedStatement);
        }
    }

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 使用 Hint 查詢數(shù)據(jù)
     */
    public void printHintSimpleSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id";
        try (
                HintManager hintManager = HintManager.getInstance();
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            hintManager.addDatabaseShardingValue("t_order", "user_id", 11);
            printSimpleSelect(preparedStatement);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 打印并遍歷查詢結(jié)果
     */
    private void printSimpleSelect(final PreparedStatement preparedStatement) throws SQLException {
        try (ResultSet rs = preparedStatement.executeQuery()) {
            while (rs.next()) {
                System.out.print("order_item_id:" + rs.getLong(1) + ", ");
                System.out.print("order_id:" + rs.getLong(2) + ", ");
                System.out.print("user_id:" + rs.getInt(3));
                System.out.println();
            }
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 執(zhí)行連接數(shù)據(jù)源
     */
    private void execute(final DataSource dataSource, final String sql) throws SQLException {
        try (
                Connection conn = dataSource.getConnection();
                Statement statement = conn.createStatement()) {
            statement.execute(sql);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:28 
     * @Description: 插入數(shù)據(jù)并返回主鍵參數(shù)值
     */
    private long executeAndGetGeneratedKey(final DataSource dataSource, final String sql) throws SQLException {
        long result = -1;
        try (
                Connection conn = dataSource.getConnection();
                Statement statement = conn.createStatement()) {
            statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
            ResultSet resultSet = statement.getGeneratedKeys();
            if (resultSet.next()) {
                result = resultSet.getLong(1);
            }
        }
        return result;
    }

至此可看出在分庫策略上sharding-jdbc做的流程国葬,可將通過user_id定位到制定規(guī)則的數(shù)據(jù)庫中,并在插入數(shù)據(jù)時進行動態(tài)分配數(shù)據(jù)源的數(shù)據(jù)芹壕,從而將數(shù)據(jù)均分落地到到兩個庫所對應的克隆的實際表中汇四,實現(xiàn)分庫操作。該example是通過直接取模分配數(shù)據(jù)源踢涌,當然我們也可以通過自己定的分片規(guī)則算法進行實現(xiàn)分片操作通孽。具體的實現(xiàn)流程說明下篇繼續(xù)tfyy。睁壁。背苦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市潘明,隨后出現(xiàn)的幾起案子行剂,更是在濱河造成了極大的恐慌,老刑警劉巖钳降,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厚宰,死亡現(xiàn)場離奇詭異,居然都是意外死亡遂填,警方通過查閱死者的電腦和手機固阁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門壤躲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人备燃,你說我怎么就攤上這事碉克。” “怎么了并齐?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵漏麦,是天一觀的道長。 經(jīng)常有香客問我况褪,道長撕贞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任测垛,我火速辦了婚禮捏膨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘食侮。我一直安慰自己号涯,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布锯七。 她就那樣靜靜地躺著链快,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眉尸。 梳的紋絲不亂的頭發(fā)上域蜗,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音噪猾,去河邊找鬼霉祸。 笑死,一個胖子當著我的面吹牛袱蜡,可吹牛的內(nèi)容都是我干的脉执。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼戒劫,長吁一口氣:“原來是場噩夢啊……” “哼半夷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迅细,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤巫橄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茵典,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湘换,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了彩倚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筹我。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帆离,靈堂內(nèi)的尸體忽然破棺而出蔬蕊,到底是詐尸還是另有隱情,我是刑警寧澤哥谷,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布岸夯,位于F島的核電站,受9級特大地震影響们妥,放射性物質(zhì)發(fā)生泄漏猜扮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一监婶、第九天 我趴在偏房一處隱蔽的房頂上張望旅赢。 院中可真熱鬧,春花似錦惑惶、人聲如沸煮盼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踩娘,卻和暖如春刮刑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背养渴。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工雷绢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人理卑。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓翘紊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親藐唠。 傳聞我的和親對象是個殘疾皇子帆疟,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容