作者:Vinkn 来自http://www.cnblogs.com/Vinkn/

一、简介

  框架就是一组可重用的构件,LZ自己写的姑且就叫微型小框架:lfdb。LZ也对其他的ORM框架没有什么了解,现在只会一个Hibernate,还是勉强会,什么懒加载,什么二级缓存这些太高级了,平时也没用到,但是用了就要明白个所以然,自己揣摩着模仿写个小框架,但是没有研究过Hibernate是怎么写的,也不清楚系统的架构,凭借自己的感觉写的,很多地方理解上有错,很多代码写得也很垃圾,还没很多东西没有考虑到,比如当个表的映射关系,数据库外键的关联等等。希望各位大神给与一点点指点。

二、结构

1、Configuration:配置文件类,加载并解析配置文件,生成实例化的SessionFactory。

2、SessionFactory:接口,加载数据库驱动,生成Session放入SessionPool(池)中,提供Session。

  >>具体实现:SessionFactoryImpl

3、Session:接口,提供事务管理,包含对象的增删改查,以及sql执行。

  >>具体实现:SessionImpl

4、SQLBuilder:接口,创建增删改差的sql语句。可以针对不同的数据库设计不同的实现。

  >>具体实现:Mysql SQLBuilder

三、使用

一个东西,要想明白他的原理,必须先要知道怎么使用:

  1. 创建Configuration对象:构造时加载配置文件。
  2. 使用Configuration对象创建一个SessionFactory对象:configuration.buildSessionFactory()。
  3. 获取Session。
  4. 使用session执行操作。
  5. 关闭session。

代码如下:

 public static void main(String[] args) {
         //生成配置对象
         Configuration configuration=new Configuration("dbtest/test/config.xml");
         //生成Session工厂
         SessionFactory sessionFactory=configuration.buildSessionFactory();
         //获取Session
         Session session=sessionFactory.getSession();
         Student student=new Student();
         student.setSex("男");
         student.setSname("德玛西亚");
         student.setCollege("超神学院");
         student.setSno("1212121");
         //执行事务
         session.add(student);
         //关闭Session
         session.colse();
     }

四、实现

