一个基于注解的orm简单实现(二):实现思路

先来看一段常见的数据库操作代码:

    protected User getDataFromDatabase(long id){
        String sql = "select firstname from user where id=?";//1
        Connection conn = DBConnectionFactory.getConnection();
        PreparedStatement stat;
        User user;//2
        try {
            stat = conn.prepareStatement(sql);
            stat.setObject(1, id);
            ResultSet rs = stat.executeQuery();
            user.setFirstName(rs.getString("firstname"));//3
            stat.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return user;
    }

在上面代码中存在三个可变部分,如果需要把数据库操作代码修改为任何对象都能使用的同一段代码,则需要提取出这三个可变部分。所以我们修改一下上面代码。
1、首先提取一下sql语句部分。如果我们可以动态生成该sql语句,数据库对象映射器应该就完成了一半。所以我们先来拆解sql语句,看看下面这段代码:

        String selectList="firstname";
        String whereClause="id=?";
        String tableName = "user";
        String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
        protected User getDataFromDatabase(String sql,long id){
        //String sql = "select firstname from user where id=?";//1
        Connection conn = DBConnectionFactory.getConnection();
        PreparedStatement stat;
        User user;//2
        try {
            stat = conn.prepareStatement(sql);
            stat.setObject(1, id);
            ResultSet rs = stat.executeQuery();
            user.setFirstName(rs.getString("firstname"));//3
            stat.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return user;
    }

拆解了第一部分,现在看起来好像也感觉差别不大,仅仅是把sql当作参数传递进去。关于第二第三可变部分,我们再来看看下面这段代码:

    String selectList="firstname";
    String whereClause="id=?";
    String tableName = "user";
    String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
    Class klass = User.class;
    String fieldName = "firstName";
    String columnName = "firstname";
    Field field = klass.getDeclaredField(fieldName);
    protected Object getDataFromDatabase(String sql,Object id){
        //String sql = "select id,firstname from user where id=?";//1
        Connection conn = DBConnectionFactory.getConnection();
        PreparedStatement stat;
        Object user;//2
        try {
            stat = conn.prepareStatement(sql);
            stat.setObject(1, id);
            ResultSet rs = stat.executeQuery();
            user = klass.newInstance();
            field.set(user,rs.getObject(columnName));
            //user.setFirstName(rs.getString("firstname"));//3
            stat.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return user;
    }

现在再重新看函数体内,与特定user对象的信息,好像没有了,当然这里为了简化问题,user对象只有一个firstname,后面会看到有多个变量时,仅仅是field.set()那里变成了一个for循环。然后我们再来优化一下代码,毕竟所有代码堆在一个地方乱七八糟,非常不容易理解。而且如果代码仅仅是这样的话,也没有任何的可重用性。我们先把函数体提取到BaseMapper.class。把其他可变的部分,提取到TableMap.class和OneToOneColumnMap.class。TableMap存储对象与数据库表映射信息,OneToOneColumnMap存储对象field与表列的映射信息。每一个对象都会有一个BaseMapper实例,存储各自的对象关系映射信息。代码如下:

class BassMapper{
     protected TableMap<T> tableMap;
     public Object getDataFromDatabase(String sql,Object... param){
        Connection conn = DBConnectionFactory.getConnection();
        PreparedStatement stat;
        Object result = null;
        try {
            stat = conn.prepareStatement(sql);
            for(int i = 0;i < param.length;i++){
                stat.setObject(i + 1, param[i]);
            }
            ResultSet rs = stat.executeQuery();
            if(rs.next()){
                result = (T) tableMap.getKlass().newInstance();
                for(Iterator<OneToOneColumnMap> it = tableMap.getOneToOneColumns();it.hasNext();){
                    OneToOneColumnMap columnMap = it.next();
                    Object columnValue = rs.getObject(columnMap.getColumnName());
                    columnMap.setField(result, columnValue);
                }
            }
            stat.close();
        } catch (SQLException | InstantiationException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return result;
    }
}
class OneToOneColumnMap{
    private String columnName;
    private String fieldName;
    protected Field field;
    private TableMap dataMap;

    public OneToOneColumnMap(String columnName,String fieldName,TableMap dataMap){
        this.columnName = columnName;
        this.fieldName = fieldName;
        this.dataMap = dataMap;
        initField();
    }

    public String getColumnName(){
        return this.columnName;
    }

    public String getFieldName(){
        return this.fieldName;
    }

    public Object getValue(Object subject){
        try {
            return field.get(subject);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public void setField(Object result,Object columnValue){
        try {
            field.set(result, columnValue);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected void initField(){
        try {
            this.field = dataMap.getKlass().getDeclaredField(getFieldName());
            field.setAccessible(true);
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
class TableMap{
    private Class<T> domainClass;
    private String tableName;
    private OneToOneColumnMap primaryKeyColumn;  
    private List<OneToOneColumnMap> oneToOneColumnMaps = new ArrayList<OneToOneColumnMap>();

    public TableMap(String tableName,Class<T> domainClass){
        this.domainClass = domainClass;
        this.tableName = tableName;
    }
    public void addOneToOneColumn(String columnName,String fieldName){
        OneToOneColumnMap columnMap = new OneToOneColumnMap(columnName,fieldName,this);
        if(!oneToOneColumnMaps.contains(columnMap)){
            if(primaryKeyColumn == null){
                primaryKeyColumn = columnMap;
            }
            oneToOneColumnMaps.add(columnMap);
        }
    }

    public void setPrimaryKeyColumn(String columnName, String fieldName){
        this.primaryKeyColumn = new OneToOneColumnMap(columnName,fieldName,this);
        if(!oneToOneColumnMaps.contains(primaryKeyColumn)){
            oneToOneColumnMaps.add(primaryKeyColumn);
        }
    }

    public String primaryKeyWhereClause(){
        return primaryKeyColumn.getColumnName() + " = ? ";
    }

    public Object primaryKeyColumnName(){
        return primaryKeyColumn.getColumnName();
    }

    public Object primaryKeyValue(Object domainObject){
        return primaryKeyColumn.getValue(domainObject);
    }

    public String getTableName(){
        return this.tableName;
    }

    public String insertList(){
        StringBuffer result = new StringBuffer("?");
        for(int i = 0;i < oneToOneColumnMaps.size() - 1;i++){
            result.append(",");
            result.append("?");
        }
        return result.toString();
    }

    public String columnList(){
        StringBuffer result = new StringBuffer(" ");
        for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
            OneToOneColumnMap columnMap = it.next();
            result.append(columnMap.getColumnName());
            result.append(",");
        }
        result.setLength(result.length() - 1);
        return result.toString();
    }

    public String updateList(){
        StringBuffer result = new StringBuffer(" SET ");
        for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
            OneToOneColumnMap column = it.next();
            result.append(column.getColumnName());
            result.append("=?,");
        }
        result.setLength(result.length() - 1);
        return result.toString();
    }

    public String getColumnForField(String fieldName){
        for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
            OneToOneColumnMap columnMap = it.next();
            if(columnMap.getFieldName().equals(fieldName)){
                return columnMap.getColumnName();
            }
        }
        return null;
    }
}

BaseMapper通过一个TableMap来初始化,依赖关系如下:
这里写图片描述
项目代码:https://github.com/hu-xuemin/xBlog.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值