封装JDBC:实现简单ORM框架lfdb

时间:2023-03-08 17:36:48
封装JDBC:实现简单ORM框架lfdb

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

一、简介

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

二、结构

封装JDBC:实现简单ORM框架lfdb

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示例的源代码