给Java初学者的学习笔记

第21章 JDBC

2019-04-15  本文已影响480人  yangsg

1. 基础知识

Java连接数据库,是通过操作系统完成相应的连接,这种连接方式被称为桥连接。以操作系统为桥梁(比如在windows系统中利用数据源ODBC),连接Java程序和关系型数据库。局限性:应用程序不可跨平台。

JDBC推出后,可以利用Java程序直接访问关系型数据库。

访问网络中某个数据库,需要以下信息

2. 连接MySQL数据库

2.1 前置准备

点击“Java Build Path”,打开“Libraries”选项卡,点击右侧的“Add JARs”


操作示范

找到,并选择刚刚复制的jar包文件,点击OK


找到并选中

点击OK后,可以看到mysql的驱动已经参与到了编译环境中


操作示范
2.2 查询的示例

创建连接各个数据库的连接的代码,格式都是固定的
基本思路:

  1. 通过Class.forName("")加载驱动类
//1.加载驱动
try {
    Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
  1. 声明连接字符串和账号密码
//2.配置连接字符串
String url ="jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
String username = "root";
String password = "root";
  1. 利用DriverManager创建数据库连接(Connection)
//3.创建数据库连接
Connection conn = null;
try {
    conn = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
    e.printStackTrace();
}   

4.声明SQL语句

//4.声明SQL语句
String sql = "select empno,ename,hiredate from emp";

5.加载和执行SQL语句

//5.加载SQL语句
Statement s = conn.createStatement();
//6.执行SQL语句,得到查询结果(结果集对象)
ResultSet rs = s.executeQuery(sql);

6.遍历结果集

while(rs.next()) {
//每执行一轮循环,遍历出查询结果的一行数据
    int empno = rs.getInt("empno"); //取得整数类型的数据
    String ename = rs.getString("ename"); //取得文本类型的数据
    Date birthday = rs.getDate("hiredate"); //取得日期类型的数据
    System.out.println(empno+"\t"+ename+"\t"+birthday);
}

7.关闭数据库连接

//8.关闭数据库连接
try {
    conn.close();
} catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

完整示例

public class Test {

    public static void main(String[] args) {
        //1.加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //2.配置连接字符串
        String url ="jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "root";
        
        //3.创建数据库连接
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
        //4.声明SQL语句
        String sql = "select empno,ename,hiredate from emp";    
        try {
            //5.加载SQL语句
            Statement s = conn.createStatement();
            //6.执行SQL语句,得到查询结果(结果集对象)
            ResultSet rs = s.executeQuery(sql);
            //7.遍历结果集
            while(rs.next()) {
                //每执行一轮循环,遍历出查询结果的一行数据
                int empno = rs.getInt("empno");
                String ename = rs.getString("ename");
                Date birthday = rs.getDate("hiredate");
                
                System.out.println(empno+"\t"+ename+"\t"+birthday);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //8.关闭数据库连接
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
2.3 DML的示例

DML操作不需要遍历结果集,使用executeUpdate(sql)方法来完成DML操作,其返回结果为int类型,表示DML操作影响的数据行数。

public class Test2 {

    public static void main(String[] args) {
        // 1.加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 2.配置连接字符串
        String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "root";

        // 3.创建数据库连接
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 4.声明SQL语句
        String sql = "insert into emp values (1015,'HAHA','CLERK',null,null,5000,0,10)";
        try {
            // 5.加载SQL语句
            Statement s = conn.createStatement();
            // 6.执行SQL语句,得到的结果表示此次DML操作影响了a行数据
            int a = s.executeUpdate(sql);//增删改
            System.out.println(a);
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // 8.关闭数据库连接
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
2.4 预加载的示例

因为用户可以输入,输入了一个SQL片段后可能对原有的SQL语句逻辑造成破坏,从而达到非法的目的
数据库表

image.png
登录程序
public class Test1 {

    public static void main(String[] args) {
        //1.加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //2.连接字符串
        String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "root";
        
        //3.创建数据库连接
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        //4.声明SQL语句 
        System.out.println("请输入账号:");
        Scanner sc1 = new Scanner(System.in);
        String lname = sc1.nextLine();
        
        System.out.println("请输入密码:");
        Scanner sc2 = new Scanner(System.in);
        String lpass = sc2.nextLine();
        
        String sql = "select * from haha where lname = '"+lname+"' and lpass = '"+lpass+"'";
        System.out.println(sql);
        
        //5.加载和执行SQL语句
        try {
            Statement s = conn.createStatement();
            ResultSet rs = s.executeQuery(sql);
            if(rs.next()) {
                System.out.println("登录成功");
            }else {
                System.out.println("登录失败");
            }       
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }   
    }
}

在输入admin/123或者haha/456的情况可以正常登录
如果输入错误的账号和密码是无法正确登录
但:如果用户输入的账号是:admin,密码是:' or 1=1 and lname='admin
执行的SQL语句变成了

select * from haha where lname = 'admin' and lpass = '' or 1=1 and lname='admin'

逻辑被破坏,也能够正常登录成功,这种情况就是SQL注入
SQL注入带来了很大的系统风险,也是经常被黑产所利用,在编写程序需要控制SQL注入的问题。

利用预加载的statement来解决SQL注入问题。
预加载的statement的特点(与Statement相比)

将要输入至SQL的参数,使用英文"?"替代
将刚才有问题的程序更换如下

public class Test1 {

    public static void main(String[] args) {
        //1.加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //2.连接字符串
        String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "root";
        
        //3.创建数据库连接
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        //4.声明SQL语句 
        System.out.println("请输入账号:");
        Scanner sc1 = new Scanner(System.in);
        String lname = sc1.nextLine();
        
        System.out.println("请输入密码:");
        Scanner sc2 = new Scanner(System.in);
        String lpass = sc2.nextLine();
        
        String sql = "select * from haha where lname = ? and lpass = ?";
        System.out.println(sql);
        
        //5.加载和执行SQL语句
        try {
            PreparedStatement pst = conn.prepareStatement(sql);
            //参数绑定:根据实际的数据类型进行设置
            pst.setString(1, lname);
            pst.setString(2, lpass);
            
            ResultSet rs = pst.executeQuery();
            if(rs.next()) {
                System.out.println("登录成功");
            }else {
                System.out.println("登录失败");
            }       
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }   
    }
}

建议所有的JDBC统一使用PreparedStatement完成

2.5 批处理的示例(了解)

利用批处理,对一批SQL语句统一的执行,主要用于大量数据的新增操作中,节省时间。

Statement st = conn.createStatement();
for(int i = 0; i < 99; i++) {
    st.addBatch(sql); //将sql添加到批处理中
}
st.executeBatch(); //执行批次

优势:执行的速度较快
劣势:执行同样或者类似SQL

上一篇下一篇

猜你喜欢

热点阅读