程序员

简单ORM论道

2019-03-24  本文已影响0人  _chubby

ORM定义:对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换

万物同源,始于JDBC

其他所有框架对关系数据库的操作都是基于以上步骤的封装。

基于JdbcTemplate实现简单的ORM,ORM的关注点是表跟实体的映射。那么关注点就在于
简单InsertBean实现

方法定义

/**
 * 往数据库指定的表插入一个BEAN的数据
 * @param tableName
 * @param keyId
 * @param dataBean
 * @return
 */
public Long insertBean(String tableName,String keyColumn,Object dataBean) throws DbException;

实现的模板方法

Map<String,Field> fieldMap = getClassFieldMap(bean.getClass());
List<String> fieldList = getTableFieldList(tableName);
Map<String,Object> dataMap = constructInsertMap(fieldMap, fieldList, keyColumn);
insertMap(dataMap,tableName)

insertMap(Map<String, ?> dataMap, String tableName) 具体实现

wrapInsertMap(dataMap); //对dataMap进行包装、再一次赋空值、日期处理等等
SimpleJdbcInsert insert = getSimpleJdbcInsert();    
insert.withTableName(tableName).usingColumns(getCols(dataMap));
insert.execute(insertMap);

更直白的描述

InsertBeanActivity.png

获取实体属性具体实现 getClassFieldMap(bean.getClass())

    /**
     * 取得类的属性名
     * @param clazz
     * @return
     */
    public static Map<String,Field> getClassFieldMap(Class<?> clazz){
        Map<String,Field> rtMap = null;
        if(clazz != null){
            if(null == rtMap){
                rtMap = new HashMap<String,Field>();
                Field[] fields = clazz.getDeclaredFields();
                if(fields != null && fields.length>0){
                    Field.setAccessible(fields,true);
                    Field f = null;
                    for (int j = 0; j < fields.length; j++) {
                        f = fields[j];
                        rtMap.put(f.getName().toLowerCase(), f);
                    }
                }
            }           
        }
        return rtMap;       
    }