1、  Configuration类实现

 /**
  * Configuration:参数配置类
  *
  * @author ZWQ
  * @version 1.0
  *          <p>
  *          通过该类使用配置文件建立SessionFactory。
  *          </p>
  * **/
 public class Configuration {
     //数据库驱动
     private String driver = "";
     //连接url
     private String url = "";
     //用户名
     private String user = "";
     //密码
     private String password = "";
     //Session池初始大小
     private int initsize = 5;
     //Session池最大大小
     private int maxsize = 10;

     /**
      * 默认构造方法,使用项目根目录src下面的lfdb.config.xml文件
      */
     public Configuration() {
         initConfig("lfdb.config.xml");
     }

     /**
      * 带参构造方法,使用项目自定义的.xml文件
      * <p>
      * 根目录下使用为Configuration configuration=new Configuration("config.xml");
      * </p>
      * <p>
      * 具体包下面使用为Configuration configuration=new Configuration("demo/config.xml");
      * </p>
      *
      * @param configFile
      *            :String 需要使用的lfdb配置文件
      */
     public Configuration(String configFile) {
         initConfig(configFile);
     }

     private void initConfig(String configFile) {
         try {
             // 获取配置文件输入流
             InputStream configInputStream = getClass().getClassLoader().getResourceAsStream(configFile);
             if (configInputStream == null) {
                 System.out.println(">>>>>>>配置文件未找到");
                 new FileNotFoundException();
             }
             // XML文件解析
             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
             dbf.setIgnoringComments(true);
             dbf.setIgnoringElementContentWhitespace(true);
             DocumentBuilder db = dbf.newDocumentBuilder();
             System.out.println(">>>>>>>解析配置文件...");
             Document document = db.parse(configInputStream);
             Element root = document.getDocumentElement();
             NodeList config = root.getChildNodes();
             // 读取配置参数内容
             for (int i = 0; i < config.getLength(); i++) {
                 Node node = config.item(i);
                 String nodeName = node.getNodeName();
                 if (nodeName.equalsIgnoreCase("driver")) {
                     driver = node.getFirstChild().getNodeValue().trim();
                 } else if (nodeName.equalsIgnoreCase("url")) {
                     url = node.getFirstChild().getNodeValue().trim();
                 } else if (nodeName.equalsIgnoreCase("user")) {
                     user = node.getFirstChild().getNodeValue().trim();
                 } else if (nodeName.equalsIgnoreCase("password")) {
                     password = node.getFirstChild().getNodeValue().trim();
                 } else if (nodeName.equalsIgnoreCase("initsize")) {
                     initsize = Integer.parseInt(node.getFirstChild().getNodeValue().trim());
                 } else if (nodeName.equalsIgnoreCase("maxsize")) {
                     maxsize = Integer.parseInt(node.getFirstChild().getNodeValue().trim());
                 }
             }
             System.out.println(">>>>>>>配置文件解析完成");
         } catch (Exception e) {
             e.printStackTrace();
             new RuntimeException();
         }
     }

     /**
      * 建立一个SessionFactory
      *
      * @return SessionFactory 返回一个SessionFactory的实例
      * **/
     public SessionFactory buildSessionFactory() {
         return new SessionFactoryImpl(this);
     }

2、  SessionFactoryImpl类实现

 public class SessionFactoryImpl implements SessionFactory {
     // Session池
     LinkedList<Session> sessionPool = new LinkedList<Session>();
     // 与Configuration中参数相对应
     private String driver;
     private String url;
     private String user;
     private String password;
     private int initsize;
     private int maxsize;
     // 当前Session池最大大小
     private int currentsize;

     // 通过Configuration构造,并加载驱动,初始化Session池
     public SessionFactoryImpl(Configuration configuration) {
         driver = configuration.getDriver();
         url = configuration.getUrl();
         user = configuration.getUser();
         password = configuration.getPassword();
         initsize = configuration.getInitsize();
         maxsize = configuration.getMaxsize();
         loadDriver();
         for (int i = 0; i < initsize; i++) {
             createSession();
         }
     }

     // 创建Session,放入Session池
     private void createSession() {
         if (currentsize < maxsize) {
             try {
                 Connection connection = DriverManager.getConnection(url, user, password);
                 //当前只支持MySql语句的生成
                 SQLBuilder sqlBuilder = new MysqlSQLBuilder();
                 sessionPool.addLast(new SessionImpl(connection, sqlBuilder, sessionPool));
                 currentsize++;
             } catch (Exception e) {
                 System.out.println(">>>>>>>创建Session出错");
                 e.printStackTrace();
             }

         } else {
             System.out.println(">>>>>>>已超出Session配置最大容量");
         }
     }

     // 加载数据库驱动
     private void loadDriver() {
         System.out.println(">>>>>>>加载数据库驱动...");
         try {
             // 加载数据库驱动.
             Class.forName(driver);
             System.out.println(">>>>>>>加载数据库驱动成功...");
         } catch (ClassNotFoundException e) {
             System.out.println(">>>>>>>加载数据库驱动失败...");
             e.printStackTrace();
             new RuntimeException();
         }
     }

     @Override
     public Session getSession() {
         synchronized (sessionPool) {
             if (this.sessionPool.size() > 0) {
                 return this.sessionPool.removeFirst();
             } else {
                 createSession();
                 if (this.sessionPool.size() > 0) {
                     return this.sessionPool.removeFirst();
                 } else {
                     System.out.println(">>>>>>>>已经没有session");
                     return null;
                 }
             }
         }
     }

     @Override
     public void closeSession(Session session) {
         sessionPool.addLast(session);
         session=null;
     }
 }

3、  SessionImpl类实现:部分代码

     @Override
     public void add(Object object) {
         try {
             String sql = sqlBuilder.createAddSQL(object);
             Statement statement = connection.createStatement();
             statement.executeUpdate(sql);
         } catch (Exception e) {
             System.out.println(">>>>>>>>添加对象失败");
             e.printStackTrace();
         }
     }
   @Override
     public <T> List<T> get(Class<T> clazz, String sql) {
         List<T> result = null;
         try {
             Statement statement = connection.createStatement();
             ResultSet rs = statement.executeQuery(sql);
             BasicRowProcessor basicRowProcessor = new BasicRowProcessor();
             result = basicRowProcessor.toBeanList(rs, clazz);
         } catch (SQLException e) {
             System.out.println(">>>>>>>获取结果出错");
             e.printStackTrace();
         }
         return result;
     }

4、  MysqlSQLBuilder类实现:部分代码

 @Override
     public String createAddSQL(Object object) {
         StringBuilder sql = new StringBuilder();
         StringBuilder columns = new StringBuilder();
         StringBuilder values = new StringBuilder();
         sql.append("insert into ");
         sql.append(object.getClass().getSimpleName());

         try {
             Field[] fields = object.getClass().getDeclaredFields();
             boolean firststate = false;
             for (Field field : fields) {
                 field.setAccessible(true);
                 if (field.getName().toString().toLowerCase().equals("id")) {
                     continue;
                 }
                 if (firststate) {
                     columns.append(",");
                     values.append(",");

                 } else {
                     firststate = true;
                 }
                 String column = field.getName();
                 Object value = field.get(object);
                 columns.append(column);
                 if (field.getType() == String.class) {
                     values.append("'");
                     values.append(value);
                     values.append("'");
                 } else {
                     values.append(value);
                 }
             }
             sql.append("(");
             sql.append(columns);
             sql.append(") values(");
             sql.append(values);
             sql.append(")");
         } catch (IllegalArgumentException | IllegalAccessException e) {
             System.out.println(">>>>>>>创建插入sql语句失败");
             e.printStackTrace();
         }
         return sql.toString();
     }

五、总结

  写一个框架是需要用心的事情,需要考虑到使用者的方便性,以及功能的完整性与健壮性。

  这个只是一个半成品,很多地方还没有实现,bug也不少,性能就更加不要说了,写这个是为了学习,很多地方理解有误的,还望各路大神指出。

六、附件

项目文件夹:lfdb

下载地址:http://pan.baidu.com/s/1bn1Y6BX

如果有什么疑问或者建议,请联系我

文件说明:

1、lfdb源码.zip  :lfdb的源代码

2、lfdb_1.2.jar  :可以直接使用的jar包

3、lfdbdemo源码.zip  :lfdb示例的源代码

封装JDBC:实现简单ORM框架lfdb的更多相关文章

  1. JDBC 利用反射技术将查询结果封装为对象(简单ORM实现)

    ORM(Object Relational Mapping)对象关系映射 public class ORMTest { public static void main(String[] args) t ...

  2. JAVA描述的简单ORM框架

    抽了点时间自己写了个ORM,主要是为了复习JAVA泛型,映射,注解方面的知识.如需代码,可前往:https://github.com/m2492565210/java_orm自行下载 框架的类结构如下 ...

  3. 常见ORM框架及JDBC操作工具类

    在Java 程序里面去连接数据库,最原始的办法是使用JDBC 的API.我们先来回顾一下使用JDBC 的方式,我们是怎么操作数据库的. // 注册JDBC 驱动 Class.forName(" ...

  4. mybatis(一)常见ORM框架及JDBC操作工具类

      转载:https://www.cnblogs.com/wuzhenzhao/p/11075569.html 在Java 程序里面去连接数据库,最原始的办法是使用JDBC 的API.我们先来回顾一下 ...

  5. PHP ORM框架与简单代码实现(转)

    对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据 ...

  6. 重学 Java 设计模式:实战中介者模式「按照Mybaits原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...

  7. 简单实用的Android ORM框架TigerDB

    TigerDB是一个简单的Android ORM框架,它能让你一句话实现数据库的增删改查,同时支持实体对象的持久化和自动映射,同时你也不必关心表结构的变化,因为它会自动检测新增字段来更新你的表结构. ...

  8. 【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

    文件夹      [SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器開始(八)      [SSH进阶之路]一步步重构容器实现Spring框架--解决容器对组件的"侵入 ...

  9. .Net Core 简单定时任务框架封装

    有段日子没有更新,写点东西冒个泡 .这篇文章过来讲个小东西,也是大家在日常开发中也经常需要面临的问题:后台定时任务处理.估计大家看到这句就已经联想到 QuartZ 等类似第三方类库了,不好意思,后边的 ...

随机推荐

  1. vijosP1071 新年趣事之打牌

    vijosP1071 新年趣事之打牌 链接:https://vijos.org/p/1071 [思路] 01背包+路径输出. 用d[][]记录[][]可转移的数目,>=2则输出-1,0输出0,否 ...

  2. [待解决问题] 启动不了Android工程

    在使用 AudioInputStream sample = AudioSystem.getAudioInputStream(voiceSampleFile); 调用javax.sound.sample ...

  3. poj1691绘画板

    1 7 0 0 2 2 1 0 2 1 6 2 2 0 4 2 1 1 2 4 4 2 1 4 3 6 1 4 0 6 4 1 3 4 6 6 2 #include<stdio.h> #i ...

  4. 用python正则表达式提取字符串

    在日常工作中经常遇见在文本中提取特定位置字符串的需求.python的正则性能好,很适合做这类字符串的提取,这里讲一下提取的技巧,正则表达式的基础知识就不说了,有兴趣的可以看re的教程. 提取一般分两种 ...

  5. 53个要点提高php效率

    用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说 ...

  6. export 命令 设置环境变量

    export KERN_DIR=/usr/src/kernels/2.6.18-194.11.1.el5-x86_64 设置环境变量 内核加载目录

  7. UML进行Linux内核调试

    http://www.lenky.info/ http://blog.csdn.net/ztz0223/article/details/7874759 http://user-mode-linux.s ...

  8. windows 下解决 Time_Wait 和 CLOSE_WAIT 方法

    修改Time_Wait参数的方法 (在服务端修改)Windows下在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Paramet ...

  9. jQuery ajax 传递数组到struts2

    使用jQuery的$.ajax()方法进行异步交互时,如果传递的数据有数组(例如传输checkbox数据),Action中经常会接受不到数据. 此时应该注意一下data中数组的写法,例如: //组合成 ...

  10. Codeforces 231E - Cactus

    231E - Cactus 给一个10^5个点的无向图,每个点最多属于一个环,规定两点之间的简单路:从起点到终点,经过的边不重复 给10^5个询问,每个询问两个点,问这两个点之间有多少条简单路. 挺综 ...