/* * Copyright 2014 mango.jfaster.org * * The Mango Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jfaster.mango.sharding; import org.jfaster.mango.annotation.*; import org.jfaster.mango.datasource.SimpleDataSourceFactory; import org.jfaster.mango.operator.Mango; import org.jfaster.mango.support.DataSourceConfig; import org.jfaster.mango.support.Table; import org.jfaster.mango.support.model4table.Bill; import org.jfaster.mango.util.HashUtil; import org.junit.Before; import org.junit.Test; import javax.sql.DataSource; import java.sql.Connection; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; /** * @author ash */ public class BillShardingTest { private static String[] dsns = new String[]{"db1", "db2", "db3", "db4"}; private static Bill1Dao bill1Dao; private static Bill2Dao bill2Dao; private static Bill3Dao bill3Dao; private static Bill4Dao bill4Dao; private static BillDao billDao; private static SimpleBillDao simpleBillDao; @Before public void before() throws Exception { Mango mango = Mango.newInstance(); for (int i = 0; i < 4; i++) { DataSource ds = DataSourceConfig.getDataSource(i + 1); Connection conn = ds.getConnection(); Table.BILL_PARTITION.load(conn); conn.close(); mango.addDataSourceFactory(new SimpleDataSourceFactory(dsns[i], ds)); } bill1Dao = mango.create(Bill1Dao.class); bill2Dao = mango.create(Bill2Dao.class); bill3Dao = mango.create(Bill3Dao.class); bill4Dao = mango.create(Bill4Dao.class); billDao = mango.create(BillDao.class); simpleBillDao = mango.create(SimpleBillDao.class); } @Test public void test() throws Exception { int price = 0; for (int cid = 0; cid < 10; cid++) { for (int intUid = 10; intUid < 20; intUid++) { String uid = String.valueOf(intUid); price++; Bill o = new Bill(); o.setCid(cid); o.setUid(uid); o.setPrice(price); billDao.insert(o); assertThat(billDao.getBill(cid, uid), equalTo(o)); assertThat(getDaoByCid(cid).getBill(getTableByUid(uid), cid, uid), equalTo(o)); } } for (int cid = 100; cid < 110; cid++) { for (int intUid = 110; intUid < 120; intUid++) { String uid = String.valueOf(intUid); price++; Bill o = new Bill(); o.setCid(cid); o.setUid(String.valueOf(uid)); o.setPrice(price); getDaoByCid(cid).insert(getTableByUid(uid), o); assertThat(billDao.getBill(cid, uid), equalTo(o)); assertThat(getDaoByCid(cid).getBill(getTableByUid(uid), cid, uid), equalTo(o)); } } } @Test public void test2() throws Exception { int price = 0; for (int cid = 0; cid < 10; cid++) { for (int intUid = 10; intUid < 20; intUid++) { String uid = String.valueOf(intUid); price++; Bill o = new Bill(); o.setCid(cid); o.setUid(uid); o.setPrice(price); simpleBillDao.insert(o); assertThat(simpleBillDao.getBill(cid, uid), equalTo(o)); assertThat(getDaoByCid(cid).getBill(getTableByUid(uid), cid, uid), equalTo(o)); } } for (int cid = 100; cid < 110; cid++) { for (int intUid = 110; intUid < 120; intUid++) { String uid = String.valueOf(intUid); price++; Bill o = new Bill(); o.setCid(cid); o.setUid(String.valueOf(uid)); o.setPrice(price); getDaoByCid(cid).insert(getTableByUid(uid), o); assertThat(simpleBillDao.getBill(cid, uid), equalTo(o)); assertThat(getDaoByCid(cid).getBill(getTableByUid(uid), cid, uid), equalTo(o)); } } } interface IBillDao { int insert(String table, Bill bill); public Bill getBill(String table, int cid, String uid); } @DB(name = "db1") interface Bill1Dao extends IBillDao { @SQL("insert into #{:table}(cid, uid, price) values(:cid, :uid, :price)") int insert(@Rename("table") String table, Bill bill); @SQL("select cid, uid, price from #{:1} where cid = :2 and uid = :3") public Bill getBill(String table, int cid, String uid); } @DB(name = "db2") interface Bill2Dao extends IBillDao { @SQL("insert into #{:table}(cid, uid, price) values(:cid, :uid, :price)") int insert(@Rename("table") String table, Bill bill); @SQL("select cid, uid, price from #{:1} where cid = :2 and uid = :3") public Bill getBill(String table, int cid, String uid); } @DB(name = "db3") interface Bill3Dao extends IBillDao { @SQL("insert into #{:table}(cid, uid, price) values(:cid, :uid, :price)") int insert(@Rename("table") String table, Bill bill); @SQL("select cid, uid, price from #{:1} where cid = :2 and uid = :3") public Bill getBill(String table, int cid, String uid); } @DB(name = "db4") interface Bill4Dao extends IBillDao { @SQL("insert into #{:table}(cid, uid, price) values(:cid, :uid, :price)") int insert(@Rename("table") String table, Bill bill); @SQL("select cid, uid, price from #{:1} where cid = :2 and uid = :3") public Bill getBill(String table, int cid, String uid); } @DB(table = "bill") @Sharding( databaseShardingStrategy = BillDatabaseShardingStrategy.class, tableShardingStrategy = BillTableShardingStrategy.class ) interface BillDao { @SQL("insert into #table(cid, uid, price) values(:cid, :uid, :price)") int insert(@DatabaseShardingBy("cid") @TableShardingBy("uid") Bill bill); @SQL("select cid, uid, price from #table where cid = :1 and uid = :2") public Bill getBill(@DatabaseShardingBy int cid, @TableShardingBy String uid); } static class BillDatabaseShardingStrategy implements DatabaseShardingStrategy<Integer> { @Override public String getDataSourceFactoryName(Integer cid) { return getDatabaseByCid(cid); } } static class BillTableShardingStrategy implements TableShardingStrategy<String> { @Override public String getTargetTable(String table, String uid) { return table + "_" + Integer.valueOf(uid) % 10; } } @DB(table = "bill") @Sharding(shardingStrategy = BillShardingStrategy.class) interface SimpleBillDao { @SQL("insert into #table(cid, uid, price) values(:cid, :uid, :price)") int insert(@DatabaseShardingBy("cid") @TableShardingBy("uid") Bill bill); @SQL("select cid, uid, price from #table where cid = :1 and uid = :2") public Bill getBill(@DatabaseShardingBy int cid, @TableShardingBy String uid); } static class BillShardingStrategy implements ShardingStrategy<Integer, String> { @Override public String getDataSourceFactoryName(Integer cid) { return getDatabaseByCid(cid); } @Override public String getTargetTable(String table, String uid) { return table + "_" + Integer.valueOf(uid) % 10; } } private static String getDatabaseByCid(int cid) { long hash = HashUtil.fnv1_31(cid); return "db" + (hash % 4 + 1); } private static String getTableByUid(String uid) { return "bill_" + Integer.valueOf(uid) % 10; } private static IBillDao getDaoByCid(int cid) { String database = getDatabaseByCid(cid); if ("db1".equals(database)) { return bill1Dao; } else if ("db2".equals(database)) { return bill2Dao; } else if ("db3".equals(database)) { return bill3Dao; } else if ("db4".equals(database)) { return bill4Dao; } return null; } }