package jef.orm.partition; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; import jef.common.log.LogUtil; import jef.database.Condition.Operator; import jef.database.DbClient; import jef.database.ORMConfig; import jef.database.PagingIterator; import jef.database.QB; import jef.database.Session.PopulateStrategy; import jef.database.annotation.PartitionTable; import jef.database.annotation.PartitionTableImpl; import jef.database.meta.FBIField; import jef.database.meta.MetaHolder; import jef.database.query.Query; import jef.database.query.RangeDimension; import jef.database.query.Selects; import jef.database.query.UnionQuery; import jef.database.routing.PartitionResult; import jef.database.test.DataSource; import jef.database.test.DataSourceContext; import jef.database.test.DatabaseInit; import jef.database.test.IgnoreOn; import jef.database.test.JefJUnit4DatabaseTestRunner; import jef.json.JsonUtil; import jef.tools.DateUtils; import jef.tools.IOUtils; import org.junit.Test; import org.junit.runner.RunWith; /** * 这个测试案例描述各种单表操作的分表计算办法 1、目前实现的: 使用 * * @author Administrator * */ @RunWith(JefJUnit4DatabaseTestRunner.class) @DataSourceContext({ @DataSource(name="oracle",url="${oracle.url}",user="${oracle.user}",password="${oracle.password}"), @DataSource(name = "mysql", url = "${mysql.url}", user ="${mysql.user}", password = "${mysql.password}"), @DataSource(name="postgresql",url="${postgresql.url}",user="${postgresql.user}",password="${postgresql.password}"), @DataSource(name = "derby", url = "jdbc:derby:./db;create=true"), @DataSource(name = "hsqldb", url = "jdbc:hsqldb:mem:testhsqldb", user = "sa", password = ""), @DataSource(name = "sqlite", url = "jdbc:sqlite:test.db?date_string_format=yyyy-MM-dd HH:mm:ss"), @DataSource(name = "sqlserver", url ="${sqlserver.url}",user="${sqlserver.user}",password="${sqlserver.password}") }) public class PartitionTest extends org.junit.Assert { private DbClient db; public static class A { Class<?> clz; } @Test public void main1() { A a = new A(); a.clz = int.class; String aa = JsonUtil.toJsonWithoutQuot(a); System.out.println(aa); A b = JsonUtil.toObject(aa, A.class); PartitionTable object = PartitionEntity.class.getAnnotation(PartitionTable.class); PartitionTableImpl my = PartitionTableImpl.create(object); String data = JsonUtil.toJsonWithoutQuot(my); System.out.println(data); PartitionTable rr = JsonUtil.toObject(data, PartitionTableImpl.class); System.out.println(rr); } @DatabaseInit public void createTables() throws SQLException { try { db.dropTable(PartitionEntity.class); db.createTable(PartitionEntity.class); PartitionEntity p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 3, 1)); p.setName("Zxa"); db.dropTable(p); db.createTable(p); // p.setDateField(DateUtils.get(2012, 3, 2)); // p.setName("XX"); // db.dropTable(p); // db.createTable(p); // // p.setDateField(DateUtils.get(2012, 4, 1)); // p.setName("a"); // db.dropTable(p); // db.createTable(p); // // p.setDateField(DateUtils.get(2012, 5, 1)); // p.setName("A"); // db.dropTable(p); // db.createTable(p); // // p.setDateField(DateUtils.get(2012, 6, 1)); // p.setName("XXX"); // db.dropTable(p); // db.createTable(p); // // p.setDateField(DateUtils.get(2012, 7, 1)); // p.setName(null); // db.dropTable(p); // db.createTable(p); } catch (Exception e) { LogUtil.exception(e); } } /** * @测试对象 测试当 简单条件,between构成的Range条件时判断查询的表 * * @预期结果 查询03,04,05,06四张分表 * @throws SQLException */ @Test public void testBetween() throws SQLException { System.out.println("===================== testBetween 03,04,05,06======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.getInstance().setName("Zxa"); q.addCondition(QB.between(PartitionEntity.Field.dateField, DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1))); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } /** * * @测试对象 测试当 IN条件下时判断查询的表 * * @预期结果 查询03,06表 * @throws SQLException */ @Test public void testDimensionIn() throws SQLException { System.out.println("===================== testDimensionIn 03,06======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(PartitionEntity.Field.dateField, Operator.IN, new Date[] { DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1) }); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } @Test public void testGroup() throws SQLException { System.out.println("===================== testDimensionIn 03,06======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); Selects items = QB.selectFrom(q); items.column(PartitionEntity.Field.longField).group().as("longField"); items.column(PartitionEntity.Field.intField).count().as("intField"); List<PartitionEntity> result = db.select(q); } /** * @测试对象 测试当 三个普通eq条件用OR拼装 时判断查询的表 * * @预期结果 查询03,05,06表 * @throws SQLException */ @Test public void testDimension3ConditionOr() throws SQLException { System.out.println("===================== testDimension3ConditionOr 03,05,06======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(QB.or(QB.eq(PartitionEntity.Field.dateField, DateUtils.get(2012, 3, 1)), QB.eq(PartitionEntity.Field.dateField, DateUtils.get(2012, 5, 1)), QB.eq(PartitionEntity.Field.dateField, DateUtils.get(2012, 6, 1)))); q.addOrderBy(false, PartitionEntity.Field.name); /* * select * from (select t.* from PARTITIONENTITY_05 t where (t.ID=? or * t.ID=? or t.ID=?) union all select t.* from PARTITIONENTITY_06 t * where (t.ID=? or t.ID=? or t.ID=?) union all select t.* from * PARTITIONENTITY_03 t where (t.ID=? or t.ID=? or t.ID=?) ) t order by * t.NAME DESC */ db.select(q); } /** * @测试对象 测试当 对于大于和小于构成的区间 时判断查询的表 * * @预期结果 查询03,04,05,06表 * @throws SQLException */ @Test public void testDimensionSpan() throws SQLException { System.out.println("===================== testDimensionSpan 3,4,5,6======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(PartitionEntity.Field.dateField, Operator.GREAT_EQUALS, DateUtils.get(2012, 3, 1)); q.addCondition(PartitionEntity.Field.dateField, Operator.LESS, DateUtils.get(2012, 6, 2)); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } /** * @测试对象 较复杂的维度解析,一个 IN条件 AND 一个<的开区间Range条件 * * @预期结果 查询03表 * * @throws SQLException */ @Test public void testDimensionInWithRange() throws SQLException { System.out.println("===================== testSpan 03======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(PartitionEntity.Field.dateField, Operator.IN, new Date[] { DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1) }); q.addCondition(PartitionEntity.Field.dateField, Operator.LESS, DateUtils.get(2012, 5, 1)); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } /** * @测试对象 和上例一样,不同的是会将所有的有效区间都去掉,某种意义上分区条件构成的一个永远为false的表达式。 * 这种情况下,不存在任何能匹配用户查询条件的表。为了查询能够正确执行,我们使用基础表(即不带分表后缀的表做查询) * * @预期结果 查询基础表 * * 错误,变化为查询全部实际存在的表…… * * 由于代码修改,造成基表都没有创建。。。。此时出错 * @throws SQLException */ @Test public void testDimensionInWithRange2() throws SQLException { System.out.println("===================== testSpan 原始表======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(PartitionEntity.Field.dateField, Operator.IN, new Date[] { DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1) }); q.addCondition(PartitionEntity.Field.dateField, Operator.LESS, DateUtils.get(2012, 3, 1)); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } /** * 较复杂的维度解析,一个 IN条件 OR 一个Between的Range条件 * * @throws SQLException */ @Test public void testDimensionInX() throws SQLException { System.out.println("===================== testSpan 03,05,06,07======================="); Query<PartitionEntity> q = QB.create(PartitionEntity.class); q.addCondition(QB.or(QB.in(PartitionEntity.Field.dateField, new Date[] { DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1) }), QB.between(PartitionEntity.Field.dateField, DateUtils.get(2012, 5, 1), DateUtils.get(2012, 7, 1)))); q.addCondition(PartitionEntity.Field.intField, Operator.GREAT, 14); q.addCondition(PartitionEntity.Field.intField, Operator.LESS, 17); q.addOrderBy(false, PartitionEntity.Field.name); db.select(q); } /** * 基础测试,测试分表维度的计算 */ public void testMathRange() { RangeDimension<Integer> a = new RangeDimension<Integer>(3, 15); RangeDimension<Integer> b = new RangeDimension<Integer>(4, 16); RangeDimension<Integer> c = new RangeDimension<Integer>(3, 17, false, true); RangeDimension<Integer> d = new RangeDimension<Integer>(4, 6, false, false); RangeDimension<Integer> e = new RangeDimension<Integer>(null, 13); RangeDimension<Integer> f = new RangeDimension<Integer>(6, null); System.out.println(a + " AND " + b + " = " + a.mergeAnd(b)); System.out.println(a + " AND " + c + " = " + a.mergeAnd(c)); System.out.println(a + " AND " + d + " = " + a.mergeAnd(d)); System.out.println(a + " AND " + e + " = " + a.mergeAnd(e)); System.out.println(a + " AND " + f + " = " + a.mergeAnd(f)); System.out.println(a + " OR " + b + " = " + a.mergeOr(b)); System.out.println(a + " OR " + c + " = " + a.mergeOr(c)); System.out.println(a + " OR " + d + " = " + a.mergeOr(d)); System.out.println(a + " OR " + e + " = " + a.mergeOr(e)); System.out.println(a + " OR " + f + " = " + a.mergeOr(f)); RangeDimension<Date> g = new RangeDimension<Date>(new Date(), null); RangeDimension<Date> h = new RangeDimension<Date>(DateUtils.get(2011, 1, 1), DateUtils.get(2012, 5, 1), false, false); RangeDimension<Date> i = new RangeDimension<Date>(DateUtils.get(2011, 1, 1), DateUtils.get(2012, 5, 1), true, true); System.out.println(g + " AND " + h + " = " + g.mergeAnd(h)); System.out.println(g + " AND " + i + " = " + g.mergeAnd(i)); System.out.println(h + " AND " + i + " = " + h.mergeAnd(i)); System.out.println(g + " OR " + h + " = " + g.mergeOr(h)); System.out.println(g + " OR " + i + " = " + g.mergeOr(i)); System.out.println(h + " OR " + i + " = " + h.mergeOr(i)); } /** * 当批操作时 批会对结果自动分组,然后将数据分别查到不同的表里去 * * @throws SQLException */ @Test public void testPartitionBatchInsert() throws SQLException { db.createTable(PartitionEntity.class); List<PartitionEntity> batch = new ArrayList<PartitionEntity>(); PartitionEntity p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 3, 1)); p.setName("张三"); batch.add(p); p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 5, 1)); p.setName("王五"); batch.add(p); p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 4, 10)); p.setName("李四"); batch.add(p); p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 5, 20)); p.setName("前五"); batch.add(p); p = new PartitionEntity(); p.setDateField(DateUtils.get(2012, 3, 8)); p.setName("赵三"); batch.add(p); // 这个开关可以关闭分组插入 // batch.setGroupForPartitionTable(false); db.batchInsert(batch); } /** * 调用count方法,覆盖多张表的场合 当分为多张表的时候,采用多个count语句查询,然后将结果相加 * * @throws SQLException */ @Test public void testCountAll() throws SQLException { System.out.println("======================testCountAll========================"); db.count(QB.create(PartitionEntity.class)); } /** * 查询记录覆盖多张表的场合 直接用union All一次查询所有表得出结果 * * @throws SQLException */ @Test public void testSelectAll() throws SQLException { System.out.println("======================testSelectAll========================"); db.selectAll(PartitionEntity.class); } /** * 分表扫描器测试。分表扫描器能自动检查数据库中的所有子表。 * * @throws SQLException */ @Test public void testPartitionMetadata() throws SQLException { db.dropTable(PartitionEntity.class); db.createTable(PartitionEntity.class); System.out.println("======================testPartitionMetadata========================"); long start = System.nanoTime(); PartitionResult[] result = db.getSubTableNames(MetaHolder.getMeta(PartitionEntity.class)); System.out.println("1." + (System.nanoTime() - start)); LogUtil.show(result); assertEquals(12,result[0].tableSize()); // 第二次查询分表元数据,根据缓存,在刷新期内不会再访问数据库。 start = System.nanoTime(); db.getSubTableNames(MetaHolder.getMeta(PartitionEntity.class)); System.out.println("2." + (System.nanoTime() - start)); } /** * 分表环境下,对查询列指定别名的场景测试 * * @throws SQLException */ @Test public void testSelectUsingAlias() throws SQLException { ORMConfig.getInstance().setFilterAbsentTables(false); testPartitionBatchInsert(); // prepare data ORMConfig.getInstance().cacheDebug = true; Query<PartitionEntity> q = QB.create(PartitionEntity.class); Selects items = QB.selectFrom(q); items.column(PartitionEntity.Field.id).as("id"); items.column(PartitionEntity.Field.name).as("name"); items.column(PartitionEntity.Field.dateField).as("dateField"); items.column(PartitionEntity.Field.longField).as("longField"); items.column(PartitionEntity.Field.intField).as("intField"); q.getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); List<PartitionEntity> list = db.select(q, null); for (PartitionEntity obj : list) { LogUtil.show(obj.toString()); org.junit.Assert.assertTrue(obj.getDateField() != null); } // 再测试下使用UnionQuery的场景 UnionQuery<PartitionEntity> unionQuery = QB.unionAll(PartitionEntity.class, q); unionQuery.getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); List<PartitionEntity> list2 = db.select(unionQuery, null); for (PartitionEntity obj : list2) { LogUtil.show(obj.toString()); org.junit.Assert.assertTrue(obj.getDateField() != null); } } /** * 分表环境下,分组查询时,对查询列指定别名的场景测试 * * @throws SQLException */ @Test public void testGroupUsingAlias() throws SQLException { System.out.println("===================== testGroupUsingAlias ======================="); testPartitionBatchInsert(); // prepare data Query<PartitionEntity> q = QB.create(PartitionEntity.class); Selects items = QB.selectFrom(q); items.column(PartitionEntity.Field.longField).as("longField"); items.column(PartitionEntity.Field.intField).as("intField"); items.column(PartitionEntity.Field.longField).group().as("longField"); items.column(PartitionEntity.Field.intField).count().as("intField"); q.getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); db.select(q, null); } /** * 分表环境下,分页查询时,对查询列指定别名的场景测试 * * @throws SQLException */ @Test public void testPageUsingAlias() throws SQLException { System.out.println("===================== testPageUsingAlias ======================="); testPartitionBatchInsert(); // prepare data PartitionEntity entity = new PartitionEntity(); entity.getQuery().addCondition(QB.between(PartitionEntity.Field.dateField, DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1))); Selects selectItems1 = QB.selectFrom(entity.getQuery()); selectItems1.column(PartitionEntity.Field.id).as("id"); selectItems1.column(PartitionEntity.Field.dateField).as("dateField"); selectItems1.column(PartitionEntity.Field.intField).as("intField"); selectItems1.column(PartitionEntity.Field.longField).as("longField"); entity.getQuery().getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); PagingIterator<PartitionEntity> page = db.pageSelect(entity, 4); List<PartitionEntity> list = page.next(); for (PartitionEntity obj : list) { LogUtil.show(obj.toString()); org.junit.Assert.assertTrue(obj.getDateField() != null); } } /** * 分表环境下,2表关联并分页查询时,对查询列指定别名的场景测试; 同时测试当查询结果需要映射到带有@Column的实体类的场景。 * * @throws SQLException */ @Test public void testUnionUsingAlias() throws SQLException { System.out.println("===================== testUnionUsingAlias ======================="); testPartitionBatchInsert(); // prepare data for PartitionEntity // prepare data for NonPartitionEntity db.createTable(NonPartitionEntity.class); List<NonPartitionEntity> batch = new ArrayList<NonPartitionEntity>(); NonPartitionEntity p = new NonPartitionEntity(); p.setDateField(DateUtils.get(2012, 3, 1)); p.setName("张三"); batch.add(p); p = new NonPartitionEntity(); p.setDateField(DateUtils.get(2012, 5, 1)); p.setName("王五"); batch.add(p); p = new NonPartitionEntity(); p.setDateField(DateUtils.get(2012, 4, 10)); p.setName("李四"); batch.add(p); p = new NonPartitionEntity(); p.setDateField(DateUtils.get(2012, 5, 20)); p.setName("前五"); batch.add(p); p = new NonPartitionEntity(); p.setDateField(DateUtils.get(2012, 3, 8)); p.setName("赵三"); batch.add(p); // 这个开关可以关闭分组插入 db.batchInsert(batch, false); // prepare data for NonPartitionEntity finished NonPartitionEntity entity1 = new NonPartitionEntity(); entity1.getQuery().addCondition(NonPartitionEntity.Field.intField, 0); PartitionEntity entity = new PartitionEntity(); entity.getQuery().addCondition(QB.between(PartitionEntity.Field.dateField, DateUtils.get(2012, 3, 1), DateUtils.get(2012, 6, 1))); Selects selectItems1 = QB.selectFrom(entity1.getQuery()); selectItems1.column(NonPartitionEntity.Field.id).as("id"); selectItems1.column(NonPartitionEntity.Field.name).as("name"); selectItems1.column(NonPartitionEntity.Field.dateField).as("dateField"); selectItems1.column(NonPartitionEntity.Field.intField).as("intField"); selectItems1.column(NonPartitionEntity.Field.longField).as("longField"); Selects selectItems2 = QB.selectFrom(entity.getQuery()); selectItems2.column(PartitionEntity.Field.id).as("id"); selectItems2.column(PartitionEntity.Field.name).as("name"); selectItems2.column(PartitionEntity.Field.dateField).as("dateField"); selectItems2.column(PartitionEntity.Field.intField).as("intField"); selectItems2.column(PartitionEntity.Field.longField).as("longField"); UnionQuery<NonPartitionEntity> unionQuery = QB.unionAll(NonPartitionEntity.class, entity1.getQuery(), entity.getQuery()); unionQuery.addOrderBy(false, new FBIField("dateField")); unionQuery.getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); PagingIterator<NonPartitionEntity> page = db.pageSelect(unionQuery, NonPartitionEntity.class, 4); List<NonPartitionEntity> list = page.next(); for (NonPartitionEntity obj : list) { LogUtil.show(obj.toString()); org.junit.Assert.assertTrue(obj.getDateField() != null); } // 再测试下查询结果映射到不带有@Column的实体类的场景 UnionQuery<PartitionEntityResult> unionQuery2 = QB.unionAll(PartitionEntityResult.class, entity1.getQuery(), entity.getQuery()); PagingIterator<PartitionEntityResult> page2 = db.pageSelect(unionQuery2, PartitionEntityResult.class, 4); List<PartitionEntityResult> list2 = page2.next(); for (PartitionEntityResult obj : list2) { LogUtil.show(obj.toString()); org.junit.Assert.assertTrue(obj.getDateField() != null); } } @Test @IgnoreOn({ "oracle", "postgresql" }) public void jsonLoad() throws IOException { System.out.println("=====================================1"); String s = IOUtils.asString(this.getClass().getResource("resource.txt"), "GBK"); System.out.println(s); PartitionTableImpl table = JsonUtil.toObject(s, PartitionTableImpl.class); System.out.println(table.key()); String s2 = JsonUtil.toJson(table); System.out.println("====================================="); System.out.println(s2); } }