一、JDBC的六步骤(背过)

第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)

第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)

第三步:获取数据库操作对象(专门执行sql语句的对象)

第四步:执行SQL语句(DQL DML….)

第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)

第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)

  1. import java.sql.*;
  2. public class JDBCTest01 {
  3. public static void main(String[] args) {
  4. Connection conn =null;
  5. Statement stmt = null;
  6. ResultSet rs =null;
  7. try{
  8. //1.注册驱动
  9. Class.forName("com.mysql.jdbc.Driver");
  10. //2.获取连接
  11. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  12. //3.获取数据库操作对象
  13. stmt = conn.createStatement();
  14. //4.执行sql
  15. //int executeUpdate(insert/delete/update)
  16. //ResultSet executeQuery(select)
  17. String sql ="select empno as a,ename,sal from emp";
  18. rs =stmt.executeQuery(sql);
  19. //5.处理查询结果集
  20. while(rs.next()){
  21. /*
  22. // 以指定的格式取出
  23. int empno = rs.getInt(1);
  24. String ename = rs.getString(2);
  25. double sal = rs.getDouble(3);
  26. System.out.println(empno + "," + ename + "," + (sal + 100));
  27. */
  28. // 按下标取出,程序不健壮
  29. int empno = rs.getInt("a");
  30. String ename = rs.getString("ename");
  31. double sal = rs.getDouble("sal");
  32. System.out.println(empno + "," + ename + "," + (sal + 200));
  33. }
  34. } catch (ClassNotFoundException e) {
  35. e.printStackTrace();
  36. } catch (SQLException throwables) {
  37. throwables.printStackTrace();
  38. // 6、释放资源
  39. }finally{
  40. if(rs != null){
  41. try{
  42. rs.close();
  43. } catch (Exception e){
  44. e.printStackTrace();
  45. }
  46. }
  47. if(stmt != null){
  48. try{
  49. stmt.close();
  50. } catch (Exception e){
  51. e.printStackTrace();
  52. }
  53. }
  54. if(conn != null){
  55. try{
  56. conn.close();
  57. } catch (Exception e){
  58. e.printStackTrace();
  59. }
  60. }
  61. }
  62. }
  63. }

二、SQL问题

该问题存在BUG
用户名:fdsa
密码:fdsa’ or ‘1’=’1登录成功
这种现象被称为SQL注入(安全隐患)。(黑客经常使用)5、导致SQL注入的根本原因是什么?
用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到SQL注入。

  1. package ustc.java.jdbc;
  2. import java.sql.*;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.Scanner;
  6. /*
  7. 模拟实现用户登录功能
  8. */
  9. public class JDBCTest06 {
  10. public static void main(String[] args) {
  11. // 初始化界面
  12. Map<String,String> userLoginInfo = initUI();
  13. // 验证用户名和密码
  14. boolean loginSuccess = login(userLoginInfo);
  15. // 输出最后结果
  16. System.out.println(loginSuccess ? "登录成功" : "登录失败");
  17. }
  18. /**
  19. * 用户登录
  20. * @param userLoginInfo 用户登录信息
  21. * @return true表示登录成功,false表示登录失败
  22. */
  23. private static boolean login(Map<String, String> userLoginInfo) {
  24. //单独定义变量
  25. String loginName = userLoginInfo.get("loginName");
  26. String loginPwd = userLoginInfo.get("loginPwd");
  27. boolean loginSuccess = false;
  28. Connection conn = null;
  29. Statement stmt = null;
  30. ResultSet rs = null;
  31. try {
  32. // 1、注册驱动
  33. Class.forName("com.mysql.jdbc.Driver");
  34. // 2、获取连接
  35. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  36. // 3、获取数据库操作对象
  37. stmt = conn.createStatement();
  38. // 4、执行sql语句
  39. String sql = "select * from t_user where loginName = '"+ loginName+ "' and loginPwd = '" + loginPwd+ "'";
  40. rs = stmt.executeQuery(sql);
  41. // 5、处理结果集
  42. if(rs.next()) {
  43. loginSuccess = true;
  44. }
  45. } catch (ClassNotFoundException e) {
  46. e.printStackTrace();
  47. } catch (SQLException throwables) {
  48. throwables.printStackTrace();
  49. } finally {
  50. // 6、释放资源
  51. if (rs != null) {
  52. try {
  53. rs.close();
  54. } catch (SQLException throwables) {
  55. throwables.printStackTrace();
  56. }
  57. }
  58. if (stmt != null) {
  59. try {
  60. stmt.close();
  61. } catch (SQLException throwables) {
  62. throwables.printStackTrace();
  63. }
  64. }
  65. if (conn != null) {
  66. try {
  67. conn.close();
  68. } catch (SQLException throwables) {
  69. throwables.printStackTrace();
  70. }
  71. }
  72. }
  73. return loginSuccess;
  74. }
  75. /**
  76. * 初试化界面
  77. * @return 用户输入的用户名和密码等登录信息
  78. */
  79. private static Map<String, String> initUI() {
  80. Scanner s = new Scanner(System.in);
  81. System.out.print("请输入用户:");
  82. String loginName = s.nextLine();
  83. System.out.print("请输入密码:");
  84. String loginPwd= s.nextLine();
  85. Map<String,String> userLoginInfo = new HashMap<>();
  86. userLoginInfo.put("loginName",loginName);
  87. userLoginInfo.put("loginPwd",loginPwd);
  88. return userLoginInfo;
  89. }
  90. }

