Hibernate学习_001_模拟hibernate的实现

来源:互联网 发布:网络flash英文歌曲 编辑:程序博客网 时间:2024/05/17 07:56

前言:本人菜鸟一只,原来一直认为拜读大神们神作来提升自己能力就已经足够,但是发现这样其实是对自己能力提升设置了一个壁垒,所以现在我会把自己的学习成果写成博文,这样,既方便大家学习交流,也便于同行发现自己学习认知上的不足并给与指正。同时,我也认为,技术博客不仅仅是一个分享知识的平台,同时也是自己总结所学知识的一个平台,不管是原创,还是参考其他大牛们神作后的所思所想,只要是自己经过思考所得,那就有它存在的价值。

        以前,用ssh做过几个小的项目,但是仅仅是机械式的操作,局限于使用,并没有对其内部实现机制进行深入的理解,考完研,闲来无事,决定重新彻头彻尾学一遍ssh,个人觉得其实struts+hibernate+spring架构中,struts最为简单,无非就是action,拦截器等的各种配置,spring最为复杂,因为其对于各个组件,框架的支持,十分的繁杂,比如,java securty, Restful等。 而hibernate则介于两者之间。

       今天参考hibernate的文档实现了ssh的集成化,决定写一个hibernate的模拟实现。 我们大家其实都会使用hibernate,无非就是CRUD.OOA,OOD,这些东西,感觉十分简单,可是我们也许从没有想过为什么会有hibernate.cfg.xml,Entity.hbm.xml文件,也很少去想通过session去save一个对象的时候,hibernate内部究竟帮我做了什么,为什么一个标准的Java Bean 属性一定会有getXxx()方法。这些我通过以下一个例子对大家说明。(如果说的不对,欢迎大家指正,相互学习。)

       首先,我们建立好自己的实体类。(这个类就是一个标准的Java Bean ,无需多解释。)

public class Person{private int id;private String name;private int age;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}

  然后,建立好我们的Session类。(这个类就是模拟Hibernate中的session的。)

  注:以下代码我们假设我们从配置文件已经读出数据库表名,从实体映射中已经读出来属性名和字段名的对应关系。

public class Session {//待处理sql语句。String sql ="";//数据库表名String tableName="Person";//此Map对象模拟的是从*.hbm.xml或者是从@Entity中读出来的(数据库列名:属性)键值对。Map<String,String> vfs;//取得对应Entity类中的getProperty方法。String[] methodNames;public Session(){vfs = new HashMap<String,String>();vfs.put("id", "id");vfs.put("name", "name");vfs.put("age", "age");//按照vfs的长度来设置方法名数组的长度。methodNames = new String[vfs.size()];}public void save(Person s) throws Exception{Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/HibernateDemo", "root", "root");//拼凑sql语句。而且顺便在这个方法中把sql中用到的属性放到methodNames中,以便通过反射形式给SQL赋值的时候使用。createSQL();PreparedStatement pstm  = conn.prepareStatement(sql);//在以下循环中对sql语句中的占位符“?”进行赋值。for(int index = 0 ; index < vfs.size();index ++ ){String value = methodNames[index];String property = Character.toUpperCase(value.charAt(0))+value.substring(1);String method = "get"+property;//以下则是通过反射来模拟hibernate核心实现机制。        Method m = s.getClass().getMethod(method);if(m.getReturnType().getName().equals("java.lang.String")){pstm.setString(index+1, (String)m.invoke(s));}if(m.getReturnType().getName().equals("int")){pstm.setInt(index+1, (Integer)m.invoke(s));}}pstm.executeUpdate();pstm.close();conn.close();}private void createSQL() {//填充(?,?,?)形式的字符串String place1 = "";for(int i = 0 ; i < vfs.size(); i ++){place1 += "?,";}place1 = place1.substring(0, place1.length()-1);//填充(id,name,age)形式字符串。String values = "";int methodIndex = 0 ; for(String m : vfs.keySet()){values += m +",";//把属性设置到对应的数组中,到时候通过反射赋值的时候使用。methodNames[methodIndex++]= vfs.get(m);}values = values.substring(0,values.length()-1);sql = "insert into "+tableName +" ("+values+") values ("+place1+")";}}
接着就是我们的测试代码:
public class PersonTest {public static void main(String[] args) throws Exception{     Session session = new Session();          Person p = new Person();     p.setId(2);     p.setName("s");     p.setAge(1);          session.save(p);}}

        其实,hibernate底层是采用的还是jdbc来操作数据库,我们在使用hibernate的session保存一个对象的时候,其实是会调用所保存对象的getXxx()方法,在底层jdbc中对参数进行赋值,所以,按常理来说,我们所保存的java对象,一般最好是一个标准的Java Bean。还有一点,其实hibernate内部实现机制并没有大量的采用反射机制,可能是效率的影响吧,更多的hibernate实现是通过直接生成二进制码的方式来实现,这样效率得到很大提升。

       理解如有误区,欢迎大家指点,相互交流,共同进步。

       

0 0