反射封装JDBC——hibernate DDL 实现原理

反射封装JDBC——hibernate DDL 实现原理

0 votes,  0.00 avg. rating ( 0% score)

  现在学习java的人实在是太多了,什么培训学校,什么高校,基本上是学习java的,以至于现在java工资比较低。我记得上次我去面试的时候, 居然几个假冒的项目经理说struts底层不是用servlet,当时我觉得这项目经理未必也太….,也许我理解错误了吧,struts底层不是采用servlet,本来从事java已经2年了,但是只是入门阶段,所以写的东西有很多错误,希望大家可以指出来,我也好学习学习。

  做java的人肯定学过什么S*SH框架吧,但是很多人都只会使用罢了,很少的人会去看源码,其实这些框架真正的价值是在于整个架构,而不是在于使用罢了,如果你做为一个程序员,底层是怎么实现的都不知道,那又有什么作用呢,在此我通过反射写了一个类似于hibernate实现(DDL),同时我也添加了一些新的东西,可能是我的想法和hibernate作者有点出入吧,就是在更新方法的时候。大家仔细看看就知道了。

  首先看一下项目结构,下面有连接,我直接把源码上传上去,大家可以直接下载来看   (因为我没有实现hibernate的自动创建表,所以需要自己建立表,建立表参考UsersBean类)下载链接http://files.cnblogs.com/bolobeach/JDBCHelper.rar

  一、闲话少说了吧 ,我相信看我写的博客都知道,我比较喜欢直接上源码来看,连接数据库最基本上的操作我封装到一个类里面,这个基本上没有什么讲的,【如果你采用java7的话不需要关闭数据库资源,JVM会自动关闭的,这是java7的新特性,如果不明白的请看我上一篇博文】下面请看此代码

       
       
  1. package com.zh.db;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. /**
  8. * @Copyright (C), 2010-2030 淘青春团队
  9. * @FileName DB.java
  10. * @version 1.0
  11. * @Description: 【用来操作数据库的类】
  12. * @Author 张兵
  13. * @Date: 2013-8-3:下午8:09:19
  14. * @Modification User: 程序修改时由开发人员编写
  15. * @Modification Date: 程序修改时间
  16. * @mailto bolobeach@gmail.com
  17. */
  18. public class DB {
  19. private String DBDrive = "com.mysql.jdbc.Driver";
  20. private String DBUrl = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
  21. private String DBUser = "root";
  22. private String DBPassword = "XXXXXX";
  23. private ResultSet _rs = null;
  24. private Connection _conn = null;
  25. private Statement _stmt = null;
  26. /**
  27. * 执行一则更新语句,返回主键值
  28. *
  29. * @param sql
  30. * @return
  31. */
  32. public Connection getConn() {
  33. try {
  34. Class.forName(DBDrive);
  35. _conn = DriverManager.getConnection(DBUrl, DBUser, DBPassword);
  36. System.out.println("数据库可以使用了!!!!");
  37. } catch (Exception e) {
  38. System.out.println("---------出现异常,获取连接失败--------");
  39. e.printStackTrace();
  40. }
  41. return _conn;
  42. }
  43. public int executeUpdate(String sql) {
  44. int result = -1;
  45. try {
  46. // 执行sql
  47. _stmt = getConn().createStatement();
  48. _stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
  49. // 获取主键
  50. _rs = _stmt.getGeneratedKeys();
  51. while (_rs.next()) {
  52. // 获取最后一个主键值
  53. result = _rs.getInt(1);
  54. }
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. } finally {
  58. this.colse();
  59. }
  60. return result;
  61. }
  62. public ResultSet executeQuery(String sql) {
  63. try {
  64. // 执行sql
  65. _stmt = getConn().createStatement();
  66. _rs = _stmt.executeQuery(sql);
  67. } catch (Exception e) {
  68. e.printStackTrace();
  69. }
  70. return _rs;
  71. }
  72. /**
  73. * 获取数据库连接
  74. *
  75. * @return
  76. */
  77.  
  78. // 关闭数据库操作。。。。
  79. public boolean colse() {
  80. try {
  81. if (_rs != null) {
  82. _rs.close();
  83. }
  84. if (_stmt != null) {
  85. _stmt.close();
  86. }
  87. if (_conn != null) {
  88. _conn.close();
  89. }
  90. return true;
  91. } catch (SQLException e) {
  92. System.out.println("关闭失败。。。。。");
  93. e.printStackTrace();
  94. return false;
  95. }
  96. }
  97. }