解决SQL注入问题
3、解决SQL注入的关键是什么?
用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译。不起作用。4、对比一下statement和Preparedstatement?
Statement存在sql注入问题,Preparedstatement解决了SQL注入问题。
Statement是编译一次执行一次。PreparedStatement是编译一次,可执行多次。Preparedstatement效率较高一些。Preparedstatement会在编译阶段做类型的安全检查。

  1. package ustc.java.jdbc;
  2. import java.sql.*;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.Scanner;
  6. public class JDBCTest07 {
  7. public static void main(String[] args) {
  8. // 初始化界面
  9. Map<String,String> userLoginInfo = initUI();
  10. // 验证用户名和密码
  11. boolean loginSuccess = login(userLoginInfo);
  12. // 输出最后结果
  13. System.out.println(loginSuccess ? "登录成功" : "登录失败");
  14. }
  15. /**
  16. * 用户登录
  17. * @param userLoginInfo 用户登录信息
  18. * @return true表示登录成功,false表示登录失败
  19. */
  20. private static boolean login(Map<String, String> userLoginInfo) {
  21. boolean loginSuccess = false;
  22. Connection conn = null;
  23. PreparedStatement ps = null;
  24. ResultSet rs = null;
  25. try {
  26. // 1、注册驱动
  27. Class.forName("com.mysql.jdbc.Driver");
  28. // 2、获取连接
  29. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  30. // 3、获取预编译的数据库操作对象
  31. // sql语句的框架中,一个?,表示一个占位符,一个?将来接收一个值。注意:?不要用单引号括起来
  32. String sql = "select * from t_user where loginName = ? and loginPwd = ?";
  33. // 程序执行到此处,会发送sql语句框架给DBMS,DBMS对sql语句框架进行预编译。
  34. ps = conn.prepareStatement(sql);
  35. // 给占位符?传值,第一个?的下标是1,第二个?的下标是2(JDBC中下标都从1开始)
  36. ps.setString(1,userLoginInfo.get("loginName"));
  37. ps.setString(2,userLoginInfo.get("loginPwd"));
  38. // 4、执行sql语句
  39. rs = ps.executeQuery();
  40. // 5、处理结果集
  41. if(rs.next()) {
  42. loginSuccess = true;
  43. }
  44. } catch (ClassNotFoundException e) {
  45. e.printStackTrace();
  46. } catch (SQLException throwables) {
  47. throwables.printStackTrace();
  48. } finally {
  49. // 6、释放资源
  50. if (rs != null) {
  51. try {
  52. rs.close();
  53. } catch (SQLException throwables) {
  54. throwables.printStackTrace();
  55. }
  56. }
  57. if (ps != null) {
  58. try {
  59. ps.close();
  60. } catch (SQLException throwables) {
  61. throwables.printStackTrace();
  62. }
  63. }
  64. if (conn != null) {
  65. try {
  66. conn.close();
  67. } catch (SQLException throwables) {
  68. throwables.printStackTrace();
  69. }
  70. }
  71. }
  72. return loginSuccess;
  73. }
  74. /**
  75. * 初试化界面
  76. * @return 用户输入的用户名和密码等登录信息
  77. */
  78. private static Map<String, String> initUI() {
  79. Scanner s = new Scanner(System.in);
  80. System.out.print("请输入用户:");
  81. String loginName = s.nextLine();
  82. System.out.print("请输入密码:");
  83. String loginPwd = s.nextLine();
  84. Map<String,String> userLoginInfo = new HashMap<>();
  85. userLoginInfo.put("loginName",loginName);
  86. userLoginInfo.put("loginPwd",loginPwd);
  87. return userLoginInfo;
  88. }
  89. }

