什么是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); } } }