接上文,我们获取到了连接,需要封装成查询类进行查询操作
我们就叫它BillQuery
BillQuery
举个栗子,我们通过主表主键来执行查询操作。其实保证唯一性
我们规定:public class BillQuery实例化的时候必须要使用泛型,
public BillQuery(Class<E> clazz)
构造参数必须传入对应的class
每个pojo都是基于元数据来得,所以在实例化BillQuery的时候,我们把一些信息注入到类内部,
在查询的时候可以获取到主表的SinglePojo和子表的(List)SinglePojo.
查询策略是先查主表,主表的主键就是子表的外键,再查询子表
我们通过的是主表主键的List数组来进行查询,这个时候会有一个问题,一般情况下,我们用in的语句来进行数组数据的查询,这个时候会有效率问题。我们设置Max的in的数量为100,如果超过100的数量,我们采取创建临时表的方式来查询
private ISinglePojo[] query(Class<? extends ISinglePojo> clazz,
IAttributeMeta field, TableIDQueryCondition conditionBuilder) {
IAttributeMeta[] feilds = new IAttributeMeta[] {
field
};
String condition = conditionBuilder.build(feilds);
SinglePojoQuery query = new SinglePojoQuery(clazz);
ISinglePojo[] pojos = query.queryWithWhereKeyWord(condition, null);
IVOMeta meta = null;
if (pojos.length > 0) {
meta = pojos[0].getMetaData();
}
else {
ISinglePojo pojo = Constructor.construct(clazz);
meta = pojo.getMetaData();
}
String message = "从数据库中加载【" + meta.getLabel();
message = message + "】数据" + pojos.length;
return pojos;}
我们使用对于SinglePojo适用的query方法进行查询主表数据
private String constructSQL(IAttributeMeta[] attributeMetas,String wheresqlpart, String condition, String order) {
ITableMeta[] tables =
this.getTables(attributeMetas, wheresqlpart, condition, order);
SqlBuilder sql = new SqlBuilder();
sql.append(" select ");
// 要查询的字段
sql.append(this.constructQueryField(attributeMetas, tables.length > 1));
sql.append(" from ");
// 要查询的表
for (ITableMeta table : tables) {
sql.append(table.getName());
sql.append(",");
}
sql.deleteLastChar();
if (wheresqlpart == null) {
sql.append(" where ");
}
else {
sql.append(" ");
sql.append(wheresqlpart);
sql.append(" and ");
}
IAttributeMeta keyMeta = this.voMeta.getPrimaryAttribute();
// 看是否有主键。如果没有主键,则当前元数据也不可能有扩展表。因为没有对应的主键存在
if (keyMeta.getColumn() != null) {
ITableMeta mainTable = keyMeta.getColumn().getTable();
// 表间连接语句,包含了dr=0
String connectSql = this.constructTableConnecSQL(tables, mainTable);
sql.append(connectSql);
}
else {
sql.append(tables[0].getName());
sql.append(".");
sql.append("dr=0 ");
}
// 额外的条件
if (condition != null) {
sql.append(" ");
sql.append(condition);
}
// 排序语句
if (order != null) {
sql.append(" ");
sql.append(order);
}
return sql.toString(); }
我们的sql的组装就通过元数据+pojo类已经完成
这个时候我们刚刚说的数据库连接就用到了
public IRowSet query(String sql) {
DBTool tool = new DBTool();
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
List<Object[]> list = new ArrayList<Object[]>();
int count = -1;
int rowcount = 0;
try {
connection = tool.getConnection();
stmt = connection.createStatement();
// 设置结果集
if (this.maxRows> 0) {
stmt.setMaxRows(this.maxRows);
}else {
stmt.setMaxRows(0);
}
rs = stmt.executeQuery(sql);
count = rs.getMetaData().getColumnCount();
while (rs.next()) {
Object[] rows = new Object[count];
for (int i = 0; i < count; i++) {
rows[i] = rs.getObject(i + 1);
}
list.add(rows);
rowcount++;
if (this.maxRows != DataAccessUtils.MAX_ROWS
&& rowcount >= this.maxRows) {
break;
}
}
}
catch (SQLException ex) {
TransferSqlException e = new TransferSqlException(ex, sql);
ExceptionUtils.wrappException(e);
}
finally {
this.closeDB(connection, stmt, rs);
}
int size = list.size();
Object[][] data = new Object[size][count];
data = list.toArray(data);
IRowSet rowSet = new RowSet(data);
return rowSet;
}
我们使用PrepareStatement 来进行实际的预编译查询,减少了sql注入的风险,也有助于提高批量查询的执行效率
执行完成,用RowSet包装返回数据
这个时候我们需要将返回的RowSet与我们的SinglePojo进行匹配转换
public E[] convert(IRowSet rowset) {
int size = rowset.size();
E[] pojos = Constructor.construct(this.clazz, size);
int cursor = 0;
int length = this.names.length;
while (rowset.next()) {
for (int i = 0; i < length; i++) {
Object value = rowset.getObject(i);
//BLOB类型的JavaType转换为Object,数据比较大时,oracle会转换成LONG存储,超过LONG的范围会报错,
//因此,判断Object类型数据是String时,转换为byte[]来进行存储,见类DataAccessUtils
//查询出来后如属性原始类型为BLOB,需要将byte[]再转为String,如为其它类似TYPE_IMAGE,则不需要转为String
if (pojos[cursor].getMetaData() == null) {
pojos[cursor].setAttributeValue(this.names[i], value);
} else {
IAttributeMeta attribute = pojos[cursor].getMetaData().getAttribute(this.names[i]);
if (attribute != null && attribute.getModelType() == IType.TYPE_BLOB && value instanceof byte[]) {
value = new String((byte[])value);
}
pojos[cursor].setAttributeValue(this.names[i], value);
}
}
cursor++;
}
return pojos;
}
这样就实现了返回值RowSet与实体类的赋值操作,实际我们能看出,我们的Mapping是放在了元数据来实现的,也就是最开始的PowerDesign来实现
这样主表的pojo我们赋值完毕,查询子表的方式类似,要考虑多子表的情况稍微复杂一点点
最后,我们需要将主表pojo和子表pojo组合成AggPojo
public E[] composite() {
IVOMeta parentMeta = this.billMeta.getParent();
IVOMeta[] childrenMeta = this.billMeta.getChildren();
List<E> list = new ArrayList<E>();
MapList<String, SinglePojo> index = this.voIndex.get(parentMeta);
Set<Entry<String, List<SinglePojo>>> entryset = index.entrySet();
for (Entry<String, List<SinglePojo>> entry : entryset) {
String pk = entry.getKey();
SinglePojo parent = entry.getValue().get(0);
E bill = Constructor.construct(this.billClass);
bill.setParent(parent);
for (IVOMeta childMeta : childrenMeta) {
SinglePojo[] pojos = this.construct(pk, childMeta);
bill.setChildren(childMeta, pojos);
}
list.add(bill);
}
E[] bills = null;
if (list.size() == 0) {
bills = Constructor.declareArray(this.billClass, 0);
}
else {
ListToArrayTool<E> tool = new ListToArrayTool<E>();
bills = tool.convertToArray(list);
}
return bills;}
这样实现了一个nosql的查询,这些过程对于使用者来说都是透明的
现在基本实现了对于数据的查询
有些时候,业务数据比较多的情况下,粗粒度的查询难免会导致查询的数据过多,影响查询效率和用户的友好程度,而且这样的查询在主子表的情况下没有做任何筛选就全查出来了,可能有些子表数据我们不关心,所以细粒度没有精细到表体行。
所以我们有了懒加载的查询,和针对子表查询返回主子表数据的ViewPojo查询。下次分享