JDBC与Java数据库、SQL注入

JDBC:java与数据库交互的技术

API:接口,类 (来自于Java.Sql包)

  • DriverManager:管理JDBC驱动程序,提供方法获取与数据库的连接
  • SqlException:数据库操作相关的异常
接口:
  • Connection:与数据库特定的连接(会话)--对象,在连接上下文中执行SQL语句并返回结果
  • PreparedStatement:预编译的Sql语句对象
  • Statement:执行静态的Sql语句对象
  • ResultSet:数据库结果集的数据表(接数据库数据返回的结果)
  • CollableStatement:执行存储过程

JDBC程序开发步骤

  1. 引入驱动jar
  2. 加载驱动
//加载驱动 Mysql版本不变 这条语句不变

Class.forName("驱动名称");

Class.forName("com.mysql.jdbc.Driver");
  1. 建立与数据库的连接
  • 方法:getConnection(String url, String user, String password)
  • url:连接路径
  1. 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
  2. 例子:jdbc:mysql://localhost:3306/scott
细节问题:

如果连接的是本机mysql服务器,并且mysql服务器默认端口是3306,则url可写为:jdbc:mysql:///数据库名称

  • user:数据库的用户名
  • password:密码
//连接 dbc:mysql:// 不变
//DriverManager.getConnection("url","用户名","密码")
//url:jdbc:mysql://主机名或IP地址(localhost):端口号/连接名
conn = DriverManager.getConnection("jdbc:mysql://主机名或IP地址:端口号/连接名", "用户名", "用户密码");

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/scott", "root", "123456");

  1. 构建Sql语句
//st = conn.createStatement();

//为防止发生SQL注入问题
ps = conn.preparedStatement();
  1. 执行Sql语句
  • 在查询时,连接字符串时用' '
//查询功能并接收
rs = st.executeQuery("select * from dept where deptno = 10");

为防止发生SQL注入问题:使用prepareStatement()方法

  • 使用PreparedStatement 在查询时用 代替
  • 给参数赋值

setXxx(要赋值的参数的索引(索引从1开始),要赋值的数据):方法名称由数据类型决定

//使用PreparedStatement 在查询时用?代替
ps = conn.prepareStatement(" select * from emp where ename like ? ");

//给参数赋值
//setXxx(要赋值的参数的索引(索引从1开始),要赋值的数据):方法名称由数据类型决定
String ename = new Scanner(System.in).nextLine();
ps.setString(1,ename);
//执行Sql数据,返回接收的数据
rs  = ps.executeQuery();
注意:

