您的位置:首页 > 编程语言 > Java开发

初步封装jdbc

2015-12-27 14:39 387 查看
单纯的通过jdbc来写数据库操作时,有很多“废话”代码,不写又不行,写了又嫌麻烦。一些持久层框架帮助我们解决了这些问题。大大加快了开发的效率。我刚接触反射,于是自己琢磨着写一个初步的jdbc封装,既可以练手,又可以复用,关键是自己造的小轮子,使用过程中,思路和注意点会非常清晰。若有错误,十分欢迎各位前辈指正!这只是一个初步的简单封装,用的一些初级的语句测试,都没有问题。不过如果是复杂的sql语句有可能会出现bug。一步一步来吧。遇到问题,用debug模式调试,效率很高,容易发现不起眼的细节问题。

说明一下自己的思路。首先,一定是面向对象的,传值和返回值,我们都是以一个对象作为参数传递。这样在不同的模块操作时,有利于一个整体的思路,并且扩展性稍好。其次,一个sql语句包含了字段名,我们只需要获取到字段名对应的值,那么sql语句就可以执行了。执行之后的结果,分为两部分,一是执行executeQuery,所以我们需要对获取到的记录进行封装,有几条就封装几个,最后装入一个ArrayList,作为返回值即可。二是执行executeUpdate,返回值是一个int的整数,只需判断是否大于零,返回true或者false即可。这是整个流程的整体思路。

以下是代码:

public class CrudOperation {
public Object operator(String sql,Object entity){
String[] array=entity.getClass().toString().split(" ");
String className=array[1];
Object object=null;
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
int n=0;
Map<String,Object> map=reflectForParameters(className,sql,entity);
ArrayList<String> columnList=(ArrayList<String>) map.get("column");
ArrayList<Object> parameterList=(ArrayList<Object>) map.get("parameter");
ArrayList<String> returnTypeList=(ArrayList<String>) map.get("returnType");
ArrayList<Object> resultOfEntity=new ArrayList<Object>();
con=JdbcConnection.getConnection();
try {
Class clazz=Class.forName(className);
ps=con.prepareStatement(sql);
for(int i=0;i<columnList.size();i++){
if("Integer".equalsIgnoreCase(returnTypeList.get(i))||"int".equalsIgnoreCase(returnTypeList.get(i))){
ps.setInt(i+1,(Integer) parameterList.get(i));
}
else if("Date".equalsIgnoreCase(returnTypeList.get(i))){
ps.setDate(i+1, (Date) parameterList.get(i));
}
else{
ps.setString(i+1, (String) parameterList.get(i));
}
}
if(sql.trim().startsWith("select")){
rs=ps.executeQuery();
ArrayList<Object> result=result=new ArrayList<Object>();//这句放到while(rs.next)下面,不然出bug,刚发现的
while(rs.next()){
Field[] fields=clazz.getDeclaredFields();
for(Field f:fields){
if(!"serialVersionUID".equals(f.getName().toString())){
if("int".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1))
||"Integer".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1))){
resultOfEntity.add(rs.getInt(f.getName().toString()));
}
else if("Date".equalsIgnoreCase(f.getType().toString().substring(f.getType().toString().lastIndexOf(".")+1))){
resultOfEntity.add(rs.getDate(f.getName().toString()));
}
else{
resultOfEntity.add(rs.getString(f.getName().toString()));
}
}
}
//	rs.next()为真,则有记录,将每一条记录都反射封装成对象,装入结果集
result.add(reflectToCreateEntity(className,resultOfEntity));
}
object=result;
}
else{
n=ps.executeUpdate();
if(n>0){
object=true;
}
else{
object=false;
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
if(rs!=null){
JdbcConnection.close(con, ps, rs);
}
else if(ps!=null){
JdbcConnection.close(con, ps);
}
else{
JdbcConnection.close(con);
}
}
return object;
}

