什么是JDBC

是一种访问数据库的规范(API、接口)。这种规范可以屏蔽不同数据库的实现细节,提供统一的访问数据库的方式。

JDBC语法

更新操作

public class JDBCDemo01 {
    public static void main(String[] args) throws Exception{
        //注册驱动(从JDBC3开始可以省略)
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接
        //URL-> 协议//主机IP:端口号/数据库(资源名)
        String url = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
        Connection connection = DriverManager.getConnection(url,
                "root", "980909");
        //获取语句执行平台对象
        Statement statement = connection.createStatement();
        //执行操作
        String sql = "create table test(id int, name varchar(20), age int);";
        int rows = statement.executeUpdate(sql);
        System.out.println(rows);
        //关闭流
        statement.close();
        connection.close();
    }
}

查询操作

public class JDBCDemo02 {
    public static void main(String[] args) throws Exception{
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
        Connection connection = DriverManager.getConnection(url,
                "root", "980909");
        Statement statement = connection.createStatement();
        String sql = "select * from jdbc_user;";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            // int id = resultSet.getInt(1);  列号从1开始
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            Date birthday = resultSet.getDate("birthday");
            System.out.println(id + " " + username + " " + password + " " + birthday);
        }
        resultSet.close();
        statement.close();
        connection.close();
    }
}

写一个简单的JDBC工具类

public class JDBCUtils {
    public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
    public static final String URL = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
    public static final String USER = "root";
    public static final String PASSWORD = "980909";

    static {
        try {
            Class.forName(DRIVERNAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        try {
            Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
            return connection;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            return null;
        }
    }

    public static void close(Connection connection, Statement statement) {
        if (statement != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

SQL注入

SELECT * FROM jdbc_user WHERE username = 'tom' AND PASSWORD = '1' OR 1=1;

图片说明

JDBC例子

public class TestLogin01 {
    public static void main(String[] args) throws SQLException {
//1.获取连接
        Connection connection = JDBCUtils.getConnection();
//2.获取Statement
        Statement statement = connection.createStatement();
//3.获取用户输入的用户名和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名: ");
        String name = sc.nextLine();
        System.out.println("请输入密码: ");
        String pass = sc.nextLine();
        System.out.println(pass);
//4.拼接Sql,执行查询

        String sql = "select * from jdbc_user " +
                "where username = " + " '" + name + "' " + " and password = " + " '" + pass + "'";
        System.out.println(sql);
        ResultSet resultSet = statement.executeQuery(sql);
//5.处理结果集,判断结果集是否为空
        if (resultSet.next()) {
            System.out.println("登录成功! 欢迎您: " + name);
        } else {
            System.out.println("登录失败!");
        }
//释放资源
        JDBCUtils.close(connection, statement, resultSet);
    }
}

分析

如果此时用户的密码为 xxx' or '1' = '1, 就会被sql注入。
防止这种问题,就需要不进行字符串拼接。

解决办法

使用PreparedStatement

public class TestLogin02 {
    public static void main(String[] args) throws Exception{
        Scanner sc = new Scanner(System.in);
        String str1 = sc.next();
        String str2 = sc.next();
        Connection connection = JDBCUtils.getConnection();
        String sql = "select * from jdbc_user where username = ? and password = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //如果要设置null就用setObject
        preparedStatement.setString(1, str1);
        preparedStatement.setString(2, str2);
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            System.out.println("查询成功");
        } else {
            System.out.println("查询失败");
        }
        JDBCUtils.close(connection, preparedStatement, resultSet);
    }
}

preparedStatement的性能也很好,sql的模板(就是带?的)会提前编译好,插入数据的时候性能高。
普通的statement插入数据的时候,插10000次会编译10000次。性能不好。

事务

public class TestTrans {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            //关闭自动提交,相当于开启事务
            connection.setAutoCommit(false);
            String sql = "update account set money = money - ? where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, 500.0);
            preparedStatement.setString(2, "tom");
            int rows = preparedStatement.executeUpdate();
            String sql2 = "update account set money = money + ? where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, 500.0);
            preparedStatement.setString(2, "jack");
            int rows2 = preparedStatement.executeUpdate();
            System.out.println(rows + "\t" + rows2);
            connection.commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            try {
                connection.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        } finally {
            JDBCUtils.close(connection, preparedStatement);
        }
    }
}