您的位置:首页 > 其它

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

2013-10-15 10:32 155 查看


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

发表回复

0.00 / 5 5

1
/ 5

2
/ 5

3
/ 5

4
/ 5

5
/ 5

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的新特性,如果不明白的请看我上一篇博文】下面请看此代码

package com.zh.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
* @Copyright (C), 2010-2030 淘青春团队
* @FileName DB.java
* @version 1.0
* @Description: 【用来操作数据库的类】
* @Author 张兵
* @Date: 2013-8-3:下午8:09:19
* @Modification User: 程序修改时由开发人员编写
* @Modification Date: 程序修改时间
* @mailto bolobeach@gmail.com
*/
public class DB {
private String DBDrive = "com.mysql.jdbc.Driver";
private String DBUrl = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
private String DBUser = "root";
private String DBPassword = "XXXXXX";
private ResultSet _rs = null;
private Connection _conn = null;
private Statement _stmt = null;
/**
* 执行一则更新语句,返回主键值
*
* @param sql
* @return
*/

public Connection getConn() {
try {
Class.forName(DBDrive);
_conn = DriverManager.getConnection(DBUrl, DBUser, DBPassword);
System.out.println("数据库可以使用了!!!!");
} catch (Exception e) {
System.out.println("---------出现异常,获取连接失败--------");
e.printStackTrace();
}
return _conn;
}

public int executeUpdate(String sql) {
int result = -1;
try {

// 执行sql
_stmt = getConn().createStatement();
_stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
// 获取主键
_rs = _stmt.getGeneratedKeys();
while (_rs.next()) {
// 获取最后一个主键值
result = _rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
this.colse();
}
return result;
}

public ResultSet executeQuery(String sql) {

try {
// 执行sql
_stmt = getConn().createStatement();
_rs = _stmt.executeQuery(sql);

} catch (Exception e) {
e.printStackTrace();
}

return _rs;
}

/**
* 获取数据库连接
*
* @return
*/

// 关闭数据库操作。。。。
public boolean colse() {
try {
if (_rs != null) {
_rs.close();
}
if (_stmt != null) {
_stmt.close();
}
if (_conn != null) {
_conn.close();
}
return true;
} catch (SQLException e) {
System.out.println("关闭失败。。。。。");
e.printStackTrace();
return false;
}
}

}


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

package com.zh.reflectUtil;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.zh.basic.BasicDao;
import com.zh.basic.BasicImpl;
import com.zh.bean.UsersBean;
import com.zh.db.DB;

/**
* @Copyright (C), 2010-2030 淘青春团队
* @FileName ReflectUtil.java
* @version 1.0
* @Description: 【java反射的until帮助类】
* @Author 张兵
* @Date: 2013-8-3:下午8:23:43
* @Modification User: 程序修改时由开发人员编写
* @Modification Date: 程序修改时间
* @mailto bolobeach@gmail.com
*/
public class ReflectUtil {
public static void main(String[] args) {
BasicDao basicDao = new BasicImpl();
//UsersBean usersBean = new UsersBean(1, "张兵", "123", "390125214@qq.com");
UsersBean usersBean = new UsersBean();
usersBean.setEmail("390125214@qq.com");
usersBean.setPassword("123");
usersBean.setUserName("张fff兵");
usersBean.setUsersId(2);
try {
int a = basicDao.update(usersBean);
System.out.println("zuihou.."+a);
} catch (Exception e) {
e.printStackTrace();
}
/*try {
getPK("usersBean");
} catch (SQLException e) {
e.printStackTrace();
}*/
}

/**
* 把第一个字母转换为大写
*
* @param fildeName
* @return
* @throws Exception
*/
public static String getMethodName(String fildeName) throws Exception {
byte[] items = fildeName.getBytes();
items[0] = (byte) ((char) items[0] - 'a' + 'A');
return new String(items);
}
/**
* 把头字母转为小写最优化的
* @param tableName
* @return
* @throws Exception
*/
public static String getTableName(String tableName) throws Exception{
byte[] temp = tableName.getBytes();
temp[0] = (byte) ((char) temp[0] +32);
return new String(temp);
}
/**
* 通过表的名字,得到表的主键
* @param tableName 表明
* @return list对象 (考虑联合主键)
* @throws SQLException
*/
public static List<Object> getPK(String tableName) throws SQLException{
List<Object> list = new ArrayList<>();
DB db = new DB();
Connection connection = db.getConn();
DatabaseMetaData data = connection.getMetaData();
ResultSet resultSet = data.getPrimaryKeys(null, null, tableName.toUpperCase());
while (resultSet.next()) {
list.add(resultSet.getObject(4));
}
return list;
}
}


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