演示statement的用途
即什么时候使用statement
综上所述: Preparedstatement使用较多。只有极少数的情况下需要使用statement5、什么情况下必须使用statement呢?
业务方面要求必须支持sql注入的时候。
statement支持sql注入,凡是业务方面要求是需要进行sql语句拼接的,必须使用statement。

  1. package ustc.java.jdbc;
  2. import java.sql.*;
  3. import java.util.Scanner;
  4. public class JDBCTest08 {
  5. public static void main(String[] args) {
  6. //用户在控制台输入desc就是降序,输入asc就是升序
  7. Scanner s = new Scanner(System.in);
  8. System.out.println("请输入desc或者asc");
  9. String keyWords = s.nextLine();
  10. //执行SQL
  11. Connection conn = null;
  12. Statement stmt = null;
  13. ResultSet rs = null;
  14. try {
  15. Class.forName("com.mysql.jdbc.Driver");
  16. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  17. stmt = conn.createStatement();
  18. String sql = "select ename from emp order by ename " + keyWords;
  19. rs = stmt.executeQuery(sql);
  20. //遍历结果集
  21. while(rs.next()){
  22. System.out.println(rs.getString("ename"));
  23. }
  24. } catch (ClassNotFoundException e) {
  25. e.printStackTrace();
  26. } catch (SQLException throwables) {
  27. throwables.printStackTrace();
  28. } finally {
  29. if (rs != null) {
  30. try {
  31. rs.close();
  32. } catch (SQLException throwables) {
  33. throwables.printStackTrace();
  34. }
  35. }
  36. if (stmt != null) {
  37. try {
  38. rs.close();
  39. } catch (SQLException throwables) {
  40. throwables.printStackTrace();
  41. }
  42. }
  43. if (conn != null) {
  44. try {
  45. rs.close();
  46. } catch (SQLException throwables) {
  47. throwables.printStackTrace();
  48. }
  49. }
  50. }
  51. }
  52. }

三、JDBC事务机制

JDBC事务机制:
1、JDBc中的事务是自动提交的,什么是自动提交?
只要执行任意一条DML语句,则自动提交—次。这是JDBC默认的事务行为。但是在实际的业务当中,通常都是N条DML语句共同联合才能完成的,必须保证他们这些DML语句在同一个事务中同时成功或者同时失败。

