hibernate通过反射,动态生成insert语句原理 并向数据库添加数据

来源:互联网 发布:java intent bundle 编辑:程序博客网 时间:2024/04/30 11:59

hibernate中的反射机制,实现逆向访问数据库,并封装insert方法


首先,我们写dao层的时候会发现,有很多insert语句,比如: insert into Users(username,password) values('zhangsan','zs123') 。开发过程中会遇到很多这样的插入语句,为了简化开发,Hibernate框架实现语句的封装,


为了更好的理解,我们下面通过反射机制来模拟封装insert方法  和通过Hibernate实现逆向访问数据库,并调用上面封装好的insert方法向数据库中动态插入数据。

1.Hibernate实现逆向访问数据库

1)首先我们需要的实体类 Users

public class Users {private Integer id; // 编号private String username; // 账户private String password;// 密码private Integer state_id; // 职位状态
 public void setId(Integer id)  {this.id = id;}public Integer getId() {return id;}public void setUsername(String username) {this.username = username;}public String getUsername() {return username;}public void setPassword(String password) {this.password = password;}public String getPassword()  {return password;}public void setState_id(Integer state_id){this.state_id = state_id;}public Integer getState_id()             {return state_id;}
public Users() {}public Users(Integer id, String username, String password, Integer state_id) {this.id = id;this.username = username;this.password = password;this.state_id = state_id;}@Overridepublic String toString() {return "Users [id=" + id + ", username=" + username + ", password=" + password + ", state_id=" + state_id + "]";}}

2) 配置连接数据库的属性文件 test.properites

mysql.username=rootmysql.password=mysqlpassmysql.url=jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8mysql.driverClassName=com.mysql.jdbc.Driver
3)编写连接数据库的工具类

public class ConnectMysqlUtil {private static Connection con;static {// 使用反射加载属性文件:InputStream in = Object.class.getResourceAsStream("/test.properties");Properties pro = new Properties();try {pro.load(in);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} // 从输入流中读取属性列表(键和元素对)。// 获取properties中的属性String mysql_username = pro.getProperty("mysql.username").trim();String mysql_password = pro.getProperty("mysql.password").trim();String mysql_url = pro.getProperty("mysql.url").trim();String mysql_driverClassName = pro.getProperty("mysql.driverClassName").trim();try {Class.forName(mysql_driverClassName);con = DriverManager.getConnection(mysql_url, mysql_username, mysql_password);} catch (ClassNotFoundException | SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static Connection getCon(){return con;}}


通过上面的步骤,我们的准备工作已经做好了, 现在只需要编写工具类ReflexUtil来封装动态生成的insert语句 就可以了

重点:

public class ReflexUtil {//获取并且返回完整的insert  语句//String拼接public static String getInsertSQL(Object o) {Class c = o.getClass();Field[] fl = c.getDeclaredFields();String fieldName = "";//属性名拼接String valueName = ""; //字段值拼接for (Field field : fl) {String str = field.getName(); //获取属性名Method[] ms = c.getDeclaredMethods(); //获取方法for (Method method : ms) {String name = method.getName();//获取方法名if(name.startsWith("get")&&!name.startsWith("getClass")){//过滤 筛选get方法String str1 = name.substring(3);  //通过方法名截取出字段名if(str.equalsIgnoreCase(str1)&&!"id".equalsIgnoreCase(str)){ //判断前面的属性名 是否 与截取出来的字段名相同 ,则说明顺序相同 ,则拼接//去掉IDfieldName += str + ",";String str2;try {str2 = method.invoke(o, null).toString(); //获取方法值String type = method.getReturnType().getSimpleName(); //方法类型if("String".equalsIgnoreCase(type)){valueName += "'"+str2+"'"+","; //数据库中 String类型  需要加单引号 插入}else{valueName +=str2+",";}} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}fieldName = fieldName.substring(0, fieldName.length()-1); //去除末尾的逗号valueName = valueName.substring(0, valueName.length()-1);String sql= "insert into "+c.getSimpleName()+"("+fieldName+")"+" values"+"("+valueName+")";return sql;}//获取并且返回完整的insert  语句//StringBuffer拼接public static String getInsertSql(Object o){Class c = o.getClass();Field[] fl = c.getDeclaredFields();StringBuffer fieldName= new StringBuffer();//属性名拼接StringBuffer valueName=new StringBuffer() ; //字段值拼接for (Field field : fl) {String str = field.getName(); //获取属性名Method[] ms = c.getDeclaredMethods(); //获取方法for (Method method : ms) {String name = method.getName();//获取方法名if(name.startsWith("get")&&!name.startsWith("getClass")){//过滤 筛选get方法String str1 = name.substring(3);  //通过方法名截取出字段名if(str.equalsIgnoreCase(str1)&&!"id".equalsIgnoreCase(str)){ //判断前面的属性名 是否 与截取出来的字段名相同 ,则说明顺序相同 ,则拼接//去掉IDfieldName.append(str + ",") ;String str2;try {str2 = method.invoke(o, null).toString();String type = method.getReturnType().getSimpleName();if("String".equalsIgnoreCase(type)){valueName.append("'"+str2+"'"+",");}else{valueName.append(str2+",");}} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}String endFieldName = fieldName.substring(0, fieldName.length()-1); //去除末尾的逗号String endValueName = valueName.substring(0, valueName.length()-1);String sql= "insert into "+c.getSimpleName()+"("+endFieldName+")"+" values"+"("+endValueName+")";return sql;}}


最后编写测试类

public static void main(String[] args) throws SQLException {Users users = new Users(1,"张三","zs1231",8);String sql = ReflexUtil.getInsertSQL(users);Connection con = ConnectMysqlUtil.getCon();PreparedStatement psta = con.prepareStatement(sql);int i = psta.executeUpdate();if(i>0){System.out.println("插入成功");}}
测试结果:




通过上面步骤:实现了Hibernate底层的东西,也让我们理解了Hibernate的实现原理



0 0
原创粉丝点击