关键点:
使用泛型方法来获取
通过泛型的模式获取运行时类
/*通过反射获取运行是要建立的类的引用*/ /** * 建立泛型参数、泛型方法 * <T>表示泛型方法 * 方法名前面的T表示返回值类型 * Class<T>当中的T表示对应的运行时类 * @param clazz * @param sql * @param args * @param <T> * @return */ public <T> T getInstance(Class<T> clazz, String sql, Object ...args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { //获取数据库连接 conn = JDBCUtils.getConnection(); //预编译sql ps = conn.prepareStatement(sql); //填充占位符 for (int i=0; i<args.length; i++) { ps.setObject(i+1, args[i]); } //执行sql保存为结果集对象 rs = ps.executeQuery(); //获取结果集元数据 ResultSetMetaData rsmd = rs.getMetaData(); //获取列数 int columnCount = rsmd.getColumnCount(); //获取结果集 if (rs.next()) { //通过反射获取运行时加载类建立对象的引用--->反射+泛型 T t = clazz.newInstance(); //--->任何一个类在提供一个JavaBean对象的时候要提供一个空参的public权限的构造器,在这里使用 /* 方法当中返回一个t t由当前类决定的 */ //动态的获取列,列的数量为列数 for (int j=0; j<columnCount; j++) { //动态的获取列值--->结果集当中获取列值 Object columnValue = rs.getObject(j+1); //获取每列的列名 String columnLabel = rsmd.getColumnLabel(j+1); //动态获取加载的类的属性--->获取到域(T类型的) Field field = clazz.getField(columnLabel); //设置私有属性可访问 field.setAccessible(true); //将对象属性设置成列值 field.set(t, columnValue); } return t; } }catch (Exception e) { e.printStackTrace(); } return null; }
查询结果集返回多条数据--->多个对象
新语法糖:--->list.forEach(System.out::println)
由于占位符的使用所以解决了SQL
注入的问题
/** * 查询一条sql语句返回多个结果集对象 * 使用List进行封装然后再集中展示 * @since JDK 1.8 * @date 2021/09/30 * @author Lucifer */ public <T> List<T> getForList(Class<T> clazz, String sql, Object ...args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { //获取数据库连接 conn = JDBCUtils.getConnection(); //预编译sql ps = conn.prepareStatement(sql); //填充占位符 for (int i=0; i<args.length; i++) { ps.setObject(i+1, args[i]); } //执行sql保存为结果集对象 rs = ps.executeQuery(); //获取结果集元数据 ResultSetMetaData rsmd = rs.getMetaData(); //获取列数 int columnCount = rsmd.getColumnCount(); //创建集合对象--->用于存储查询出的结果集对象 ArrayList<T> list = new ArrayList<T>(); //查询多条语句使用循环进行查询 while (rs.next()) { T t = clazz.newInstance(); //处理结果集每一行数据的每一列 for (int j=0; j<columnCount; j++) { //获取列值 Object columnValue = rs.getObject(j+1); //获取列名 String columnLabel = rsmd.getColumnLabel(j+1); //动态获取运行类 Field field = clazz.getDeclaredField(columnLabel); field.setAccessible(true); field.set(t, columnValue); } //将t对象添加进入集合数组 list.add(t); /* 查询未找到 1、抛异常了 2、没有数据了 */ } return list; }catch (Exception e) { e.printStackTrace(); } return null; }
注意:
占位符的目的是为了解决SQL
注入问题
避免拼串的发生
/** * 针对所有得运行时类进行表的查询操作 * @since JDK 1.8 * @date 2021/09/30 * @author Lucifer */ public <T> T getInstanceSQL(Class<T> clazz, String sql, Object ...args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { //建立连接 conn = JDBCUtils.getConnection(); //预编译sql ps = conn.prepareStatement(sql); //填充占位符 for (int i=0; i<args.length; i++) { ps.setObject(i+1, args[i]); } //执行查询操作 rs = ps.executeQuery(); //获取结果集元数据 ResultSetMetaData rsmd = rs.getMetaData(); //通过结果集元数据获取列数 int columnCount = rsmd.getColumnCount(); //查询表中第一行数据 while (rs.next()) { //通过反射获取运行时加载类建立对象的引用--->反射+泛型 T t = clazz.newInstance(); //循环获取列值 for (int j=0; j<columnCount; j++) { //动态的获取列值--->结果集当中获取列值 Object columnValue = rs.getObject(j+1); //获取每列的列名 String columnLabel = rsmd.getColumnLabel(j+1); //动态获取加载的类的属性--->获取到域(T类型的) Field field = clazz.getField(columnLabel); //设置私有属性可访问 field.setAccessible(true); //将对象属性设置成列值 field.set(t, columnValue); } return t; } }catch (Exception e) { e.printStackTrace(); } return null; }
测试方法:
@Test public void testLoginNo1() { //获取控制台内容 Scanner scan = new Scanner(System.in); System.out.println("UserName:"); String user = scan.next(); System.out.println("PassWord:"); String password = scan.next(); //提供一个sql语句 String sql = "select `name`, `password` from users where Name = ? and Password = ?"; /* 上诉的写法称为拼串,需要拼写sql语句。--->不是一个完整的sql语句,存在sql注入的风险 */ User returnUser = getInstanceSQL(User.class, sql, user, password); if (returnUser!=null){ System.out.println("Successfully!"); }else { System.out.println("UserName or PassWord Error!!!"); } }
Preparestatement
预编译sql
语句--->预编译期间已经判断了sql
的逻辑关系
Preparestatement
可以传流文件,拼串不可以。
Preparestatement
可以更高效的插入--->预编译期间只需要检验一次,后续的添加只需要填充占位符即可
Statement
因为没有预编译,所以在拼串的时候可以改变其逻辑关系,由且变成或等
面向接口编程的思想
ORM
思想
原则:
不出现第三方的API
将第三方API与代码解耦,第三方API封装到XML
或者配置文件中,全程操作使用Driver
对象进行操作--->多态的一种形式
JavaBean
类对应到数据库当中的一张表原则:
Java
操作的任何东西都是以对象的方式进行呈现
getColumnCount
getColumnLabel
//动态获取加载的类的属性--->获取到域(T类型的) Field field = clazz.getField(columnLabel); //设置私有属性可访问 field.setAccessible(true); //将对象属性设置成列值 field.set(t, columnValue);