JDBC-PreparedStatement

通用的查询方法

以面向对象的思想编写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;
      	}
      
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值