轻量级DAO层实践初体验

 1. 观念 JDBC 完毕进程

MyBatis 1

 

  • 任凭你项目中选用的是何许的 ORM
    框架[Hibernate/MyBatis…..],或然是今日大热的小圈子模型 DSL
    DAO层,都是在古板 JDBC的底蕴上拓展的包裹。
  • 骚年一经你上手就是 DAO
    层框架,没有见过上述的多少个东西的话,建议你反编译
    JDK去和他们打个招呼。
  • MyBatis,价值观 JDBC
    完成获取数据库数据的代码(随上图系列图)

            //getConnection
            String url = "jdbc:mysql://localhost/db_school?useUnicode=true&characterEncoding=UTF-8";
            String userName = "root";
            String pwd = "123456";
            Connection conn = DriverManager.getConnection(url, userName, pwd);
    
            //创建 createStatement/prepareStatement
            String sqlStatement = "select * from tmp_services where uuid ='c9ea709cb30d4954a33dfec01d3ef142'";
            Statement statement = conn.createStatement();
    
            String sqlPrepared = "select * from tmp_services where uuid = ?";
            PreparedStatement preparedStatement = conn.prepareStatement(sqlPrepared);
            preparedStatement.setString(1, "c9ea709cb30d4954a33dfec01d3ef142");
    
            //executeQuery
            ResultSet resultSetStatement = statement.executeQuery(sqlStatement);
            ResultSet resultSetPrepared = preparedStatement.executeQuery();
    
            //遍历结果
            while (resultSetPrepared.next()) {
                System.out.println("on:" + resultSetPrepared.getRow());
                System.out.println("uuid:" + resultSetPrepared.getString("uuid") + ",name:" + resultSetPrepared.getString("name"));
            }
    
  • PreparedStatement/Statement
    提供的三种不一致的运行 执行Sql 事物对象。

  • PreparedStatement 为预编译
    Sql,执行前早已被编译,DBMS 只需实践即可,那就意味着那 那种样式的 Sql
    语句执行功能至极高。
  • Statement
     为履行时才会进展编译Sql,然后被 DBMS 执行,所以那些目的在履行 Sql
    不是很频仍时,相对科学。
  • PreparedStatement
    功效高,还足以有效的防护 Sql
    注入,但会占用多余的内存空间(用于预编译)。
  • 就就像是胸大,臀完美的四姐,脸不狼狈,你必要就义局部东西,去换取别的一些事物,没有断然完美的拔取。

      近日快被 Hibernate
给坑哭了,有了和睦出手达成 ORM 映射 DAO 的扼腕。

     
工作之余折腾了快一星期,总算是有点小成就。

     
现打算将经过记录下来,方便自身一连回看填补遗漏。

 2. 基于表明的 ORM 实践

      JDBC
访问数据库的法子是最飞速的,没有之一,好比是高级编程语言的频率永远不容许超越底层汇编语言是一样的道理。

      不过 JDBC
对于程序员来说太难明白了,不可能将关全面据库中的数据抽象到
Java的面向对象的世界。

     
上边是自个儿业余时间在物色出来的不依靠任何框架,只利用 JDK自带的诠释和反光的
DAO 层达成,

     
其中还有为数不少的难点,不过大体的样子已经很可喜了。

      a.定义你自身的 DAO 表名申明

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
public @interface TableName {
    String value();
}

     b.在 POJO (与数量库表结构对应)
中是增进 TableName 评释

@TableName("tmp_services")
public class Service extends BaseVO<Service>{
    private String id;
    private String name;
    private String theme;
    private String type;
    private String descrition;
    private String XSD;
    private String remark;
   ..........
}

    d.获取注脚表名、社团 Sql
、调整姿势

    public <T> List<T> find(Class<T> clazz, Map param, Connection connection) throws DataOptException {
        TableName tableName = clazz.getAnnotation(TableName.class);
        if (tableName == null) {
            throw new DataOptException("A1-308", "没有找到类[" + clazz.getName() + "]所映射的表!");
        } else {
            String sql = "SELECT * FROM " + tableName.value() + " WHERE 1=1 ";
            ArrayList paras = new ArrayList();

            if (param != null) {
                Iterator<Map.Entry<String, Object>> iterator = param.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, Object> entry = iterator.next();
                    sql = sql + " AND " + entry.getKey() + " = ?";
                    paras.add(entry.getValue());
                }
            }
            return this.select(connection, sql, paras, clazz);
        }
    }

    e.熟习的JDBC
操作、获取查询结果集、反射填充POJO属性