  保存方法以及删除方法在这里我就不用讲了吧,代码大家应该都看的明明白白的,也许有些人对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操作。

package com.zh.basic;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import com.zh.db.DB;
import com.zh.reflectUtil.ReflectUtil;

/**
* @Copyright (C), 2010-2030 淘青春团队
* @FileName BasicImpl.java
* @version 1.0
* @Description: 用于详细说明此程序文件完成的主要功能
* @Author 张兵
* @Date: 2013-8-3:下午8:22:31
* @Modification User: 程序修改时由开发人员编写
* @Modification Date: 程序修改时间
* @mailto bolobeach@gmail.com
*/
public class BasicImpl extends DB implements BasicDao {
ReflectUtil reflectUtil = new ReflectUtil();
public int save(Object object) throws Exception {
int reNumber = -1;
String values = "";
String temp = "";
Class<?> clazz = object.getClass();
ArrayList<Object> params = new ArrayList<Object>();
Field[] fields = clazz.getDeclaredFields();
//在这里必须设置,不然不可以得到私有变量
Field.setAccessible(fields, true);
int fieldsLength = fields.length;
for (int i = 0; i < fieldsLength; i++) {
Field field = fields[i];
values +=field.getName()+",";
Object val = field.get(object);
temp+="?,";
params.add(val);
}
String tableName = clazz.getSimpleName();
String sql = "insert into "+reflectUtil.getTableName(tableName)+"("+values.substring(0, values.length()-1)+") values("+temp.substring(0,temp.length()-1)+")";
System.out.println(sql);
try {
Connection conn = this.getConn();
PreparedStatement ps = null;
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.size(); i++) {
System.err.println(params.get(i));
ps.setObject(i+1, params.get(i));
}
reNumber = ps.executeUpdate();
this.colse();
} catch (Exception e) {
e.printStackTrace();
}
return reNumber;
}

public int update(Object object) throws Exception{
int reNumber = -1;
String values = "";
Class<?> clazz = object.getClass();
ArrayList<Object> params = new ArrayList<Object>();
Field[] fields = clazz.getDeclaredFields();
Field.setAccessible(fields, true);
int fieldsLength = fields.length;
String tableName = this.reflectUtil.getTableName(clazz.getSimpleName());
List<Object> list = this.reflectUtil.getPK(tableName);
Object pkValue = null;
Object pk = null;
for (Object object2 : list) {
pk = object2;
for (int i = 0; i < fieldsLength; i++) {
Field field = fields[i];
if (field.getName().equals(object2)) {
values +=field.getName()+"=?,";
pkValue =  field.get(object);
}else {
values +=field.getName()+"=?,";
}
Object val = field.get(object);
params.add(val);
}
}
String sql = "update "+tableName+" set "+values.substring(0,values.length()-1)+" where "+pk+"=?";
System.out.println(sql);
try {
Connection conn = this.getConn();
PreparedStatement ps = null;
ps = conn.prepareStatement(sql);
int temp1 = params.size();
for (int i = 0; i < temp1; i++) {
System.err.println(params.get(i));
ps.setObject(i+1, params.get(i));
}
ps.setObject(temp1+1, pkValue);
reNumber = ps.executeUpdate();
this.colse();
} catch (Exception e) {
e.printStackTrace();
}
return reNumber;
}
public int deleteById(Class<?> clazz,Object id) throws Exception{
int reNumber = -1;
String tableName = this.reflectUtil.getTableName(clazz.getSimpleName());
List<Object> list = this.reflectUtil.getPK(tableName);//得到主键
Connection conn = this.getConn();
for (Object object : list) {
String sql = "delete from "+tableName+" where "+object+"=?";
PreparedStatement ps = null;
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
reNumber = ps.executeUpdate();
reNumber = 1;
this.colse();
}
return reNumber;
}

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: