zoukankan      html  css  js  c++  java
  • 9.24JavaWeb之PreparedStatement

    9.24JavaWeb之PreparedStatement

    PreparedStatement和Statement

    工作原理图:

     

    PreparedStatement是Statement的一个子接口

    Connection连接的四个条件

    条件:

    • 使用的驱动--->使用xml或者其他配置文件进行管理

    • URL--->连接的ip和端口号和数据库

    • 用户名

    • 密码

    封装获取连接的过程:

    getConnection()

        /*获取数据库连接*/
       /**
        * 获取数据库连接
        * @return
        */
       public static Connection getConnection() throws SQLException {
           /*从配置文件当中去读数据库连接所需要的数据--->通过获取系统类加载器来读取配置文件*/
           InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("Localhost.properties");
           //创建Properties引用
           Properties prop = new Properties();
           try {
               //读取流文件
               prop.load(is);
          }catch (IOException e){
               System.out.println("读取流文件的时候抛出的异常!");
               e.printStackTrace();
          }

           //获取文件当中的属性
           String driverClass = prop.getProperty("DRIVER");
           String url = prop.getProperty("URL");
           String username = prop.getProperty("USERNAME");
           String password = prop.getProperty("PASSWORD");

           try {
               //反射获取mysql驱动
               Class.forName(driverClass);
          }catch (ClassNotFoundException e){
               System.out.println("获取数据库驱动抛出的异常!");
               e.printStackTrace();
          }

           /*获取Connection对象引用*/
           Connection conn = DriverManager.getConnection(url, username, password);

           return conn;
      }

    closeResource()

        /*关闭资源类*/
       public static void closeResource(Connection conn, PreparedStatement ps){
           /*后打开的先关闭*/
           try {
               if (ps!=null){
                   ps.close();
              }
          }catch (SQLException e){
               System.out.println("关闭ps抛出的异常!");
               e.printStackTrace();
          }
           try {
               if (conn!=null){
                   conn.close();
              }
          }catch (SQLException e){
               System.out.println("关闭连接抛出的异常!");
               e.printStackTrace();
          }
      }

    将改、查的过程封装

    将不确定的信息参数化:

    使用可变形参将需要参数化的地方参数化:

        /*统一的修改方法*/
       //由于通配符不知道有多少所以设置成可变形参
       public void upload(String sql, Object ...args){
           //定义属性
           Connection conn = null;
           PreparedStatement ps = null;

           //获取数据库连接
           try {
               conn = JDBCUtils.getConnection();

               //创建PreparedStatement对象携带sql去进行操作
               ps = conn.prepareStatement(sql);

               //填充占位符
               /*
               sql当中占位符的个数应该与可变形参的长度一致
               可变形参当成数组
                */
               for (int i = 1; i < args.length; i++){
                   ps.setObject(i, args[i]); //当心参数声明错误
              }

               //执行语句
               ps.execute();
          }catch (Exception e){
               e.printStackTrace();
          }

           //关闭资源
           JDBCUtils.closeResource(conn, ps);
      }

    测试:

        @Test
       public void testCommonUpdate(){
    //       String sql = "delete from customers where `id` = 1;";
    //       upload(sql, 3);

           String sql = "update `users` set `name` = ? where `id` = ?;";
           upload(sql, "Jun", 2);
      }

    JavaSQL对应数据类型转换表:

    Java类型SQL类型
    boolean Bit
    byte TinyInt
    short Smallint
    int Integer
    long Bigint
    String Char,Varchar,LongVarchar
    byte array Binary,Var Binary
    java.sql.Date Date
    java.sql.Time Time
    java.sql.TimeStamp TimeStamp

    针对不同的表进行查询操作:

        @Test
       public void testQueryNo1 () throws SQLException {
           Connection conn = null;
           PreparedStatement ps = null;
           ResultSet rs = null;

           try {
               //获取连接,生成连接对象
               conn = JDBCUtils.getConnection();
               //sql
               String sql = "select `id`,`name`,`email`,`photo` from customers where `id` = ?;";
               //预编译
               ps = conn.prepareStatement(sql);
               ps.setObject(1, 1);

               //执行sql语句并返回结果集
               rs = ps.executeQuery();

               //处理结果集--->类似迭代器--->调用has/next方法(相当于有一个指针指向了结果集,要判断是否有内容)迭代器中的has和next方法返回一个布尔类型的值,表示下一个位置有没有值
           /*
           结果集当中有相关的方法获取到具体的字段的值
            */
               if (rs.next()){
                   //判断结果集的next方法返回的布尔类型进而判断是否取出值
                   int id = rs.getInt(1);
                   String name = rs.getString("Jun");
                   String email = rs.getString("JunkingBoy@163.com");
                   Date birth = rs.getDate(19990909);

                   //直接显示
                   System.out.println("id:" + id + "name:" + name + "email:" + email + "birthday:" + birth);

                   //封装到一个数组当中进行输出
                   Object[] resp = new Object[]{id, name, email, birth};

                   //封装到一个集合类的对象当中--->相当于专门的定义一个结构体用于输出
                   /*将数据封装成一个对象*/
                   Customer cus = new Customer(id, name, email, birth);

                   /*打印--->调用toString方法*/
                   System.out.println(cus);
              }
          }catch (Exception e){
               e.printStackTrace();
          }finally {
               //关闭资源--->rs也需要关闭
               JDBCUtils.closeResource(conn, ps, rs);
          }
      }

    ORM思想:一个Java类对应一个表格

    package JDBCStatementCRUD;

    import java.util.Date;

    /**
    * 相当于一个结构体,用于存放某一个表当中的记录
    * ORM的编程思想:
    * 1、一个数据表对应一个Java类
    * 2、表中的一条记录对应一个Java类的一个对象
    * 3、表中的一个字段对应Java类的一个属性
    * @since JDk 1.8
    * @date 2021/09/24
    * @author Lucifer
    */
    public class Customer {
       /*属性字段私有化*/
       private int id;
       private String name;
       private String email;
       private Date birth;

       /*生成构造器*/
       public Customer() {
      }

       public Customer(int id, String name, String email, Date birth) {
           this.id = id;
           this.name = name;
           this.email = email;
           this.birth = birth;
      }

       public int getId() {
           return id;
      }

       public String getName() {
           return name;
      }

       public String getEmail() {
           return email;
      }

       public Date getBirth() {
           return birth;
      }

       public void setId(int id) {
           this.id = id;
      }

       public void setName(String name) {
           this.name = name;
      }

       public void setEmail(String email) {
           this.email = email;
      }

       public void setBirth(Date birth) {
           this.birth = birth;
      }
    }

    指定查询的字段进行查询:

        @Test
       public void testQueryNo1 () {
           Connection conn = null;
           PreparedStatement ps = null;
           ResultSet rs = null;

           try {
               //获取连接,生成连接对象
               conn = JDBCUtils.getConnection();
               //sql
               String sql = "select `id`,`name`,`email`,`photo` from customers where `id` = ?;";
               //预编译
               ps = conn.prepareStatement(sql);
               ps.setObject(1, 1);

               //执行sql语句并返回结果集
               rs = ps.executeQuery();

               //处理结果集--->类似迭代器--->调用has/next方法(相当于有一个指针指向了结果集,要判断是否有内容)迭代器中的has和next方法返回一个布尔类型的值,表示下一个位置有没有值
               /*
               结果集当中有相关的方法获取到具体的字段的值
                */
               if (rs.next()){
                   //判断结果集的next方法返回的布尔类型进而判断是否取出值
                   int id = rs.getInt(1);
                   String name = rs.getString("Jun");
                   String email = rs.getString("JunkingBoy@163.com");
                   Date birth = rs.getDate(19990909);

                   //直接显示
                   System.out.println("id:" + id + "name:" + name + "email:" + email + "birthday:" + birth);

                   //封装到一个数组当中进行输出
                   Object[] resp = new Object[]{id, name, email, birth};

                   //封装到一个集合类的对象当中--->相当于专门的定义一个结构体用于输出
                   /*将数据封装成一个对象*/
                   Customer cus = new Customer(id, name, email, birth);

                   /*打印--->调用toString方法*/
                   System.out.println(cus);
              }
          }catch (Exception e){
               e.printStackTrace();
          }finally {
               //关闭资源--->rs也需要关闭
               JDBCUtils.closeResource(conn, ps, rs);
          }
      }

    通用的查询方式:

    关键点:

    1. 根据传入的sql语句判断需要查询的字段进行查询

    2. 因为ORM的思想,一个表对应一个JavaBean对象。所以需要根据传入的sql要获取传入的列

    3. 通过元数据获取列数,循环获取查询的列名,在通过反射运行时类的属性与列名进行比较,相同的赋值--->这不是判断而是同时获取

    4. 没有查询到的属性为null

        /**
        * 针对Customers表的通用的查询操作--->查询的字段数量不一样
        * 1、获取列数--->结果集元数据
        * 2、获取列名--->结果集元数据
        * 3、获取需要查询多少个字段--->反射的方式来获取--->动态获取对象当中的属性--->运行时类加载器
        */
       @Test
       public Customer queryForCustomers(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();
               //处理结果集--->希望返回一个对象,所以返回表对象
               //因为传入的sql查询的字段决定了查询的结果集,所以要想办法拿到结果集当中的列--->在result接口中将列封装在结果集的元数据当中
               ResultSetMetaData rsmd = rs.getMetaData(); //--->获取结果集的元数据(修饰结果集的元数据)--->类比元注解,修饰现有数据的一个数据--->通过结果集的元数据获取结果集中的列数
               int columnCount = rsmd.getColumnCount(); //--->获取列数
               //查询一条数据,用if,多条用while
               if (rs.next()) {
                   //new对象
                   Customer cust = new Customer(); //--->查询到结果了造对象,所以写到if里面
                   //循环获取列--->类似操作excel的方法
                   //这个是处理一行结果集,处理一行数据中的每一个列
                   for (int i=0; i<columnCount; i++) {
                       Object value = rs.getObject(i+1); //--->获取到该字段的值了(列值)
                       //--->JDBC当中最困难的一块(拿到数据了以后封装到一个对象当中,按照拿到的属性赋值)--->构造器或者set方法
                   /*
                   1、用空参的构造器new一个对象
                   2、看查询什么,查询的对象就set方法放进去
                   3、给cust对象指定的某个属性赋值为value--->找到并且判断是哪个属性--->用结果集当中的属性对应到对象当中的属性
                   获取结果集当中的列名
                    */

                       //获取每个列的列名(结果集的元数据去拿)--->动态获取--->通过反射的方法获取
                       String columnName = rsmd.getColumnName(i+1); //--->列名

                       //给cust对象当中的columnName的属性赋值为columValue--->通过反射去赋值
                   /*
                   1、在Customer类当中找columnName的属性
                   2、把属性对应对象的成员赋值给成员
                   调用运行时类的指定属性--->反射
                    */
                       Field field = Customer.class.getDeclaredField(columnName);
                       //属性可能是私有的属性
                       field.setAccessible(true); //--->设置私有的属性能访问
                       field.set(cust, value);
                       /*上述是最困难也是最重要的点--->将customer对象叫columnName名的属性赋值给列值*/
                       /*通过反射的方式去动态实现,因为不知道具体要查多少个值*/
                  }
                   return cust;
              }
          }catch (Exception e) {
               e.printStackTrace();
          }finally {
               //关闭资源
               JDBCUtils.closeResource(conn, ps, rs);
          }
           return null;
      }

     

    It's a lonely road!!!
  • 相关阅读:
    【译】用 Rust 实现 csv 解析-part3
    【译】用 Rust 实现 csv 解析-part2
    【译】用 Rust 实现 csv 解析-part1
    【译】Rust 中的 char 和 Go 中的 rune 有什么区别?
    【译】TCP/IP 网络编程基础系列-数值编码
    【译】我最喜欢的 Rust 函数签名
    Rust 学习之运算符重载
    java.util.ConcurrentModificationException: null 问题分析解决
    2020年
    科目三夜间灯光模拟
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/15369367.html
Copyright © 2011-2022 走看看