Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

RoniZeng/RORM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

4 Commits

Repository files navigation

思想介绍 & 架构介绍

我们希望设计一个可以实现对象和 SQL 自动映射的框架,但是整体用法和设计比 Hibernate 简单,砍掉不必要的功能。

会穿插使用设计模式。

增删改:对象——>sql

查询: sql——>对象

  • 增加:将对象对应成 sql 语句,执行 sql,插入数据库中

  • 删除:根据对象主键的值,生成 sql,执行,从库中删除

  • 修改:根据对象需要修改属性的值,生成 sql,执行

  • 查询:

    • 根据结果分类
      • 多行多列:List
      • 一行多列:JavaBean
      • 一行一列:
        • 普通对象:Object
        • 数字:Number
  • 核心架构

    • Query 接口:负责查询(对外提供服务的核心类)
    • QueryFacory 类:负责根据配置信息创建 query 对象
    • TypeConvertor 接口:负责类型转换
    • TableContext 类:负责获取管理数据库所有表结构和类接管的关系,并可以根据表结构生成类结构
    • DBManager 类:根据配置信息,维持连接对象的管理(增加连接池功能)
  • 工具类

    • JDBCUtils 封装常用 JDBC 操作
    • StringUtils 封装常用字符串操作
    • JavaFileUtils 封装 Java 文件操作
    • ReflectUtils 封装常用反射操作
  • 核心 Bean,封装相关数据

    • ColumnInfo:封装表中一个字段的信息(字段类型、字段名、键类型)
    • Configuration:封装配置文件信息
    • TableInfo:封装一张表的信息
  • 针对 ORM 框架的说明

    • 配置文件:目前使用资源文件,后期复杂使用可增加 xml文件配置和注解
    • 类名由表名生成,只有首字母大写有区别,其他无区别eg:user——>User
    • Java 对象的属性由表中字段生成,完全对应
    • 目前,只支持表中只有一个主键,联合主键不支持
  1. 在 src 下建立 db.properties。

  2. 每张表只能有一个主键。不能处理多个主键的情况。

  3. po 尽量使用包装类,不要使用基本数据类型。

 /**
 * 直接执行一个DML语句
 * @param sql sql语句
 * @param params 参数
 * @return int 执行sql语句后影响记录的行数
 */
 public int executeDML(String sql, Object[] params);
 /**
 * 将一个对象存储到数据库中
 * @param obj
 */
 public void insert(Object obj);
 /**
 * 删除clazz表示类对应的表中的记录(指定主键值id的记录)
 * @param clazz 和表对应的类的Class对象
 * @param id 主键值
 */
 public void delete(Class clazz, Object id); //delete from User where id=2;
 /**
 * 删除对象在数据库中对应的记录(对象所在的类对应到表,对象的主键值对应到记录)
 * @param obj
 */
 public void delete(Object obj);
 /**
 * 更新对象对应的记录,并且只更新指定字段值
 * @param obj 所要更新的对象
 * @param fieldNames 更新的属性列表
 * @return 执行sql语句后影响记录的行数
 */
 public int update(Object obj, String[] fieldNames);
 //update User set uname=?,pwd=?
 /**
 * 查询返回多行记录,并将每行记录封装到clazz指定的类对象中
 * @param sql 查询语句
 * @param clazz 封装数据的JavaBean类的Class对象
 * @param params sql的参数
 * @return 查询到的结果
 */
 public List queryRows(String sql, Class clazz, Object[] params);//传入sql,出来对象
 /**
 * 查询返回一行记录,并将该记录封装到clazz指定的类对象中
 * @param sql 查询语句
 * @param clazz 封装数据的JavaBean类的Class对象
 * @param params sql的参数
 * @return 查询到的结果
 */
 public Object queryUniqueRow(String sql, Class clazz, Object[] params);//传入sql,出来对象
 /**
 * 查询返回一个值(一行一列),并将该值返回
 * @param sql 查询语句
 * @param params sql的参数
 * @return 查询到的结果
 */
 public Object queryValue(String sql, Object[] params);//传入sql,出来对象
 /**
 * 查询返回一个数字(count(*))(一行一列),并将该值返回
 * @param sql 查询语句
 * @param params sql的参数
 * @return 查询到的结果
 */
 public Number queryNumber(String sql, Object[] params);//传入sql,出来对象

核心增删改查

