轻量级封装DbUtils&Mybatis之一概要
Why#
一时兴起,自以为是的对Jdbc访问框架做了一个简单的摸底,近期主要采用Mybatis,之前也有不少采用Dbutils,因此希望能让这两个框架折腾的更好用。
DbUtils:非常简单的Jdbc访问框架,极为轻量级,对数据查询结果集转换成目标的对象或列表或其它集合结构做了很好的支持(xxHandler)。
Mybatis:ibatis(暂未使用过)的升级版,目前所知它至少有两个坑,其一是假分页(参考DefaultResultSetHandler的skipRows方法),其二是不能支持对象列表存储时对自增id字段的赋值(至少包括3.2.6和3.3.0版本)。
参考项目#
mybatis分页组件(也支持排序,通过外置增加的排序和分页选项,在mapper文件中配置sql不包含排序):mybatis-pagination
轻量级改造概要#
Dbutils
- 简单的封装,增加代码复用,并尽量支持泛型化
Mybatis
- 实际的处理分页拦截器,暂只支持MySQL和Oracle(目前网络上关于此已经有了大量的实践,但是个人认为某些实践破坏了Mybatis本身的一些优良特性,细节将在后面的文章给出说明)
- 处理对象列表存储时自动对自增主键赋值,目前几乎完全照搬了Git上的一个项目mybatis-batch-insert的内容,只是稍做修改。
场景#
试想一下,当使用原生Jdbc执行SQL时,我们希望它有哪些feature呢?
- 支持查询泛型对象列表
- 支持插入对象列表时自动填充主键
- 支持插入对象列表
- 支持批量插入和更新
- 支持SQL语句生成和解析
- 支持多种数据库
- 支持结果集处理成各类存储结构(list,map)
实现细节#
方言##
除去标准SQL支持,不同数据库的SQL语法略有差异(虽然知道的不多),比如分页,MySQL采用limit关键字支持,Oracle则采用rownum支持。
方言枚举(目前仅支持MySQL和Oracle,其它的暂时用不到)
package org.wit.ff.jdbc.dialect;
/**
* Created by F.Fang on 2015/11/19.
*/
public enum DialectType {
MYSQL, ORACLE
}
方言定义
请参考mybatis-pagination项目里关于方言的定义,此处就不引用他的代码了,请为他的Job增加人气。
标准SQL生成#
标准SQL支持##
请参考Mybatis的AbstractSQLBuilder和SQLBuilder
SQLBuilder(有修改,增加分页支持)##
/*
* Copyright 2009-2012 The MyBatis Team
*
* Licensed 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.wit.ff.jdbc.sql;
import org.wit.ff.jdbc.dialect.Dialect;
public abstract class SQLBuilder extends AbstractSQLBuilder<SQLBuilder> {
protected boolean paging;
protected int offset;
protected int pageSize;
@Override
public SQLBuilder getSelf() {
return this;
}
protected abstract Dialect getDialect();
public SQLBuilder PAGE(int offset, int pageSize) {
paging = true;
// 这里作为底层接口不做任何检查,上层业务调用时检查.
this.offset = offset;
this.pageSize = pageSize;
return this;
}
@Override
public String toString() {
if(paging){
return getDialect().getLimitString(super.toString(), offset, pageSize);
}else{
return super.toString();
}
}
}
MySQLBuilder##
package org.wit.ff.jdbc.sql.db;
import org.wit.ff.jdbc.dialect.Dialect;
import org.wit.ff.jdbc.dialect.db.MySQLDialect;
import org.wit.ff.jdbc.sql.SQLBuilder;
/**
* Created by F.Fang on 2015/2/16.
* Version :2015/2/16
*/
public class MySQLBuilder extends SQLBuilder {
private Dialect dialect = new MySQLDialect();
@Override
public Dialect getDialect() {
return dialect;
}
}
OracleBuilder##
package org.wit.ff.jdbc.sql.db;
import org.wit.ff.jdbc.dialect.Dialect;
import org.wit.ff.jdbc.dialect.db.OracleDialect;
import org.wit.ff.jdbc.sql.SQLBuilder;
/**
* Created by F.Fang on 2015/11/20.
*/
public class OracleBuilder extends SQLBuilder {
private Dialect dialect = new OracleDialect();
@Override
public Dialect getDialect() {
return dialect;
}
}
自增主键处理#
自定义接收主键数据的接口
package org.wit.ff.jdbc.id;
/**
* Created by F.Fang on 2015/2/16.
* Version :2015/2/16
*/
public interface IdGenerator {
/**
* 参数为数组的原因是考虑联合主键,虽然暂时不会有对联合主键的支持.
* @param value
*/
void parseGenKey(Object[] value);
}
数据接口定义#
package org.wit.ff.jdbc.access;
import org.wit.ff.jdbc.converter.ParamsConverter;
import java.util.List;
/**
* Created by F.Fang on 2015/3/31.
* 简单公共数据访问层.
* Version :2015/3/31
*/
public interface IDataAccessor {
/**
* 查询
* @param sql
* @param resultType 对象类型
* @param <T>
* @return
*/
<T> List<T> query(String sql, Class<T> resultType);
/**
* 查询,如果返回类型是具体类型,那么就采用
* @param sql 查询语句
* @param params 查询参数
* @param resultType 返回类型
* @param <T>
* @return
*/
<T> List<T> query(String sql, Object[] params, Class<T> resultType);
/**
* insert 对象列表.
* @param sql insert语句.
* @param params 对象参数列表.
* @param paramsType 参数类型.
* @param converter 参数转换器.
* @param <T>
*/
<T> void insert(String sql, List<T> params, Class<T> paramsType, ParamsConverter<T> converter);
/**
* insert batch.
* @param sql
* @param params
*/
void insert(String sql, Object[][] params);
/**
* single insert.
* @param sql
* @param params
*/
void insert(String sql, Object[] params);
/**
* batch update.
* @param sql
* @param params
* @return
*/
int[] update(String sql, Object[][] params);
/**
* single update.
* @param sql
* @param params
* @return
*/
int update(String sql, Object[] params);
/**
* 删除,删除可采用条件替代批量.
* @param sql
* @param params
* @return
*/
int delete(String sql, Object[] params);
}
参数处理#
package org.wit.ff.jdbc.converter;
/**
* Created by F.Fang on 2015/3/31.
* 用于参数转换的接口.
* Version :2015/3/31
*/
public interface ParamsConverter<T> {
Object[] convert(T obj);
}
结果集处理#
暂无(目前开源社区有大量的相关API)
QA#
一段旅程,远去所有昨天的昨天,如记事本翻开新的一页,永远的不漏痕迹的把记忆藏在一片洁白中。然后绚烂的开始新的故事。