进行数据的增删改时,调用ps.executeUpdate();,不需要写 rs

  1. 获取查询结果(遍历)
 //遍历 调用next方法:移动结果集的指针
 //getXxx:参数是结果集的列名,根据结果列的数据类型对应的方法(结果列的索引值从1开始)

 if(rs.next()) {
 System.out.println(rs.getInt("deptno")+" "+rs.getString("dname")+" "+rs.getString("loc"));
}else {
System.out.println("没有数据");
}
Statement 栗子:
public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs  = null;
        try {
            //加载驱动 Mysql版本不变 这条语句不变
            Class.forName("com.mysql.jdbc.Driver");
            
            //连接 dbc:mysql:// 不变
            //DriverManager.getConnection("url","用户名","密码")
            //url:dbc:mysql://主机名或IP地址:端口号/连接名
             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/scott", "root", "123456");
        
            //根据部门编号查询部门数据
            st = conn.createStatement();
            
            //查询功能并接收
           rs = st.executeQuery("select * from dept where deptno = 10");
           
           //遍历 调用next方法:移动结果集的指针
           //getXxx:参数是结果集的列名,根据结果列的数据类型对应的方法(结果列的索引值从1开始)
           if(rs.next()) {
              System.out.println(rs.getInt("deptno")+" "+rs.getString("dname")+" "+rs.getString("loc"));
           }else {
               System.out.println("没有数据");
           }
            
        } catch (ClassNotFoundException e) { //编译异常
            e.printStackTrace();
        } catch (SQLException e) {//数据库操作相关的异常
            e.printStackTrace();
        }finally {
         try {
             //关闭资源
            conn.close();
            st.close();
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
  1. 依次关闭资源
 //关闭资源(连接--接收)
conn.close();
st.close();
rs.close();

SQL注入问题

当JDBC数据库交互时,用户传入的条件导致SQL语句发生变更,从而得到的结果不是用户想要的

问题的产生:

因为使用的是Statement接口执行静态的SQL语句

问题的解决

使用 PreparedStatement (预编译)代替 Statement

注意事项
  1. 使用PreparedStatement 在查询时用 ?代替
ps = conn.prepareStatement("select * from dept where dname = ?");

2.给参数赋值

  • setXxx(要赋值的参数的索引(索引从1开始),要赋值的数据):方法名称由数据类型决定
ps.setString(1, dname); 
  1. 接收数据
rs  = ps.executeQuery();
PreparedStatement :查询的 栗子:
public static void main(String[] args) {
        // 根据部门名称查询部门数据,根据 部门名称从控制台输入
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs  = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/scott", "root", "123456");
             //使用PreparedStatement 在查询时用?代替
             ps = conn.prepareStatement("select * from dept where dname = ?");
             
             //从控制台输入部门编号
             System.out.println("请输入一个要查询的部门名称:");
             String dname = new Scanner(System.in).nextLine();
             
             //给参数赋值
             //setXxx(要赋值的参数的索引(索引从1开始),要赋值的数据):方法名称由数据类型决定
               ps.setString(1, dname); 
               rs  = ps.executeQuery();
               //遍历 调用next方法:移动结果集的指针
               //getXxx:参数是结果集的列名,根据结果列的数据类型对应的方法(结果列的索引值从1开始)
             if(rs.next()) {
                  System.out.println(rs.getInt("deptno")+" "+rs.getString("dname")+" "+rs.getString("loc"));
            
               }else {
                   System.out.println("没有数据");
               }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            try {
                conn.close();
                ps.close();
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
    
PreparedStatement :增删改的 栗子:
public static void main(String[] args) {
        // 根据员工编号,修改员工的 工资和奖金,参数从控制台输入
        Connection conn = null;
        PreparedStatement ps = null;
    
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/scott", "root", "123456");
            ps = conn.prepareStatement("update emp set sal = ?,comm = ? where empno = ?");
            System.out.println("请输入员工工资:");
            double sal = new Scanner(System.in).nextDouble();
            System.out.println("请输入员工奖金: ");
            double comm = new Scanner(System.in).nextDouble();
            System.out.println("请输入员工编号: ");
            int empno = new Scanner(System.in).nextInt();
            ps.setDouble(1, sal);
            ps.setDouble(2, comm);
            ps.setInt(3, empno);
            ps.executeUpdate();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            try {
                conn.close();
                ps.close();
            
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

将Util包的Date转换成Sql包的Date

//将字符串转换成Date型日期
String strDate = "1985-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date utilDate = sdf.parse(strDate);
//导入util包日期
Date now = new Date();
//将util包的日期转换成sql包日期
//getTime():返回毫秒数
java.sql.Date sqlDate = new java.sql.Date(now.getTime());
//将sql包的日期传入
ps.setDate(4,sqlDate );
完整栗子
public static void main(String[] args) {
                //自增的方式
                Connection conn = null;
                PreparedStatement ps = null;
            
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/scott", "root", "123456");
                    ps = conn.prepareStatement("insert into emp(ename,job,mgr,hiredate,sal,comm,deptno) "
                            + " values(?,?,?,?,?,?,?)");

                    ps.setString(1, "test7");
                    ps.setString(2, "MANAGER");
                    ps.setInt(3, 7369);
                    
                    //将字符串转换成Date型日期
                    String strDate = "1985-01-01";
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date utilDate = sdf.parse(strDate);
                    //导入util包日期
                    Date now = new Date();
                    //将util包的日期转换成sql包日期
                    //getTime():返回毫秒数
                    java.sql.Date sqlDate = new java.sql.Date(now.getTime());
                    //将sql包的日期传入
                    ps.setDate(4,sqlDate );
                    
                    ps.setDouble(5, 5600);
                    ps.setDouble(6, 8000);
                    ps.setInt(7, 10);
                    //执行SQL
                     ps.executeUpdate();
                    
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (ParseException e) {
                    e.printStackTrace();
                }finally {
                    //关闭资源
                    try {
                        conn.close();
                        ps.close();
                    
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容