javawebday44(预编译设置 JdbcUtils 获取连接 JdbcUtils工具类)

PreparedStatement
    Statement接口的子接口
    强大之处
        防SQL攻击
        提高代码的可读性、可维护性
        提高效率
    学习PreoaredStatement的用法
        如何得到PreparedStatement对象
            给出SQL模版
            调用Connection的PreparedStatement preparedStatement(String sql 模版)
            调用pstmt的setXxx()系列方法sql模版中的?赋值
            调用pstmt的executeUpdate()或executeQuery(),但它的方法都没有参数
    预处理的原理
        服务器的工作
            校验sql语句的语法
            编译:一个与函数相似的东西
            执行:调用函数
        PreparedStatement(预编译)
            前提:连接的数据库必须支持预处理。几乎没有不支持的
            每个pstmt都与一个sql模版绑在一起,先把sql模版给数据库,数据库先进行校验,再进行编译。执行时只是把参数传递过去而已
            若二次执行时,就不用再次校验语法,也不用再次编译。直接执行

MySQL的预编译功能
预编译的好处
    当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语法格式是否正确,然后把SQL语句编译成可执行的函数,最后才是执行SQL语句。
    其中校验语法,和编译所花的事件可能比执行SQL语句花的时间还要多

    如果我们需要执行多次insert语句,但知识每次插入的值不同,MySQL服务器也是需要每次去校验SQL语句的语法格式,以及编译,就浪费了太多的事件,如果使用预编译功能,那么只对SQL语句进行一次语法校验和编译,所以效率要高

MySQL执行预编译
    MySQL执行预编译分为三步
        执行预编译语句:例如:prepare myfun from 'select * from t_book where bid=?'
        设置变量 例如 set @str='b1'
        执行语句例如 execute myfun using @str
    如果需要再次执行myfun那么就不再需要第一步,即不需要再编译语句了
        设置变量 例如 set @str='b2'
        执行语句 例如 execute myfun using@str
    通过查看MySQL日志可以看到执行的过程

使用Statement执行预编译
    使用Statement执行预编译就是把上面的SQL语句执行一次     

userServerPrepstmts参数
    默认使用PreparedStatement是不能执行预编译的,这需要在url中给出useServerPrepStmts=true 参数(MySQL Server 4.1之前的版本是不支持预编译的,二Connector/J在5.0.5以后的版本,默认是没有开启预编译功能的)
    例如:jdbc:mysql://localhost:3306/db1?useServerPrepStmts=true
    这样才能保证mysql驱动会先把SQL语句发送给服务器进行预编译,然后在执行executeQuery()时知识把参数发送给服务器

cachePrepStmts参数
    当使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,这是因为驱动没有缓存编译后的函数key,导致二次编译。如果希望缓存编译后函数的key,那么就要设置cachePrepStmts参数为true
    jdbc:mysql://localhost:3306/db1?useServertPrepStmts=true&cachePrepStmts=true    
打开批处理
    MySQL的批处理也需要通过参数来打开 rewriteBatchedStatements=true               
1、什么是SQL攻击
    在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句。例如用户在登陆时输入的用户名和密码都是为SQL语句的片段
2演示SQL攻击
    首先需要创建一张用户表,用来存储用户的信息   
/**
 *PreparedStatement 
 */