获取表的字段具体实现(基于Oracle实现) getTableFieldList(tableName)

    public List<String> getTableFieldList(String tableName){       
        List<String> list = null;
        DbTable dbTable = getDbTableDefine(tableName);
        if(dbTable != null && dbTable.getFieldMap() != null && !dbTable.getFieldMap().isEmpty()){
            list = Arrays.asList(dbTable.getFieldMap().keySet().toArray(new String[dbTable.getFieldMap().keySet().size()]));
        }
        return list;
    }   
    
    public DbTable getDbTableDefine(String tableName){
        try {           
            return DbUtil.getDbTableDefine(tableName, this.getJdbcTemplate());
        } catch (Exception e) {         
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取Table的配置
     * @param tableName
     * @param conn
     * @return
     */
    public static DbTable getDbTableDefine(String tableName, JdbcTemplate jdbcTemplate){
        
        if(StringUtils.isEmpty(tableName)){
            return null;
        }
        WebRmInforesCacheService cacheService = SpringContextUtil.getBean("com.gpdi.infores.services.bs.WebRmInforesCacheServiceImpl");
        tableName = tableName.toUpperCase();
        DbTable dbTable = cacheService.getData("DbTable_"+tableName);
        if(dbTable == null){            
            Connection conn = null;//DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
            
            ResultSet rsTable = null;//取表
            ResultSet rsField = null;//取字段
            
            ResultSet rsKey = null;//取主键
            
            ResultSet indexInfo = null;//索引
            
            Statement stmt = null;//字段注释
            ResultSet rsRemark = null;//字段注释
            try {               
                conn = jdbcTemplate.getDataSource().getConnection();
                DatabaseMetaData dm = conn.getMetaData();
                String catalog = conn.getCatalog();
                rsTable = dm.getTables(catalog, dm.getUserName(), tableName.toUpperCase(), new String[]{"TABLE", "SYNONYM"});
                if(rsTable.next()) {
                    tableName = rsTable.getString("TABLE_NAME");
                    if(StringUtils.isNotEmpty(tableName)){
                        tableName = tableName.toUpperCase();
                        dbTable = new DbTable();
                        dbTable.setUserName(dm.getUserName());
                        dbTable.setTableName(tableName);
                        LinkedHashMap<String,DbTableField> fields = new LinkedHashMap<String,DbTableField>();
                        //取主键
                        rsKey = dm.getPrimaryKeys(catalog, null, tableName);
                        String keyField = null;
                        while (rsKey.next()) {
                            keyField = rsKey.getString("COLUMN_NAME");//组合组键时、只要最后一个主键
                        }
                        //取字段
                        rsField = dm.getColumns(catalog, null, tableName, null);
                        while (rsField.next()) {
                            DbTableField f = new DbTableField();
                            
                            String fieldName = rsField.getString("COLUMN_NAME").toUpperCase();
                            f.setName(fieldName);//参数值可参考dm.getColumns(catalog, null, tableName, null)的帮助文档
                            f.setSqlType(new Integer(rsField.getString("DATA_TYPE")).intValue());//如:java.sql.Types.INTEGER
                            f.setTypeName(rsField.getString("TYPE_NAME"));//如:BIGINT
                            f.setSize(rsField.getString("COLUMN_SIZE"));//用户定义的字段长度
                            f.setBufferLength(rsField.getString("BUFFER_LENGTH"));//字段缓冲区大小
                            f.setDecimal(rsField.getString("DECIMAL_DIGITS"));//精度
                            f.setNullable("1".equals(rsField.getString("NULLABLE")));//取值0||1,1允许空值,0不允许空值
                            f.setDefaultValue(rsField.getString("COLUMN_DEF"));//默认值
                            f.setPosition(rsField.getString("ORDINAL_POSITION"));//在表中的位置
                            f.setRemark(rsField.getString("REMARKS"));//注释为空的、下面会有专门取注释
                            
                            if(StringUtils.isNotEmpty(keyField) && keyField.equalsIgnoreCase(fieldName)){
                                f.setPrimarykey(true);
                                dbTable.setKeyField(f);//主键字段
                            }
                            fields.put(fieldName.toLowerCase(),f);
                        }
                        //字段注释
                        String remarkSQL = "select c.* from all_col_comments c where lower(c.table_name) = lower('"+tableName+"')";
                        if(StringUtils.isNotEmpty(dm.getUserName()))
                            remarkSQL += " and c.owner='"+dm.getUserName()+"'";
                        stmt = conn.createStatement();
                        rsRemark = stmt.executeQuery(remarkSQL);
                        while(rsRemark.next()){
                            String fieldNmae = rsRemark.getString("COLUMN_NAME");
                            fields.get(fieldNmae.toLowerCase()).setRemark(rsRemark.getString("COMMENTS"));
                        }
                        //表名注释
                        remarkSQL = "select c.* from all_tab_comments c where lower(c.table_name) = lower('"+tableName+"')";
                        if(StringUtils.isNotEmpty(dm.getUserName())) remarkSQL += " and c.owner='"+dm.getUserName()+"'";
                        ResultSet rstRemark = stmt.executeQuery(remarkSQL);
                        if(rstRemark.next()){
                            dbTable.setTableCnName(rstRemark.getString("COMMENTS"));
                        }
                        dbTable.setFieldMap(fields);        
                        cacheService.cacheData("DbTable_"+tableName, dbTable);
                       
                    }
                }else{
                    dbTable = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                close(rsRemark);
                close(stmt);
                close(indexInfo);
                close(rsKey);
                close(rsField);
                close(rsTable);
                close(conn);
            }
        }
            
        return dbTable;
    }
updateBean、deleteBean类似不再详述
selectBean

jdbcTemplate中实现了一个BeanPropertyRowMapper或者可以自己实现一个更加通用的RowMapper

好奇心害死猫--------------JdbcTemplate后面做了什么

几个重要的类与接口
关系------------只画出重要操作与属性
Relation.png
流程

insert.withTableName(tableName).usingColumns(getCols(dataMap))

注册需要插入的表至TableMeteDataContext、插入字段则保存至AbstractJdbcInsert的declaredColumns中

insert.execute(insertMap)

插入具体流程


InsertFlow.png

重要方法

其他一些有意思的东西

其他

上一篇 下一篇

猜你喜欢

热点阅读