/**
* 这个方法用于执行完数据库操作之后,封装所取出来的字段成为对象。
* 参数需求为className和resultOfEntity,其中resultOfEntity表示对象所有的字段的值,其顺序必须与数据库字段顺序一样,这一点在建表时先做好。
* 通过反射获取所有set方法,然后执行,最后获得该对象实体。
* 此处细节尤为重要,因为序列化的问题,导致反射获取field时,会获取到serialVersionUID,找不到匹配的方法,所以进行下一次循环
* 所以,i=1,但是,此时找到的却是第一个需要执行set方法的field,而i=1,则取出来的是resultOfEntity.get(1),错位了,所以需要减一
* @param className
* @param resultOfEntity
* @return
*/
public Object reflectToCreateEntity(String className,ArrayList<Object> resultOfEntity){
Object o=null;
try {
Class<?> clazz=Class.forName(className);
Object entity=clazz.newInstance();
Field[] fields=clazz.getDeclaredFields();
Method[] methods=clazz.getDeclaredMethods();
for(int i=0;i<fields.length;i++){
if(!"serialVersionUID".equals(fields[i].getName().toString())){
for(int j=0;j<methods.length;j++){
if(("set"+fields[i].getName().toString()).equalsIgnoreCase(methods[j].getName().toString())){
//此处尤为重要,因为序列化的问题,导致反射获取field时,会获取到serialVersionUID,找不到匹配的方法,所以进行下一次循环
//所以,i=1,但是,此时找到的却是第一个需要执行set方法的field,而i=1,则取出来的是resultOfEntity.get(1),错位了,所以需要减一
methods[j].invoke(entity,resultOfEntity.get(i-1));
//							if("Integer".equalsIgnoreCase(fields[i].getType().toString().substring(fields[i].getType().toString().lastIndexOf(".")+1))){
//								methods[j].invoke(entity,Integer.valueOf((String)resultOfEntity.get(i-1)));
//							}
//							else{
//								methods[j].invoke(entity,String.valueOf(resultOfEntity.get(i-1)));
//							}
}
}
}

}
o=entity;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return o;
}

/**
* 这个方法通过className sql entity来实现获取sql语句中的列名以及列名的值,然后返回供PreparedStatement操作ps.setString,ps.setInt等等方法。
* 具体实现细节为:先解析sql,获取其中的列名,然后存入columnList,接着通过反射获取entity内部的所有get方法,如果与列名匹配,则获得该方法的
* 返回值和执行结果,其中方法的返回值决定ps.setString ,ps.setInt,ps.setDouble等等。
* 由于insert语句较为特殊,所以获取方法有所不同,故首先做了一个判断
* @param className
* @param sql
* @param entity
* @return
*/
public Map<String,Object> reflectForParameters(String className,String sql,Object entity){
Map<String,Object> map=new HashMap<String,Object>();
ArrayList<String> columnList=new ArrayList<String>();
ArrayList<Object> parameterList=new ArrayList<Object>();
ArrayList<String> returnTypeList=new ArrayList<String>();
if(sql.trim().startsWith("insert")){
int begin=sql.indexOf("(");
int over=sql.indexOf(")");
String columns=sql.substring(begin+1,over);
String[] array=columns.split(",");
for(int i=0;i<array.length;i++){
columnList.add(array[i]);
}
}                             //sql的分解是根据空格,所以对sql语句有要求,逗号之间要写空格
else{
String[] array=sql.split(" ");
for(int i=0;i<array.length;i++){
if(array[i].endsWith("=?")){
columnList.add(array[i].substring(0,array[i].indexOf("=?")));
}
}
}
try {
Class<?> clazz=Class.forName(className);
Method[] methods=clazz.getDeclaredMethods();
for(int i=0;i<columnList.size();i++){
for(Method m:methods){
if(("get"+columnList.get(i)).equalsIgnoreCase(m.getName())){
returnTypeList.add((m.getReturnType().toString()).substring(m.getReturnType().toString().lastIndexOf(".")+1));
parameterList.add(m.invoke(entity));
}
}
}
map.put("column", columnList);
map.put("parameter", parameterList);
map.put("returnType", returnTypeList);
return map;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息