@Override
 public int executeDML(String sql, Object[] params) {
 Connection connection = DBManager.getConnection();
 int cnt = 0;
 PreparedStatement ps = null;
 try {
 ps = connection.prepareStatement(sql);
 //给sql设参
 JdbcUtils.handlerParams(ps,params);
 System.out.println(ps);
 cnt = ps.executeUpdate();
 } catch (Exception e) {
 e.printStackTrace();
 }finally {
 DBManager.close(connection,ps);
 }
 return cnt;
 }
 @Override
 public void insert(Object obj) {
 //obj-->表中 insert into 表名 (id,uname,pwd) values (?,?,?)
 Class c = obj.getClass();
 //存储sql参数对象
 List<Object> params = new ArrayList<Object>();
 TableInfo tableInfo = TableContext.poClassTableMap.get(c);
 StringBuilder sql = new StringBuilder("insert into " + tableInfo.getName() + " (");
 int countNotNullField = 0; //计算不为空的属性值
 Field[] fields = c.getDeclaredFields();//遍历所有属性
 for (Field f: fields) {
 String fieldName = f.getName(); //属性名
 Object fieldValue = ReflectUtils.invokeGet(obj,fieldName);
 if (fieldValue != null){
 countNotNullField++;
 sql.append(fieldName + ",");
 params.add(fieldValue);
 }
 }
 sql.setCharAt(sql.length()-1,')');
 sql.append(" values (");
 for (int i = 0; i < countNotNullField; i++) {
 sql.append("?,");
 }
 sql.setCharAt(sql.length()-1,')');
 System.out.println(sql.toString());
 executeDML(sql.toString(),params.toArray());
 }
 @Override
 public void delete(Class clazz, Object id) {
 //Emp.class,2-->delete from emp where id=2;
 //通过class对象找表结构TableInfo
 TableInfo tableInfo = TableContext.poClassTableMap.get(clazz);
 //获得主键
 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey();
 //
 String sql = "delete from " + tableInfo.getName()
 + " where " +
 onlyPriKey.getName() + "=?";
 executeDML(sql,new Object[]{id});
 }
 @Override
 public void delete(Object obj) {
 //获得clazz
 Class c = obj.getClass();
 TableInfo tableInfo = TableContext.poClassTableMap.get(c);
 //获得主键
 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey();
 //通过反射机制调用对应的get方法或set方法 getUser()
 Object priKeyValue = ReflectUtils.invokeGet(obj,onlyPriKey.getName());
 delete(c,priKeyValue);
 }
 @Override
 public int update(Object obj, String[] fieldNames) {
 //obj{"uname","pwd"} --> update 表名 set uname=?,pwd=? where id=?
 Class c = obj.getClass();
 //存储sql参数对象
 List<Object> params = new ArrayList<Object>();
 TableInfo tableInfo = TableContext.poClassTableMap.get(c);
 ColumnInfo priKey = tableInfo.getOnlyPriKey(); //获得唯一主键
 StringBuilder sql =
 new StringBuilder("update " + tableInfo.getName() + " set ");
 for (String fname:fieldNames) {
 Object fvalue = ReflectUtils.invokeGet(obj,fname);
 params.add(fvalue);
 sql.append(fname + "=?,");
 }
 sql.setCharAt(sql.length()-1,' ');
 sql.append("where ");
 sql.append(priKey.getName() + "=? ");
 params.add(ReflectUtils.invokeGet(obj,priKey.getName()));
 System.out.println(sql);
 return executeDML(sql.toString(),params.toArray());
 }
 @Override
 public List queryRows(String sql, Class clazz, Object[] params) {
 Connection connection = DBManager.getConnection();
 PreparedStatement ps = null;
 List<Object> rows = new ArrayList<Object>();
 ResultSet resultSet = null;
 try {
 ps = connection.prepareStatement(sql);
 JdbcUtils.handlerParams(ps, params);
 resultSet = ps.executeQuery();
 ResultSetMetaData metaData = resultSet.getMetaData();
 while (resultSet.next()) {
 Object o = clazz.newInstance();
 for (int i = 0; i < metaData.getColumnCount(); i++) {
 //得到每一列的名称
 String columnLabel = metaData.getColumnLabel(i + 1);
 Object columnValue = resultSet.getObject(i + 1);
 ReflectUtils.invokeSet(o, columnLabel, columnValue);
 }
 rows.add(o);
 }
 return rows;
 }catch (Exception e){
 e.printStackTrace();
 }finally {
 DBManager.close(connection,ps);
 }
 return null;
 }
 @Override
 public Object queryUniqueRow(String sql, Class clazz, Object[] params) {
 List list = queryRows(sql,clazz,params);
 return (list == null && list.size() > 0) ? null : list.get(0);
 }
 @Override
 public Object queryValue(String sql, Object[] params) {
 //select count(*) from user...
 Connection connection = DBManager.getConnection();
 PreparedStatement ps = null;
 ResultSet resultSet = null;
 Object o =null;
 try {
 ps = connection.prepareStatement(sql);
 JdbcUtils.handlerParams(ps,params);
 resultSet = ps.executeQuery();
 while (resultSet.next()){
 o = resultSet.getObject(1);
 }
 } catch (Exception e) {
 e.printStackTrace();
 return null;
 }finally {
 DBManager.close(connection,ps);
 }
 return o;
 }
 @Override
 public Number queryNumber(String sql, Object[] params) {
 return (Number) queryValue(sql,params);
 }

连接池(Connection Pool)

  • 就是将 Connection 对象放入 List 中,反复重用
  • 连接池的初始化
    • 实现放入多个连接对象
  • 从连接池中取连接对象
    • 如果池中有可用连接,则将池中最后一个返回。同时,将该连接从池中 remove,表示正在使用。
    • 如果池中无可用连接,则创建一个新的。
  • 关闭连接
    • 不是真正的关闭连接,而是将用完的连接放入池中。
  • 市面上的连接池产品
    • DBCP
    • c3p0
    • proxool

About

手写ORM框架 v1.0

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /