通用的查询方法
以面向对象的思想编写JDBC程序
向数据表中插入一条Student记录
-
新建一个Student,对应examStudents数据表
//流水号 int flowID;
//考试类型 int type;
//身份证号 String idCard;
//准考证号 String examCard;
//学生名 String studentName;
//学生地址 String location;
//考试分数 int grade; -
在测试方法testAddStudent()中
@test
public void testAddNewStudent() {
Student student=getStudentFromConsole();
addNewStudent(student);
}
-
获取从控制台输入的Student对象
Student student=getStudentFromConsole();
-
调用addStudent(Student stu)方法执行 插入操作
-
-
新建一个方法: void addStudnt(Student student) 把参数Student 对象插入到数据库中
PreparedStatement
-
使用Statement需要进行拼写SQL语句 很容易出错
比如String sql=“INSERT INTO examStudents VALUES(”
+student.getFlowID()
+","
+student.getType()
+",’"
+student.getIdCard()
+"’,’"
+student.getExamCard()
+"’,’"
+student.getStudentName()
+"’,’"
+student.getLocation()
+"’,"
+student.getGrade()
+")"; -
可以有效的禁止SQL注入
SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段落
对于Java而言,要防范SQL注入。只要用PreparedStatement代替Statement即可**注意 下面的代码就可以实现SQL注入**
String username = "a' OR PASSWORD = ";
String password = " OR '1'='1";
String sql = "SELECT * FROM users WHERE username = '" + username
+ "' AND " + "password = '" + password + "'";
System.out.println(sql);
-
PreparedStatement能最大可能提高性能
-
PreparedStatement是Statement的子接口,可以传入带占位符的SQL语句
并且提供了占位符变量的方法
-
使用PreparedStatement
-
创建PreparedStatement:
String sql="INSERT INTO examstudents VALUES(?,?,?,?,?,?,?)"
PreparedStatement ps=con.prepareStatement(sql);
-
调用PreparedStatement的setXxx(int index,Object val)设置占位符的值 index从1开始
preparedStatement.setString(1, "ATGUIGU"); preparedStatement.setString(2, "simpleit@163.com"); preparedStatement.setDate(3, new Date(new java.util.Date().getTime()));
-
执行SQL语句: executeQuery()或 executeUpdate() 注意:执行时不再需要传入SQL语句
-
ResultSetMetaData
-
why: 如果只有一个结果集,但不知道该结果集中有多少列,列的名字都是啥
-
编写通用的方法
public <T> T get(Class<T> clazz,String sql,Object...qrgs)
-
-
What: 是描述ResultSet的元数据对象。即从中可以获取到结果集中有多少列,列名是什么。。。
-
How:
-
①得到ResultSetMetaData对象:调用ResultSet的getMetaData()方法
-
//1.得到ResultSet对象 connection = (Connection) JDBCTools.getConnection(); preparedStatement = (PreparedStatement) connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); //2.得到ResultSetMetaData对象 ResultSetMetaData rsmd=(ResultSetMetaData) resultSet.getMetaDat();
-
-
②ResultSetMetaData对象有一些好用的方法
-
int getColumnLabel(int column) SQL语句中包含哪些列
-
String getColumnLabel(int column) 获取指定的列的别名,其中索引从1开始
//3.创建一个Map<String,Object>对象, 键:SQL查询的列的别名 值:列的值 Map<String,Object> values=new HashMap<>(); //4.处理结果集。利用ResultSetMetaData 填充3对应的Map对象 while(resultSet.next()) { for(int i=0;i<rsmd.getColumnCount();i++) { String columnLabel=rsmd.getColumnLabel(i+1); Object columnValue=resultSet.getObject(i+1); values.put(columnLabel, columnValue); } }
-
-
通用的查询方法
-
Why:查询时方法的逻辑类似,很多代码类似
-
What:
-
方法的签名
-
/**
* 通用的查询方法,可以根据传入的 SQL、Class 对象返回 SQL 对应的记录的对象
* @param clazz 描述对象的类型
* @param sql SQL 语句。可能带占位符
* @param args 填充占位符的可变参数
* @return
*/
public <T> T get(Class<T> clazz,String sql,Object...args){//....}
-
-
使用该方法
-
@Test public void testGet() { String sql="SELECT id,name,email,birth" +"FROM customers WHERE id=?"; Customer customer=get(Customer.class,sql,5); System.out.println(customer); sql = "SELECT flow_id flowId, type, id_card idCard, " + "exam_card examCard, student_name studentName, " + "location, grade " + "FROM examstudent WHERE flow_id = ?"; // System.out.println(sql); Student stu = get(Student.class, sql, 5); System.out.println(stu); }
-
-
-
How:
-
实现该方法需要综合使用反射,JDBC,JDBC元数据的知识
-
步骤
-
//1.得到ResultSet对象
-
//2.得到ResultSetMetaData对象
-
//3.创建一个Map<String,Object>对象, 键:SQL查询的列的别名 值:列的值
-
//4.处理结果集。利用ResultSetMetaData 填充3对应的Map对象
-
while(resultSet.next()) { for(int i=0;i<rsmd.getColumnCount();i++) { String columnLabel=rsmd.getColumnLabel(i+1); Object columnValue=resultSet.getObject(i+1); values.put(columnLabel, columnValue); } }
-
-
//5.若Map 不为空集,利用反射创建clazz对应的对象
-
//6.遍历Map对象,利用反射为clazz对象的对应属性赋值
-
if(values.size()>0) { entity=clazz.newInstance(); //6.遍历Map对象,利用反射为clazz对象的对应属性赋值 for(Map.Entry<String, Object> entry:values.entrySet()) { String fieldName=entry.getKey(); Object value=entry.getValue(); ReflectionUtils.setFieldValue(entity, fieldName, value); } }
-
-
-
-
流程图
*
-
通用方法代码
-
/** * 通用的查询方法,可以根据传入的 SQL、Class 对象返回 SQL 对应的记录的对象 * @param clazz 描述对象的类型 * @param sql SQL 语句。可能带占位符 * @param args 填充占位符的可变参数 * @return */ public <T> T get(Class<T> clazz,String sql,Object...args){ T entity=null; Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { //1.得到ResultSet对象 connection = (Connection) JDBCTools.getConnection(); preparedStatement = (PreparedStatement) connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); //2.得到ResultSetMetaData对象 ResultSetMetaData rsmd=(ResultSetMetaData) resultSet.getMetaData(); //3.创建一个Map<String,Object>对象, 键:SQL查询的列的别名 值:列的值 Map<String,Object> values=new HashMap<>(); //4.处理结果集。利用ResultSetMetaData 填充3对应的Map对象 while(resultSet.next()) { for(int i=0;i<rsmd.getColumnCount();i++) { String columnLabel=rsmd.getColumnLabel(i+1); Object columnValue=resultSet.getObject(i+1); values.put(columnLabel, columnValue); } } //5.若Map 不为空集,利用反射创建clazz对应的对象 if(values.size()>0) { entity=clazz.newInstance(); //6.遍历Map对象,利用反射为clazz对象的对应属性赋值 for(Map.Entry<String, Object> entry:values.entrySet()) { String fieldName=entry.getKey(); Object value=entry.getValue(); ReflectionUtils.setFieldValue(entity, fieldName, value); } } } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(resultSet, preparedStatement, connection); } return entity; }
-