文件名:t_act.sql 用途:bjpowernode; source …

  1. drop table if exists t_act;
  2. create table t_act(
  3. actno int,
  4. balance double(7,2)//注意7表示有效数字的个数,2表示小数位的个数。
  5. );
  6. insert into t_act(actno,balance) values(111,20000);
  7. insert into t_act(actno,balance) values(222,0);
  8. commit;
  9. select * from t_act;
  1. /*重点三行代码:
  2. conn.setAutoCommit(false);
  3. conn.commit();
  4. conn.rollback();
  5. */
  6. package ustc.java.jdbc;
  7. import java.sql.Connection;
  8. import java.sql.DriverManager;
  9. import java.sql.PreparedStatement;
  10. import java.sql.SQLException;
  11. public class JDBCTest10 {
  12. public static void main(String[] args) {
  13. Connection conn = null;
  14. PreparedStatement ps = null;
  15. try {
  16. // 注册驱动
  17. Class.forName("com.mysql.jdbc.Driver");
  18. // 获取连接
  19. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  20. // 将自动提交改为手动提交
  21. conn.setAutoCommit(false);
  22. // 获取预编译的数据库操作对象
  23. String sql = "update t_act set balance = ? where actno = ? ";
  24. ps = conn.prepareStatement(sql);
  25. ps.setInt(1,10000);
  26. ps.setDouble(2,111);
  27. // 执行sql语句
  28. int count = ps.executeUpdate();
  29. /*String s = null;
  30. s.toString();*/
  31. ps.setInt(1,10000);
  32. ps.setDouble(2,222);
  33. count += ps.executeUpdate();
  34. System.out.println(count == 2 ? "转账成功" : "转账失败");
  35. // 程序能执行到此处,说明没有异常,事务结束,手动提交数据
  36. conn.commit();
  37. } catch (Exception e) {
  38. // 遇到异常,回滚
  39. if (conn != null) {
  40. try {
  41. conn.rollback();
  42. } catch (SQLException throwables) {
  43. throwables.printStackTrace();
  44. }
  45. }
  46. e.printStackTrace();
  47. } finally {
  48. // 释放资源
  49. if (ps != null) {
  50. try {
  51. ps.close();
  52. } catch (SQLException throwables) {
  53. throwables.printStackTrace();
  54. }
  55. }
  56. if (conn != null) {
  57. try {
  58. conn.close();
  59. } catch (SQLException throwables) {
  60. throwables.printStackTrace();
  61. }
  62. }
  63. }
  64. }
  65. }

四、JDBC工具类的封装

  1. package ustc.java.jdbc;
  2. import java.sql.*;
  3. /*
  4. JDBC工具类,简化JDBC编程
  5. */
  6. public class DBUtil {
  7. /**
  8. * 工具类中的构造方法是私有的
  9. * 因为工具类中的方法都是静态的,不需要new对象,直接通过类名去调即可。
  10. */
  11. private DBUtil(){}
  12. /**
  13. * 静态代码块,类加载的时候执行
  14. * 把注册驱动程序的代码放在静态代码块中,避免多次获取连接对象时重复调用
  15. */
  16. static {
  17. try {
  18. Class.forName("com.mysql.jdbc.Driver");
  19. } catch (ClassNotFoundException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. public static Connection getConnection() throws SQLException {
  24. return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333");
  25. }
  26. /**
  27. * 关闭资源
  28. * @param conn 连接对象
  29. * @param ps 数据库操作对象
  30. * @param rs 结果集
  31. */
  32. public static void close(Connection conn, Statement ps, ResultSet rs){
  33. if (rs != null) {
  34. try {
  35. rs.close();
  36. } catch (SQLException throwables) {
  37. throwables.printStackTrace();
  38. }
  39. }
  40. if (ps != null) {
  41. try {
  42. ps.close();
  43. } catch (SQLException throwables) {
  44. throwables.printStackTrace();
  45. }
  46. }
  47. if (conn != null) {
  48. try {
  49. conn.close();
  50. } catch (SQLException throwables) {
  51. throwables.printStackTrace();
  52. }
  53. }
  54. }
  55. }

测试DBUtil工具类和模糊查询

  1. package ustc.java.jdbc;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. /*
  7. 1、测试DBUtil工具类
  8. 2、模糊查询
  9. */
  10. public class JDBCTest {
  11. public static void main(String[] args) {
  12. Connection conn = null;
  13. PreparedStatement ps = null;
  14. ResultSet rs = null;
  15. try {
  16. conn = DBUtil.getConnection();
  17. String sql = "select ename from emp where ename like ?";
  18. ps = conn.prepareStatement(sql);
  19. ps.setString(1,"_A%");
  20. rs = ps.executeQuery();
  21. while(rs.next()){
  22. System.out.println(rs.getString("ename"));
  23. }
  24. } catch (SQLException throwables) {
  25. e.printStackTrace();
  26. }finally{
  27. DBUtil.close(conn,ps,rs);
  28. }
  29. }