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

 

posted @ 2021-10-05 19:48  俊king  阅读(273)  评论(0编辑  收藏  举报