public class Demo3 {
    /**
     * 登录
     * 使用username和password去查询数据
     * 若查询出结果集,说明正确!返回true
     * 若查不出结果,说明用户名或密码错误,返回false
     * @throws Exception 
     */
    public boolean login(String username,String password) throws Exception{
        /*
         * 一、得到Connection
         * 二、得到Statement
         * 三、得到ResultSet
         * 四、rs.next()返回的是什么,我们就返回什么
         */
        //准备四大参数
        String driverClassName = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/db1";
        String mysqlUsername = "root";
        String mysqlPassword = "123"; 
        //加载驱动类
        Class.forName(driverClassName);
        //得到Connection
        Connection con = DriverManager.getConnection(url,mysqlUsername,mysqlPassword);
        //得到Statement
        Statement stmt = con.createStatement();
        //给出sql语句,调用stmt的executeQuery(),得到ResultSet
        String sql = "select * from t_user where username ='"+username+"'and password='"+password+"'";
        System.out.println(sql);
        ResultSet rs = stmt.executeQuery(sql);

        return rs.next();
    }
    /**
     * SQL攻击
     * @throws Exception
     */
    @Test
    public void fun1() throws Exception{
        //select * from t_user where username ='a' or 'a'='a'and password='a' or 'a'='a'
        String username = "a' or 'a'='a";
        String password = "a' or 'a'='a";
        boolean bool =login(username,password);
        System.out.println(bool);
    }
    public boolean login2(String username,String password) throws Exception{
        /*
         * 一、得到Connection
         * 二、得到Statement
         * 三、得到ResultSet
         * 四、rs.next()返回的是什么,我们就返回什么
         */
        //准备四大参数
        String driverClassName = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/db1";
        String mysqlUsername = "root";
        String mysqlPassword = "123"; 
        //加载驱动类
        Class.forName(driverClassName);
        //得到Connection
        Connection con = DriverManager.getConnection(url,mysqlUsername,mysqlPassword);

        
        /*
         * 得到PreparedStatement
         * 1、给出sql模版:所有的参数使用?来替代
         * 2、调用Connection方法,得到PreparedStatement
         */
        String sql ="select * from t_user where username=? and password=?";
        PreparedStatement pstmt = con.prepareStatement(sql);

        /*
         * 二、为参数赋值 
         * 多了少了都不行会报异常
         */
        pstmt.setString(1, username);//给第一个问号赋值,值为username
        pstmt.setString(2, password);//给第二个问号赋值,值为password

        ResultSet rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句
        return rs.next();
    }
    @Test
    public void fun2() throws Exception{
        //select * from t_user where username ='a' or 'a'='a'and password='a' or 'a'='a'
        String username = "a' or 'a'='a";
        String password = "a' or 'a'='a";
        boolean bool =login2(username,password);
        System.out.println(bool);
    }
    /**
     *测试JdbcUtils.getConnection()
     * @throws SQLException 
     * @throws IOException 
     * @throws ClassNotFoundException 
     */
    @Test
    public void fun3() throws ClassNotFoundException, IOException, SQLException{
        Connection con = JdbcUtils.getConnections();
        System.out.println(con);

        Connection con1 = JdbcUtils.getConnections();
        System.out.println(con1);

    }
}
public class JdbcUtils {
    public static Connection getConnections() throws IOException, ClassNotFoundException, SQLException{
        /*
         * 1.加载配置文件
         * 2、加载驱动类
         * 3、调用DriverManager.getConnection()
         */
        //加载配置文件
        InputStream in = JdbcUtils.class.getClassLoader()
                .getResourceAsStream("dbconfig.properties");
        Properties props = new Properties();
        props.load(in);
        //加载驱动类
        Class.forName(props.getProperty("driverClassName"));
        //得到Connection
        return DriverManager.getConnection(props.getProperty("url"),
                props.getProperty("username"),
                props.getProperty("password"));
    }
}

dbconfig.properties
这里写图片描述

/**
 * v1.0
 * @author Administrator
 *
 */

public class JdbcUtils {
    private static Properties props = null;
    //只在JdbcUtils类被加载一次
    static{
        //props进行初始化,即加载dbconfig.properties文件到props对象中
        try {
            /*
             * 1.加载配置文件
             * 2、加载驱动类
             * 3、调用DriverManager.getConnection()
             */
            //加载配置文件
            InputStream in = JdbcUtils.class.getClassLoader()
                    .getResourceAsStream("dbconfig.properties");
            props = new Properties();
            props.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            //加载驱动类
            Class.forName(props.getProperty("driverClassName"));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    //获取连接
    public static Connection getConnections() throws SQLException{

        //得到Connection
        return DriverManager.getConnection(props.getProperty("url"),
                props.getProperty("username"),
                props.getProperty("password"));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值