Java教程

9.24JavaWeb之PreparedStatement

本文主要是介绍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;
    }

 

这篇关于9.24JavaWeb之PreparedStatement的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!