作者: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
三、使用
一个东西,要想明白他的原理,必须先要知道怎么使用:
- 创建Configuration对象:构造时加载配置文件。
- 使用Configuration对象创建一个SessionFactory对象:configuration.buildSessionFactory()。
- 获取Session。
- 使用session执行操作。
- 关闭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示例的源代码