java数据库编程(5) 使用preparedStatement

本文详细介绍了PreparedStatement在Java中的使用方法,对比了其与Statement的区别,特别是在性能提升和防止SQL注入方面的优势。通过实例展示了如何使用PreparedStatement执行SQL语句,以及在用户验证场景下如何避免SQL注入攻击。
摘要由CSDN通过智能技术生成
  1. preparedStatement是一种带有占位符(?)的sql语句,它可以将预编译的sql语句存储起来,然后可以使用这个预编译好的sql语句多次高效地执行传入具体参数的sql语句。
  2. 例如执行 insert into table xxx values(1);  insert into table xxx values(2); ... 这样结构相同,只是具体的数据不通过的语句,就可以使用PreparedStatement对象将一个insert into table xxx valuse(?);预编译好,然后再在具体执行的时候调用PreparedMent对象的setInt(1,x);方法传入具体的值。   这里的1是指第一个?。
  3. 具体的讲解穿插在代码中。
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.Statement;
    import java.util.Properties;
    
    public class PreparedStatementTest {
        private String driver;
        private String  url;
        private String user;
        private String pass;
    
    //    通过读取属性问价来获得属性
        public void iniParam(String paramFile) throws Exception{
            Properties properties = new Properties();
    
    //       以输入流的方式打开属性文件
            properties.load(new FileInputStream(paramFile));
    
    //        依次读取属性文件里的各种属性
            driver = properties.getProperty("driver");
            url= properties.getProperty("url");
            user = properties.getProperty("user");
            pass = properties.getProperty("pass");
            Class.forName(driver);
        }
    
    //    这是通过常规的方式将一百条记录添加到表中。
        public void insertUserStatement() throws Exception{
            long start = System.currentTimeMillis();
            try(
    //                先获得数据库链接Connection对象,并且通过这个数据库链接创建Statement对象,在由statement对象来执行sql语句
                    Connection connection  = DriverManager.getConnection(url,user,pass);
                    Statement statement  = connection.createStatement()
                    ){
                for(int i=0; i<100; i++){
    //                执行一百次添加数据。
                    statement.executeUpdate("insert into insert100 values(i)");
                }
                System.out.println("使用Statement费时:" + (System.currentTimeMillis()-start));
            }
        }
    
    
    //    通过PreparedStatement来添加一百条记录
        public void inserUserPrepare() throws Exception{
            long start = System.currentTimeMillis();
            try(
    //                PreparedStatement同样是通过Connection对象来或获得的。
    //                具体的构造方法是将要执行的sql语句传进其构造方法里。但是要将具体的数据用?代替
    //                然后再在具体执行sql语句的时候将?代替成具体的值
                    Connection connection = DriverManager.getConnection(url,user,pass);
    
                    PreparedStatement preparedStatement =
                            connection.prepareStatement("insert into insert100 values(?)"))
                    {
                        for(int i=0; i<100; i++){
                            preparedStatement.setInt(1,i);
                            preparedStatement.execute();
                        }
                        System.out.println("使用PreparedStatement费时" + (System.currentTimeMillis() - start));
            }
    
        }
    
        public static void main(String args[]) throws Exception{
            PreparedStatementTest preparedStatementTest  = new PreparedStatementTest();
            preparedStatementTest.iniParam("mysql.ini");
            preparedStatementTest.insertUserStatement();a
            preparedStatementTest.inserUserPrepare();
        }
    }
    //运行上面程序,看到以下输出:
    //        使用Statement费时:5000
    //        使用PreparedStatement费时4094

     

  4. 使用PreparedStatement不仅可以提高效率,而且可以防止sql注入。我理解的sql注入是使用一般的sql语句处理过程中如果用户输入的内容不是合法信息,但是可以和系统预先设定的sql语句部分合成一条语法和逻辑都没有问题的sql语句。并让这条语句执行某种非法操作。

  5. 如下面这个例子,在不使用PreparedStatement的情况下,如果用户名输入‘or ture or'这样的内容的话,会显示登陆成功。

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.io.FileInputStream;
    import java.io.FileReader;
    import java.sql.*;
    import java.util.Properties;
    
    public class LoginFrame {
        private final String PROP_FILE = "mysql.ini";
        private String driver;
        private String url;
        private String user;
        private String pass;
    
        private JFrame jf = new JFrame("登陆");
        private JTextField userField = new JTextField(20);
        private JTextField passField = new JTextField(20);
        private JButton loginButton = new JButton("登录");
        public void init() throws  Exception{
            Properties connProp = new Properties();
            connProp.load(new FileInputStream(PROP_FILE));
            driver = connProp.getProperty("driver");
            url = connProp.getProperty("url");
            user = connProp.getProperty("user");
            pass = connProp.getProperty("pass");
            Class.forName(driver);
            loginButton.addActionListener(new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if(validate(userField.getText(), passField.getText())){
                        JOptionPane.showMessageDialog(jf, "登陆成功");
                    }else{
                        JOptionPane.showMessageDialog(jf, "登陆失败");
                    }
                }
            });
            jf.add(userField, BorderLayout.NORTH);
            jf.add(passField);
            jf.add(loginButton, BorderLayout.SOUTH);
            jf.pack();
            jf.setVisible(true);
        }
        private boolean validate(String userName, String userPass){
            String sql = "select * from students where Sname = '" + userName + "' and Sno= '" + userPass + "';";
            System.out.println(sql);
            try(
                    Connection connection = DriverManager.getConnection(url, user, pass);
                    Statement statement = connection.createStatement();
                    ResultSet rs = statement.executeQuery(sql))
            {
                if(rs.next()){
                    return true;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return false;
        }
    
    
        private boolean valicate1(String userName, String userPass){
            try(
                    Connection conn = DriverManager.getConnection(url, user, pass);
                    PreparedStatement pstmt = conn.prepareStatement(
                            "select * from students where Sname = ? and Sno = ?")){
                pstmt.setString(1, userName);
                pstmt.setString(2,userPass);
                try(
                        ResultSet rs = pstmt.executeQuery())
                {
                    if(rs.next()){
                        return true;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return false;
        }
    
    
    
        public static void main(String args[]) throws Exception{
            new LoginFrame().init();
        }
    
    
    
    
    
    }
    

    这是因为当输入 'or ture or'之后,“拼接而成”的sql语句为 

    select * from students where Sname = '‘or true or’' and Sno= '';
    

    这样的语句是返回true的。

  6. 当使用了PaparedStatememt之后,用户输入的内容只能是代替了‘’里的内容 ,所以也就不存在sql注入了。

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.io.FileInputStream;
    import java.io.FileReader;
    import java.sql.*;
    import java.util.Properties;
    
    public class LoginFrame {
        private final String PROP_FILE = "mysql.ini";
        private String driver;
        private String url;
        private String user;
        private String pass;
    
        private JFrame jf = new JFrame("登陆");
        private JTextField userField = new JTextField(20);
        private JTextField passField = new JTextField(20);
        private JButton loginButton = new JButton("登录");
        public void init() throws  Exception{
            Properties connProp = new Properties();
            connProp.load(new FileInputStream(PROP_FILE));
            driver = connProp.getProperty("driver");
            url = connProp.getProperty("url");
            user = connProp.getProperty("user");
            pass = connProp.getProperty("pass");
            Class.forName(driver);
            loginButton.addActionListener(new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if(valicate1(userField.getText(), passField.getText())){
                        JOptionPane.showMessageDialog(jf, "登陆成功");
                    }else{
                        JOptionPane.showMessageDialog(jf, "登陆失败");
                    }
                }
            });
            jf.add(userField, BorderLayout.NORTH);
            jf.add(passField);
            jf.add(loginButton, BorderLayout.SOUTH);
            jf.pack();
            jf.setVisible(true);
        }
        private boolean validate(String userName, String userPass){
            String sql = "select * from students where Sname = '" + userName + "' and Sno= '" + userPass + "';";
            System.out.println(sql);
            try(
                    Connection connection = DriverManager.getConnection(url, user, pass);
                    Statement statement = connection.createStatement();
                    ResultSet rs = statement.executeQuery(sql))
            {
                if(rs.next()){
                    return true;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return false;
        }
    
    
        private boolean valicate1(String userName, String userPass){
            try(
                    Connection conn = DriverManager.getConnection(url, user, pass);
                    PreparedStatement pstmt = conn.prepareStatement(
                            "select * from students where Sname = ? and Sno = ?")){
                pstmt.setString(1, userName);
                pstmt.setString(2,userPass);
                try(
                        ResultSet rs = pstmt.executeQuery())
                {
                    if(rs.next()){
                        return true;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return false;
        }
    
    
    
        public static void main(String args[]) throws Exception{
            new LoginFrame().init();
        }
    
    
    
    
    
    }
    

  7. 总的看来PreparedStetement比一般的sql语句处理有两个有点

    1. 它是采用预编译的原理,性能更好。

    2. 可以防止sql注入,安全性更高。

这是我看李刚编著的《疯狂Java讲义》后总结出来的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值