public <T> List<T> select(Connection connection, String sql, List<Object> paras, Class<T> clazz) throws DataOptException {
        ArrayList retList = new ArrayList();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            Object bean;
            Iterator iterator;
            if (paras != null) {
                int count = 1;
                iterator = paras.iterator();

                while (iterator.hasNext()) {
                    bean = iterator.next();
                    preparedStatement.setObject(count++, bean);
                }
            }

            ResultSet resultSet = preparedStatement.executeQuery();

            String fname;
            Object value;
            List fields = getCanWriteField(clazz);
            Iterator filedIter = fields.iterator();

            Field field;
            while (filedIter.hasNext()) {
                field = (Field) filedIter.next();
                field.setAccessible(true); //抑制java 对修饰符的检查
            }

            HashSet hashSet = new HashSet();
            ResultSetMetaData metaData = resultSet.getMetaData();

            int i;
            for (i = 1; i <= metaData.getColumnCount(); ++i) {
                hashSet.add(metaData.getColumnLabel(i).toLowerCase());
            }

            for (i = fields.size() - 1; i >= 0; --i) {
                if (!hashSet.contains(((Field) fields.get(i)).getName().toLowerCase())) {
                    fields.remove(i);
                }
            }

            for (; resultSet.next(); retList.add(bean)) {
                bean = clazz.newInstance();
                filedIter = fields.iterator();

                while (filedIter.hasNext()) {
                    field = (Field) filedIter.next();
                    fname = field.getName();
                    if (ClassUtils.isAssignable(field.getType(), Date.class)) {
                        Timestamp timestamp = resultSet.getTimestamp(fname);
                        if (timestamp != null) {
                            field.set(bean, timestamp);
                        }
                        continue;
                    }

                    value = resultSet.getObject(fname);
                    if (value != null) {
                        try {
                            field.set(bean, reflect(field.getType(), value));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (Throwable e) {
            throw new DataOptException("A1-001", e.getMessage(), e);
        } finally {
            this.closeConnection(connection);
        }
        return retList;
    }

    f.  将 ResultSet 获取的值 转换 POJO
属性时,判断逻辑稍微多一些,基本概括了主流的 java 基本类型…

MyBatis 2MyBatis 3

 public static Object changeType(Class propType, Object tmpobj) throws ParseException {
        if (propType.isInstance(tmpobj)) {
            return tmpobj;
        } else {
            String value = toString(tmpobj, "").trim();
            if (propType.equals(Date.class)) {
                return value.length() == 0 ? null : (value.length() == 8 ? Keys.df3.parse(value) : (NumberUtils.isNumber(value) ? new Date(Long.parseLong(value) * 86400000L + Keys.df4.parse("1900-01-01").getTime()) : (value.length() == 10 ? Keys.df4.parse(value) : (value.length() <= 16 ? Keys.df5.parse(value) : Keys.df7.parse(value)))));
            } else if (propType.equals(java.sql.Date.class)) {
                return value.length() == 0 ? null : (value.length() == 8 ? new java.sql.Date(Keys.df3.parse(value).getTime()) : (NumberUtils.isNumber(value) ? new java.sql.Date(Long.parseLong(value) * 86400000L + Keys.df4.parse("1900-01-01").getTime()) : (value.length() <= 10 ? new java.sql.Date(Keys.df4.parse(value).getTime()) : new java.sql.Date(Keys.df4.parse(value.substring(0, 10)).getTime()))));
            } else if (propType.equals(Timestamp.class)) {
                return value.length() == 0 ? null : (value.length() == 8 ? new Timestamp(Keys.df3.parse(value).getTime()) : (NumberUtils.isNumber(value) ? new Timestamp(Long.parseLong(value) * 86400000L + Keys.df4.parse("1900-01-01").getTime()) : (value.length() <= 10 ? new Timestamp(Keys.df4.parse(value).getTime()) : (value.length() <= 16 ? new Timestamp(Keys.df5.parse(value).getTime()) : new Timestamp(Keys.df7.parse(value).getTime())))));
            } else if (propType.equals(Calendar.class)) {
                Date pd = (Date) changeCast(Date.class, tmpobj);
                if (pd != null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(pd);
                    return cal;
                } else {
                    return null;
                }
            } else if (propType.equals(String.class)) {
                return value;
            } else if (!propType.equals(Character.class) && !propType.equals(Character.TYPE)) {
                if (!propType.equals(Byte.class) && !propType.equals(Byte.TYPE)) {
                    if (!propType.equals(Short.class) && !propType.equals(Short.TYPE)) {
                        if (!propType.equals(Integer.class) && !propType.equals(Integer.TYPE)) {
                            if (!propType.equals(Long.class) && !propType.equals(Long.TYPE)) {
                                if (!propType.equals(Float.class) && !propType.equals(Float.TYPE)) {
                                    if (!propType.equals(Double.class) && !propType.equals(Double.TYPE)) {
                                        if (!propType.equals(Boolean.class) && !propType.equals(Boolean.TYPE)) {
                                            System.out.println("无法转换为内部表示 \'" + propType.getName() + "\' 对象不可用");
                                            return tmpobj;
                                        } else {
                                            return Boolean.valueOf(value.trim().length() == 0 ? false : (new Boolean(value)).booleanValue());
                                        }
                                    } else {
                                        return Double.valueOf("NaN".equals(value) ? 0.0D : (value.trim().length() == 0 ? 0.0D : (new Double(value)).doubleValue()));
                                    }
                                } else {
                                    return Float.valueOf("NaN".equals(value) ? 0.0F : (value.trim().length() == 0 ? 0.0F : (new Float(value)).floatValue()));
                                }
                            } else {
                                return value.length() == 0 ? Long.valueOf(0L) : Long.valueOf("NaN".equals(value) ? 0L : (value.contains(".") ? new Long(value.split("\\.")[0]) : new Long(value)).longValue());
                            }
                        } else {
                            return value.length() > 0 ? Integer.valueOf("NaN".equals(value) ? 0 : (value.contains(".") ? new Integer(value.split("\\.")[0]) : new Integer(value)).intValue()) : Integer.valueOf(0);
                        }
                    } else {
                        return Short.valueOf(value.length() > 0 ? (new Short(value)).shortValue() : 0);
                    }
                } else {
                    return new Byte(value);
                }
            } else {
                return Character.valueOf(value.length() > 0 ? (new Character(value.charAt(0))).charValue() : '\u0000');
            }
        }
    }

View Code

   d.项目中的使用格局

            Map<String,Object> map = new HashMap<>();
            map.put("uuid","c9ea709cb30d4954a33dfec01d3ef142");
            List<Service> serviceList = selecter.find(EjbService.class, map, connection);

       PO、Map 作为参数,使用格局是否很简单吗?

       只是对查询进行了的包装,后续要求关心下更新和插入、与Spring 的
整合、数据连接池的整合….

  

网站地图xml地图