使用PreParedStatement和ResultSet

操作和访问数据库

在java.sql包中有3个接口分别定义了对数据库的调用的不同方式:

Statement:用于执行静态的SQL语句并返回所生成结果的对象

PreparedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效的执行该语句

CallableStatement:用于执行SQL存储过程

Statement

使用:通过Connection对象的createStatement方法创建Statement对象,该对象用于执行静态的SQL语句,并且返回执行结果。

Statement接口中执行SQL的方法

  • int executeUpdate(String sql)  throws SQLException 执行给定的SQL语句,这可能是INSERTUPDATE ,或DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。
  • ResultSet executeQuery(String sql) throws SQLException 执行给定的SQL语句,返回单个ResultSet对象。执行SELECT语句。
package com.statementANDresultset;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

/**
 * @author 承夕
 * @date 2020/2/26 0026 - 9:58
 * @contact:https://github.com/chengxi0
 */
public class StatementResultSetDemo1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名");
        String user_in = scanner.nextLine();
        System.out.println("请输入密码");
        String password_in = scanner.nextLine();

        Connection connection = null ;
        Statement statement = null ;

        try {
             //加载配置文件
            InputStream inputStream = StatementResultSetDemo1.class.getClassLoader().getResourceAsStream("jdbc" +
                 ".properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            //获取配置文件信息
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String url = properties.getProperty("url");
            String driverClass = properties.getProperty("driverClass");

            //加载注册驱动
            Class.forName(driverClass);

            //获取连接对象
           connection = DriverManager.getConnection(url, user, password);

            //获取Statement对象
            statement = connection.createStatement();

            //定义执行的SQL语句
           /* String sql1 = "insert into `user` (name , password , address , phone) values ('zhangsan','123456','gd'," +
                    "'18888888888');";
            String sql2 = "insert into `user` (name , password , address , phone) values ('lisi','234567','gd'," +
                    "'18888886666');";*/
            String sql3 = "select `name` ,`password` from `user` where `name`='" + user_in + "' and `password` ='" + password_in + "';";

           /* int i1 = statement.executeUpdate(sql1);
            int i2 = statement.executeUpdate(sql2);*/
            boolean b1 = statement.execute(sql3);

            if (b1) {
                System.out.println("登录成功");
            }else {
                System.out.println("登录失败");
            }
            
           /* System.out.println(i1);
            System.out.println(i2);*/

        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

使用Statement的缺点:

  • 问题一:存在拼串操作,繁琐
  • 问题二:存在SQL注入问题(如上图所示),明明用户名错了,却还能登录进去

解决办法:

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(Statement扩展而来) 取代 Statement 就可以了。

PreparedStatement

获取:调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象

使用:PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引( 1 开始),第二个是设置的 SQL 语句中的参数的值

好处

  • 代码可读性和可维护性大大提高。
  • 它表示一条预编译的SQL语句,因此器有可能被重复利用,所以在被DBServer的编译器编译后的执行代码被缓存下来,下次使用的时候就不需要再编译,只要将参数直接传进去即可
  • PreparedStatement可以方式SQL注入问题
package com.statementANDresultset;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.PropertyPermission;

/**
 * @author 承夕
 * @date 2020/2/28 0028 - 9:07
 * @contact:https://github.com/chengxi0
 */
public class StatementResultSetDemo4 {
    public static void main(String[] args)  {
        Connection connection = null ;
        PreparedStatement preparedStatement = null ;
        try {
        //加载配置文件进内存
        InputStream inputStream = StatementResultSetDemo4.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();

            properties.load(inputStream);
            //获取配置文件信息
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String url = properties.getProperty("url");
            String driverClass = properties.getProperty("driverClass");

            //加载注册驱动
            Class.forName(driverClass);

            //获取连接
           connection = DriverManager.getConnection(url, user, password);

            //获取PreparedStatement对象
            preparedStatement = connection.prepareStatement("insert into `user` (`name`,`password`,`address`,`phone`) values (? ,? , ? ,?) ;");
            preparedStatement.setString(1,"王五");
            preparedStatement.setString(2,"345678");
            preparedStatement.setString(3,"cx" );
            preparedStatement.setString(4,"13243568456");

            int i = preparedStatement.executeUpdate();
            System.out.println(i);

        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ResultSet

使用:通过Statement或者PreparedStatement对象的executeQuery()方法,

注意:

  • 查询结果就是一个结果集对象.ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集ResultSet 接口由数据库厂商提供.
  • 实现 ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面
  • ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体
  • 当指针指向一行时, 可以通过调用 getXxx(int index) getXxx(int columnName) 获取每一列的值,索引是从1开始的

ResultSetMetaData

作用:通过ResultSet对象的getMetaData()方法获取,用于获取关于Result对象中列的类型和属性信息的对象

常用的方法:

  • String getColumnName(int column) 获取指定列的名称, column - 第一列是1,第二列是2,...
  • String getColumnLabel(int column) 获取指定列的别名
  • int getColumnCount() 返回此 ResultSet对象中的列数
  • String getColumnTypeName(int column)检索指定列的数据库特定类型名称
  • int getColumnDisplaySize(int column)指定指定列的正常最大宽度(以字符为单位)
  • int isNullable(int column)表示指定列中的值是否可以为null值,返回值对应columnNoNulls columnNullable  columnNullableUnknown 的静态变量之一
  • boolean isAutoIncrement(int column)指示指定列是否自动编号

JDBC工具类

package com.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @author 承夕
 * @date 2020/2/28 0028 - 9:50
 * @contact:https://github.com/chengxi0
 */
public class JDBCUtils {
    public static Connection getConnection() {
        Connection connection = null ;
        try {
        InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        properties.load(inputStream);


        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driverClass = properties.getProperty("driverClass");

        //加载注册驱动
            Class.forName(driverClass);
        connection = DriverManager.getConnection(url, user, password);


        } catch (IOException | SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return connection ;
    }

    public static void closeResource(Connection conn, Statement stm, ResultSet st) {
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }if (stm != null) {
            try {
                stm.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.statementANDresultset;

import com.domain.User;
import com.utils.JDBCUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * @author 承夕
 * @date 2020/2/28 0028 - 10:19
 * @contact:https://github.com/chengxi0
 */
public class StatementResultSetDemo5 {
    public static void main(String[] args) {
        String sql = "select * from `user` ;";
        ArrayList<User> users = StatementResultSetDemo5.initObject(sql);
        for (User u : users) {
            System.out.println(u);
        }

    }

    public static ArrayList<User> initObject(String sql, Object...args) {
        ArrayList<User> users = new ArrayList<>();

        Connection connection = null ;
        PreparedStatement pstm = null ;
        ResultSet rs = null ;

        try {
            //利用工具类获取数据库连接
            connection = JDBCUtils.getConnection();

            //获取PreparedStatement
            pstm = connection.prepareStatement(sql);

            //填充占位符
            for (int i = 1;  i <= args.length ; i ++) {
                System.out.println(args[i -1]);
                pstm.setObject(i, args[ i - 1 ]);
            }

            //获取结果集
            rs = pstm.executeQuery();

            Class<User> userClass = User.class;
            User user = null ;

            while (rs.next()) {
                user = userClass.newInstance();
              /*  //利用反射进行对成员域初始化
                Field name = userClass.getDeclaredField("name");
                //忽略访问权限
                name.setAccessible(true);
                name.set(user,rs.getString(1));*/
                Field[] fields = userClass.getDeclaredFields();
                int i = 2 ;
                for (Field f : fields) {
                    //忽略访问权限
                    f.setAccessible(true);
                    f.set(user, rs.getString(i++));
                }
                users.add(user);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(connection,pstm,rs);
        }
        return users ;
    }
}

注意:

  • 利用传参中的Object...args这个可变参数,进行填充占位符?,这个方法不错.
  • 字段,关键字不能填充到占位符
发布了55 篇原创文章 · 获赞 4 · 访问量 1056

猜你喜欢

转载自blog.csdn.net/weixin_45062761/article/details/104510644