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

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;
	}

	@Override
	public String toString() {
		return "Users [id=" + id + ", username=" + username + ", password=" + password + ", state_id=" + state_id + "]";
	}
}

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

mysql.username=root
mysql.password=mysqlpass
mysql.url=jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8
mysql.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 block
			e.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 block
			e.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)){ //判断前面的属性名 是否 与截取出来的字段名相同 ,则说明顺序相同 ,则拼接
						//去掉ID
						fieldName += 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 block
							e.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)){ //判断前面的属性名 是否 与截取出来的字段名相同 ,则说明顺序相同 ,则拼接
						//去掉ID
						fieldName.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 block
							e.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通过反射,动态生成insert语句原理 并向数据库添加数据_第1张图片hibernate通过反射,动态生成insert语句原理 并向数据库添加数据_第2张图片



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



你可能感兴趣的:(java框架)