深入Java日记——自己写一个ORM框架(2)
来源:互联网 发布:js代码死机 编辑:程序博客网 时间:2024/04/28 05:11
上一篇深入Java日记——自己写一个ORM框架(1)中提到了如何将数据库的表生成对象的JavaBean,这篇博客就讲一下如何利用JavaBean增删改查,主要行为是拼接sql语句
1.增
首先要写一个最基础的执行sql语句的方法
我们使用的PreparedStatement来执行,添加参数可以通过一个工具类来实现
public class JDBCUtils { public static void handleParams(PreparedStatement ps,Object[]params){ if (params!=null){ for (int i=0;i<params.length;i++){ try { //参数是从1开始 ps.setObject(i+1,params[i]); } catch (SQLException e) { e.printStackTrace(); } } } }}
执行sql语句方法的主体
public int executeDML(String sql,Object[] params){ Connection connection=DBManager.getConn(); int count=0; PreparedStatement ps=null; try { ps=connection.prepareStatement(sql); JDBCUtils.handleParams(ps,params); count=ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBManager.close(ps,connection); } return count; }
数据库的名字和字段的名字都是采用下划线分割法,但字段名是采用小驼峰,所以要进行一次转换
public static String camel2Underline(String line){ StringBuilder result = new StringBuilder(); if (line != null && line.length() > 0) { // 将第一个字符处理成小写 result.append(line.substring(0, 1).toLowerCase()); // 循环处理其余字符 for (int i = 1; i < line.length(); i++) { String s = line.substring(i, i + 1); // 在大写字母前添加下划线 if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) { result.append("_"); } // 其他字符直接转成大写 result.append(s.toLowerCase()); } } return result.toString(); }
插入时获取属性值主要通过反射来进行
public static Object getFieldValue(String field,Object obj){ Class clazz=obj.getClass(); Field idField= null; Object id=null; try { idField = clazz.getDeclaredField(field); idField.setAccessible(true); id=idField.get(obj); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return id; }
插入方法的主要步骤是:拼接前置sql语句,转换和拼接属性名,拼接后置sql语句
/** * 插入对象到数据库,拼接的sql如 insert into users(id,name) values(?,?) * @param obj 要储存的数据 */ public void insert(Object obj){ Class clazz = obj.getClass(); //通过Class获取TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); //拼接前置sql StringBuilder stringBuilder=new StringBuilder("insert into " + tableInfo.getTname() + "("); Field[]fields=clazz.getDeclaredFields(); Object[] fieldValue=new Object[fields.length]; //遍历所有属性,获取他们在要插入对象的值 for (int i=0;i<fields.length;i++){ Field field=fields[i]; fieldValue[i]=ReflectUtils.getFieldValue(field.getName(),obj); stringBuilder.append(StringUtils.camel2Underline(field.getName())+","); } //删除最后一个逗号 stringBuilder.delete(stringBuilder.length()-1,stringBuilder.length()); //拼接后置sql stringBuilder.append(")"); stringBuilder.append(" values("); for (int i=0;i<fields.length;i++){ stringBuilder.append("?,"); } stringBuilder.delete(stringBuilder.length()-1,stringBuilder.length()); stringBuilder.append(")"); String sql = stringBuilder.toString(); System.out.println(sql); executeDML(sql, fieldValue); }
2.删
删除我们采用两种方式,第一种是通过类和主键,另一种是通过对象实例删除
通过类和主键删除
public void delete(Class clazz,Object id){ //通过Class获取TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); //获得主键 ColumnInfo columnInfo = tableInfo.getOnlyPriKey(); String sql = "delete from " + tableInfo.getTname() + " where " + columnInfo.getName() + " =?"; executeDML(sql, new Object[]{id}); }
通过对象实例删除
public void delete(Object obj){ Class clazz = obj.getClass(); //通过Class获取TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); //获得主键 ColumnInfo columnInfo = tableInfo.getOnlyPriKey(); String sql = "delete from " + tableInfo.getTname() + " where " + columnInfo.getName() + " =?"; //通过反射获取主键 Object id = ReflectUtils.getFieldValue(StringUtils.underlineToSmallCamel(columnInfo.getName()), obj); executeDML(sql, new Object[]{id}); }
3.改
改的sql拼接方式有点类似插入
/** * 只更新指定字段 拼接的sql如 update users set name = ? where id = ? * @param obj 所要更新的对象 * @param fieldNames 要更新的字段名 * @return 执行sql语句后影响的行数 */ public int update(Object obj,String[] fieldNames){ Class clazz = obj.getClass(); //通过Class获取TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); //获得主键 ColumnInfo columnInfo = tableInfo.getOnlyPriKey(); List<Object> params=new ArrayList<>(); StringBuilder stringBuilder=new StringBuilder(); //拼接前置sql语句 stringBuilder.append("update " + tableInfo.getTname()+" set "); //遍历要修改的属性,获取他们在要插入对象的值 for (String field:fieldNames){ stringBuilder.append(StringUtils.camel2Underline(field)+" = ?"); params.add(ReflectUtils.getFieldValue(field,obj)); stringBuilder.append(","); } //删除最后一个逗号 stringBuilder.delete(stringBuilder.length()-1,stringBuilder.length()); //拼接后置sql stringBuilder.append(" where "+tableInfo.getOnlyPriKey().getName()+"=?"); String sql = stringBuilder.toString(); //通过反射获取主键 Object id = ReflectUtils.getFieldValue(StringUtils.underlineToSmallCamel(columnInfo.getName()), obj); if (id==null){ return 0; } System.out.println(sql); params.add(id); return executeDML(sql, params.toArray()); }
4.查
查的话有三种查询,第一种是查询多行记录,第二种是查询某个记录,第三种是查询某个值
查询的时候要将记录转换为对应JavaBean的List,需要用到JavaBean的set方法,我们可以通过反射来进行
public static void invokeSet(String field,Object value,Object obj){ Class clazz=obj.getClass(); try { Method method=clazz.getDeclaredMethod("set"+StringUtils.underlineToBigCamel(field),value.getClass()); method.invoke(obj,value); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
查询多行记录
/** * 返回多行记录,并将每行记录封装到指定的类中 * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 查询到的结果 */ public List queryRow(final String sql,final Class clazz,final Object[] params){ Connection connection=DBManager.getConn(); ResultSet resultSet=null; try { PreparedStatement ps=connection.prepareStatement(sql); JDBCUtils.handleParams(ps,params); resultSet=ps.executeQuery(); List result=new ArrayList(); ResultSetMetaData resultSetMetaData= null; try { resultSetMetaData = resultSet.getMetaData(); while (resultSet.next()){ Object rowObj=clazz.newInstance(); //获得遍历该行的字段,并将其赋值给对象 for(int i=0;i<resultSetMetaData.getColumnCount();i++){ //获取字段名 String columnName=resultSetMetaData.getColumnLabel(i+1); //获取字段属性 Object columnValue=resultSet.getObject(i+1); //赋值 ReflectUtils.invokeSet(columnName,columnValue,rowObj); } result.add(rowObj); } } catch (SQLException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); }finally { DBManager.close(preparedStatement,connection); } return result; } catch (SQLException e) { e.printStackTrace(); return null; } }
查询某个记录
/** * 返回一行记录,并将一行记录封装到指定的类中 * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 查询到的结果 */ public Object queryUniqueRow(String sql,Class clazz,Object[] params){ List result=queryRow(sql,clazz,params); if (result!=null&&result.size()>0){ return result.get(0); } return null; }
查询某个值
/** * 返回一个值(一行一列) * @param sql 查询语句 * @param params sql的参数 * @return 查询到的结果 */ public Object queryValue(String sql,Object[] params){ Connection connection=DBManager.getConn(); ResultSet resultSet=null; try { PreparedStatement ps=connection.prepareStatement(sql); JDBCUtils.handleParams(ps,params); resultSet=ps.executeQuery(); try { while (resultSet.next()){ //只返回第一条记录的第一个字段的值 return resultSet.getObject(1); } } catch (SQLException e) { e.printStackTrace(); }finally { DBManager.close(preparedStatement,connection); } return null; } }
以上是核心代码,之后我们还可以自定义一个连接池和自定义Query对象的工厂来适配不同数据库,这部分的代码留给你们去实现
阅读全文
0 0
- 深入Java日记——自己写一个ORM框架(2)
- 深入Java日记——自己写一个ORM框架(1)
- 自己写ORM框架 DBUtils
- 自已动手写ORM框架(2)——学前班
- 自己动手写ORM框架-java
- 自已动手写ORM框架(1)——幼儿园
- 自己写一个框架
- 如何写一个给自己的框架写一个优雅的Java Config模块(一)
- 如何写一个给自己的框架写一个优雅的Java Config模块(二)
- 如何写一个给自己的框架写一个优雅的Java Config模块(三)
- 如何写一个给自己的框架写一个优雅的Java Config模块(四)
- 如何写一个给自己的框架写一个优雅的Java Config模块(五)
- 自己写一个MVC框架(一)
- 自己写一个MVC框架(二)
- 自己写一个MVC框架(三)
- 【Java进阶】实现自己的ORM框架
- 一个java框架的开发日记(2)
- 自己写的三个框架,关于IOC,WEB,ORM
- webpack打包,配置路径
- codeforces 771a 完全图+并查集判连通块中的点数和边数
- 欢迎使用CSDN-markdown编辑器
- zTree插件之多选下拉菜单代码
- Java学习笔记之Pattern类的用法详解(正则表达式)
- 深入Java日记——自己写一个ORM框架(2)
- 线性数据结构--顺序表
- poj dfs相关之3984 迷宫问题
- 层次思想----C Programming Tutorial 4th Edition (K&R version)
- PHP mysqli 操作数据库
- C++如何只能在堆上或栈上生成对象
- 用python将%格式化字符串转换成xliff格式
- 012 提供Https支持(2017.06.22更新)
- ajax实现用户登录注册和退出