二、做这个帮助类是必不可少的,帮助类下面主要有javabean 成员变量里面首字母转为小写,或者大写,以及怎么得到一个表里面的主键,hibernate底层是没有实现的,可能是因为效率的原因吧。

       
       
  1. package com.zh.reflectUtil;
  2. import java.sql.Connection;
  3. import java.sql.DatabaseMetaData;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import com.zh.basic.BasicDao;
  9. import com.zh.basic.BasicImpl;
  10. import com.zh.bean.UsersBean;
  11. import com.zh.db.DB;
  12. /**
  13. * @Copyright (C), 2010-2030 淘青春团队
  14. * @FileName ReflectUtil.java
  15. * @version 1.0
  16. * @Description: 【java反射的until帮助类】
  17. * @Author 张兵
  18. * @Date: 2013-8-3:下午8:23:43
  19. * @Modification User: 程序修改时由开发人员编写
  20. * @Modification Date: 程序修改时间
  21. * @mailto bolobeach@gmail.com
  22. */
  23. public class ReflectUtil {
  24. public static void main(String[] args) {
  25. BasicDao basicDao = new BasicImpl();
  26. //UsersBean usersBean = new UsersBean(1, "张兵", "123", "390125214@qq.com");
  27. UsersBean usersBean = new UsersBean();
  28. usersBean.setEmail("390125214@qq.com");
  29. usersBean.setPassword("123");
  30. usersBean.setUserName("张fff兵");
  31. usersBean.setUsersId(2);
  32. try {
  33. int a = basicDao.update(usersBean);
  34. System.out.println("zuihou.."+a);
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. /*try {
  39. getPK("usersBean");
  40. } catch (SQLException e) {
  41. e.printStackTrace();
  42. }*/
  43. }
  44. /**
  45. * 把第一个字母转换为大写
  46. *
  47. * @param fildeName
  48. * @return
  49. * @throws Exception
  50. */
  51. public static String getMethodName(String fildeName) throws Exception {
  52. byte[] items = fildeName.getBytes();
  53. items[0] = (byte) ((char) items[0] - 'a' + 'A');
  54. return new String(items);
  55. }
  56. /**
  57. * 把头字母转为小写最优化的
  58. * @param tableName
  59. * @return
  60. * @throws Exception
  61. */
  62. public static String getTableName(String tableName) throws Exception{
  63. byte[] temp = tableName.getBytes();
  64. temp[0] = (byte) ((char) temp[0] +32);
  65. return new String(temp);
  66. }
  67. /**
  68. * 通过表的名字,得到表的主键
  69. * @param tableName 表明
  70. * @return list对象 (考虑联合主键)
  71. * @throws SQLException
  72. */
  73. public static List<Object> getPK(String tableName) throws SQLException{
  74. List<Object> list = new ArrayList<>();
  75. DB db = new DB();
  76. Connection connection = db.getConn();
  77. DatabaseMetaData data = connection.getMetaData();
  78. ResultSet resultSet = data.getPrimaryKeys(null, null, tableName.toUpperCase());
  79. while (resultSet.next()) {
  80. list.add(resultSet.getObject(4));
  81. }
  82. return list;
  83. }
  84. }

 三、因为我采用面向结构编程, 所以有一个接口类,在这里我就不用接口类了,直接上实现类的源码。这个才是此博文的重点。

  保存方法以及删除方法在这里我就不用讲了吧,代码大家应该都看的明明白白的,也许有些人对java反射不是很了解,可以去查查资料。我采用的就是对sql语句进行拼接,

所以保存语句以及删除语句都本质上都和hibernate一样是jdbc罢了。但是在update()方法中有些不一样,hibernate的更新原理是这样:首先hibernate先会执行一个select操作,到数据库中查找当前要update操作的对象的主键是否存在,类似于:select id from table where id=XXX,如果查找到了改id,就说明该对象是一个持久化对象,如果该对像的某些属性变化了,hibernate就会自动的执行update操作,同步数据库中的该对象。如果hibernate没有查找到该id,就说明该对象是一个游离的对象,hibernate就会执行insert操作。根据这些,就可以找找是不是要update的对象的id在数据库中不存在,或是更改的该对象的id。这些都是执行insert而不是update。 但是我可能考虑的没有那么多直接默认表结构里面有主键,首先查询出主键,把数据库那个字段表示主键查询出来,然后在根据sql语句进行跟新, 如果没有主键的对应的值话,就返回false,不做更新操作, 同时也不做insert操作。

       
       
  1. package com.zh.basic;
  2. import java.lang.reflect.Field;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSetMetaData;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import com.zh.db.DB;
  9. import com.zh.reflectUtil.ReflectUtil;
  10. /**
  11. * @Copyright (C), 2010-2030 淘青春团队
  12. * @FileName BasicImpl.java
  13. * @version 1.0
  14. * @Description: 用于详细说明此程序文件完成的主要功能
  15. * @Author 张兵
  16. * @Date: 2013-8-3:下午8:22:31
  17. * @Modification User: 程序修改时由开发人员编写
  18. * @Modification Date: 程序修改时间
  19. * @mailto bolobeach@gmail.com
  20. */
  21. public class BasicImpl extends DB implements BasicDao {
  22. ReflectUtil reflectUtil = new ReflectUtil();
  23. public int save(Object object) throws Exception {
  24. int reNumber = -1;
  25. String values = "";
  26. String temp = "";
  27. Class<?> clazz = object.getClass();
  28. ArrayList<Object> params = new ArrayList<Object>();
  29. Field[] fields = clazz.getDeclaredFields();
  30. //在这里必须设置,不然不可以得到私有变量
  31. Field.setAccessible(fields, true);
  32. int fieldsLength = fields.length;
  33. for (int i = 0; i < fieldsLength; i++) {
  34. Field field = fields[i];
  35. values +=field.getName()+",";
  36. Object val = field.get(object);
  37. temp+="?,";
  38. params.add(val);
  39. }
  40. String tableName = clazz.getSimpleName();
  41. String sql = "insert into "+reflectUtil.getTableName(tableName)+"("+values.substring(0, values.length()-1)+") values("+temp.substring(0,temp.length()-1)+")";
  42. System.out.println(sql);
  43. try {
  44. Connection conn = this.getConn();
  45. PreparedStatement ps = null;
  46. ps = conn.prepareStatement(sql);
  47. for (int i = 0; i < params.size(); i++) {
  48. System.err.println(params.get(i));
  49. ps.setObject(i+1, params.get(i));
  50. }
  51. reNumber = ps.executeUpdate();
  52. this.colse();
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. }
  56. return reNumber;
  57. }
  58. public int update(Object object) throws Exception{
  59. int reNumber = -1;
  60. String values = "";
  61. Class<?> clazz = object.getClass();
  62. ArrayList<Object> params = new ArrayList<Object>();
  63. Field[] fields = clazz.getDeclaredFields();
  64. Field.setAccessible(fields, true);
  65. int fieldsLength = fields.length;
  66. String tableName = this.reflectUtil.getTableName(clazz.getSimpleName());
  67. List<Object> list = this.reflectUtil.getPK(tableName);
  68. Object pkValue = null;
  69. Object pk = null;
  70. for (Object object2 : list) {
  71. pk = object2;
  72. for (int i = 0; i < fieldsLength; i++) {
  73. Field field = fields[i];
  74. if (field.getName().equals(object2)) {
  75. values +=field.getName()+"=?,";
  76. pkValue = field.get(object);
  77. }else {
  78. values +=field.getName()+"=?,";
  79. }
  80. Object val = field.get(object);
  81. params.add(val);
  82. }
  83. }
  84. String sql = "update "+tableName+" set "+values.substring(0,values.length()-1)+" where "+pk+"=?";
  85. System.out.println(sql);
  86. try {
  87. Connection conn = this.getConn();
  88. PreparedStatement ps = null;
  89. ps = conn.prepareStatement(sql);
  90. int temp1 = params.size();
  91. for (int i = 0; i < temp1; i++) {
  92. System.err.println(params.get(i));
  93. ps.setObject(i+1, params.get(i));
  94. }
  95. ps.setObject(temp1+1, pkValue);
  96. reNumber = ps.executeUpdate();
  97. this.colse();
  98. } catch (Exception e) {
  99. e.printStackTrace();
  100. }
  101. return reNumber;
  102. }
  103. public int deleteById(Class<?> clazz,Object id) throws Exception{
  104. int reNumber = -1;
  105. String tableName = this.reflectUtil.getTableName(clazz.getSimpleName());
  106. List<Object> list = this.reflectUtil.getPK(tableName);//得到主键
  107. Connection conn = this.getConn();
  108. for (Object object : list) {
  109. String sql = "delete from "+tableName+" where "+object+"=?";
  110. PreparedStatement ps = null;
  111. ps = conn.prepareStatement(sql);
  112. ps.setObject(1, id);
  113. reNumber = ps.executeUpdate();
  114. reNumber = 1;
  115. this.colse();
  116. }
  117. return reNumber;
  118. }
  119. }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值