网友整理老杜2020版本JDBC:
https://blog.csdn.net/qq_32480989/article/details/120876779

JDBC 基础概念

  1. JDBC是什么?

    Java DataBase Connectivity( Java语言连接数据库)

  2. JDBC的本质是什么?

    JDBC是SUN公司制定的一套接口(interface),java.sql.*; (这个软件包下有很多接口。)

    接口都有调用者和实现者。
    面向接口调用、面向接口写实现类,这都属于面向接口编程。

  3. 为什么要面向接口编程?

    1. **解耦合:降低程序的耦合度,提高程序的扩展力。**<br /> 多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)<br /> 建议:
    1. Animal a = new Cat();
    2. Animal a = new Dog();
    3. // 喂养的方法
    4. public void feed(Animal a){ // 面向父类型编程。
    5. }
    6. 不建议:
    7. Dog d = new Dog();
    8. Cat c = new Cat();
  1. 思考:为什么SUN制定一套JDBC接口呢?

    1. 因为每一个数据库的底层实现原理都不一样,Oracle数据库有自己的原理,MySQL数据库也有自己的原理,每一个数据库产品都有自己独特的实现原理。<br />
  2. JDBC的本质到底是什么?

    1. **一套接口**

    JDBC 开发流程

    开发流程

  3. JDBC开发前的准备工作,先从官网下载对应的驱动jar包,然后将其配置到环境变量 classpath当中

    1. classpath=.;D:\course\06-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar

    注意:

    • .;表示任意路径
    • 以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量
    • IDEA有自己的配置方式。
  1. JDBC编程六步(需要背会)


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

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

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

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

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

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

模拟JDBC的本质

image.png
image.png

image.pngimage.png

  1. JDBC的本质

JDBC本质.jpg

JDBC 课堂测试源码

  1. java.SQL包下:
  • java 中 sql 源码路径:

java帮助文档——>java.SQL包下———->类、接口
复习:除了java.lang包,其余包都需要导包

  1. JDBC开发的步骤详细说明:
  • 第一步:注册驱动

有一个类 :DriverManager 驱动管理器 Driver 的意思是驱动
里面有一个方法:static void registerDriver( Driver driver) 注册驱动的方法
这个方法的参数的说明:Driver是一个接口 无法new对象,就得找Driver的实现类,这个实现类是有数据库厂商写的,得去new产商写的那个实现类Driver
格式:new 包名.类名();
说明:厂商的实现类是公开的,需要包名.方式去访问这个实现类,然后再创建这个类的对象,去厂商的jar包找这个实现类。

  1. 这个方法的异常说明:

image.png
说明:继承了 exception 说明了 是受检异常,需要处理,

  • 第二步:获取连接

url:统一资源定位符(网络中某个资源的绝对路径)
https://www.baidu.com/ 这就是URL。
URL包括哪几部分?
协议
IP
PORT
资源名

  1. [http://182.61.200.7:80/index.html](http://182.61.200.7:80/index.html)<br /> http:// 通信协议<br /> 182.61.200.7 服务器IP地址<br /> 80 服务器上软件的端口<br /> index.html 是服务器上某个资源名<br /> <br /> <br /> **jdbc:mysql://127.0.0.1:3306/bjpowernode**<br /> jdbc:mysql:// 协议<br /> 127.0.0.1 IP地址<br /> 3306 mysql数据库端口号<br /> bjpowernode 具体的数据库实例名。<br /> <br /> 说明:localhost和127.0.0.1都是本机IP地址。
  2. jdbc:mysql://192.168.151.27:3306/bjpowernode<br />
  • 什么是通信协议,有什么用?

    1. 通信协议是通信之前就提前定好的数据传送格式。<br /> 数据包具体怎么传数据,格式提前定好的。<br />
  • oracle的URL:

    1. jdbc:oracle:thin:@localhost:1521:orcl
  1. JDBCTest01源码

编程六步:

  1. import java.sql.Driver;
  2. import java.sql.DriverManager;
  3. import java.sql.SQLException;
  4. import java.sql.Connection;
  5. import java.sql.Statement;
  6. public class JDBCTest01{
  7. public static void main(String[] args){
  8. Connection conn = null;
  9. Statement stmt = null;
  10. try{
  11. //1、注册驱动
  12. Driver driver = new com.mysql.jdbc.Driver(); // 多态,父类型引用指向子类型对象。
  13. // Driver driver = new oracle.jdbc.driver.OracleDriver(); // oracle的驱动。
  14. DriverManager.registerDriver(driver);
  15. //2、获取连接
  16. String url = "jdbc:mysql://192.168.151.9:3306/bjpowernode";
  17. String user = "root";
  18. String password = "981127";
  19. conn = DriverManager.getConnection(url,user,password);
  20. // com.mysql.jdbc.JDBC4Connection@41cf53f9
  21. System.out.println("数据库连接对象 = " + conn);
  22. //3、获取数据库操作对象(Statement专门执行sql语句的)
  23. stmt = conn.createStatement();
  24. //4、执行sql
  25. String sql = "insert into dept(deptno,dname,loc) values(50,'人事部','北京')";
  26. // 专门执行DML语句的(insert delete update)
  27. // 返回值是“影响数据库中的记录条数”
  28. int count = stmt.executeUpdate(sql);
  29. System.out.println(count == 1 ? "保存成功" : "保存失败");
  30. //5、处理查询结果集
  31. }catch(SQLException e){
  32. e.printStackTrace();
  33. }finally{
  34. //6、释放资源
  35. // 为了保证资源一定释放,在finally语句块中关闭资源
  36. // 并且要遵循从小到大依次关闭
  37. // 分别对其try..catch
  38. try{
  39. if(stmt != null){
  40. stmt.close();
  41. }
  42. }catch(SQLException e){
  43. e.printStackTrace();
  44. }
  45. try{
  46. if(conn != null){
  47. conn.close();
  48. }
  49. }catch(SQLException e){
  50. e.printStackTrace();
  51. }
  52. }
  53. }
  54. }
  1. JDBC完成 delete、updata

    学习方法:下去背代码
    JDBCtest02

注册驱动的另一种方式

  1. JDBCTest03 ```java import java.sql.*;

public class JDBCTest03{ public static void main(String[] args){ try{ //1、注册驱动 // 这是注册驱动的第一种写法。 // DriverManager.registerDriver(new com.mysql.jdbc.Driver()); // 注册驱动的第二种方式:常用的。 // 为什么这种方式常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中。 // 以下方法不需要接收返回值,因为我们只想用它的类加载动作。 Class.forName(“com.mysql.jdbc.Driver”); //反射机制进行类加载 //Class.forName()方法的执行会导致,方法里面的类进行类加载,然后静态代码块执行,完成驱动的注册 //2、获取连接 Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/bjpowernode”,”root”,”333”); // com.mysql.jdbc.JDBC4Connection@41cf53f9 System.out.println(conn);

  1. }catch(SQLException e){
  2. e.printStackTrace();
  3. }catch(ClassNotFoundException e){
  4. e.printStackTrace();
  5. }
  6. }

}

  1. **将连接数据库的所有信息配置到配置文件当中**
  2. <a name="x5Voq"></a>
  3. ## 从属性资源文件中读取连接数据库信息
  4. Test04
  5. ```java
  6. driver=com.mysql.cj.jdbc.Driver
  7. url=jdbc:mysql://127.0.0.1:3306/bjpowernode
  8. user=root
  9. password=123456

配置文件:jdbc.properties

  1. package jdbc;
  2. import java.sql.*;
  3. import java.util.ResourceBundle;
  4. /*
  5. 实际开发中不建议把连接数据库的信息写死在java程序中。
  6. */
  7. public class jdbc04 {
  8. public static void main(String[] args) {
  9. // 使用资源绑定器绑定属性配置文件
  10. ResourceBundle bundle =ResourceBundle.getBundle("jdbcc");
  11. String driver=bundle.getString("key");
  12. String url=bundle.getString("url");
  13. String user=bundle.getString("user");
  14. String password=bundle.getString("password");
  15. Connection conn=null;
  16. Statement stmt=null;
  17. try {
  18. //1、注册驱动(只需要改这个)
  19. Class.forName(driver);
  20. //2、获取连接
  21. conn = DriverManager.getConnection(url,user,password);
  22. //3、获取数据库操作对象
  23. stmt=conn.createStatement();//
  24. //4、执行sql
  25. String sql="update dept set dname='销售部2',loc='天津'where deptno=20";
  26. int count=stmt.executeUpdate(sql);
  27. System.out.println(count==1?"修改成功":"修改失败");
  28. } catch (SQLException e) {
  29. e.printStackTrace();
  30. }catch (ClassNotFoundException e) {
  31. e.printStackTrace();
  32. }finally{
  33. //6、释放资源
  34. if(stmt!=null){
  35. try{
  36. stmt.close();
  37. }catch(SQLException e){
  38. e.printStackTrace();
  39. }
  40. }
  41. if(conn!=null){
  42. try{
  43. conn.close();
  44. }catch(SQLException e){
  45. e.printStackTrace();
  46. }
  47. }
  48. }
  49. }
  50. }

处理查询结果集

笔记: 查询完的结果封装在 ResultSet里面
Test05

  1. package jdbc;
  2. import javax.swing.*;
  3. import java.sql.*;
  4. /*
  5. 处理查询结果集
  6. */
  7. public class jdbc05 {
  8. public static void main(String[] args) {
  9. Connection conn=null;
  10. Statement stmt=null;
  11. ResultSet rs=null;
  12. try {
  13. //1、注册驱动
  14. DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
  15. //2、获取连接
  16. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode","root","123456");
  17. //3、获取数据库操作对象
  18. stmt=conn.createStatement();//
  19. //4、执行sql
  20. String sql="select empno,ename,sal from emp";
  21. //ResultSet executeQuery(String sql) throws SQLEXception
  22. //执行给定的SQL语句,该语句返回单词ResultSet对象。
  23. // 参数sql 为要发送给数据库的SQL语句,通常为静态SQL select语句。
  24. //int executeUpdate(insert/delete/update)
  25. //ResultSet executeQuery(select)//ResultSet是执行sql语句后的查询结果集
  26. rs=stmt.executeQuery(sql);
  27. //5、处理查询结构集
  28. /*理解过程
  29. boolean flag1=rs.next();//本来在第0行,现在next到了第一行,如果有数据就返回true
  30. // System.out.println(flag1); //true
  31. if(flag1){
  32. //光标指向的行有数据
  33. //取数据
  34. //getString()方法的特点是:不管数据库中的数据类型是什么,都以String的形式取出
  35. String empno=rs.getString(1);//跟的是下标,第一列,第二列,第三列
  36. String ename=rs.getString(2);//jdbc中所有的下标从1开始,不是从0开始的
  37. String sal=rs.getString(3);
  38. System.out.println(empno+","+ename+","+sal);
  39. }
  40. //rs.next();
  41. //boolean next() throws SQLException将光标从当前位置向前移一行。
  42. // ResultSet 光标最初位于第一行之前;第一次调用 next
  43. // 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。
  44. // 返回:如果新的当前行有效,则返回 true;如果不存在下一行,则返回 false
  45. //抛出:SQLException - 如果发生数据库访问错误或在关闭的结果集上调用此方法
  46. */
  47. while(rs.next()){
  48. /*
  49. String empno=rs.getString(1);
  50. String ename=rs.getString(2);
  51. String sal=rs.getString(3);
  52. System.out.println(empno+","+ename+","+sal);
  53. */
  54. /*另一种写法,不是以列的下标获取,以列的名字获取
  55. String empno=rs.getString("empno");
  56. String ename=rs.getString("ename");
  57. String sal=rs.getString("sal");
  58. System.out.println(empno+","+ename+","+sal);
  59. */
  60. int empno=rs.getInt(1);//之所以这能用int 是因为底层数据是int类型的,不然要以String类型
  61. String ename=rs.getString(2);
  62. double sal=rs.getDouble(3);
  63. System.out.println(empno+","+ename+","+(sal-100));//double类型 方便进行运算
  64. }
  65. } catch (SQLException e) {
  66. e.printStackTrace();
  67. }finally{
  68. //6、释放资源
  69. if(rs!=null){//释放查询结果集
  70. try{
  71. rs.close();
  72. }catch(SQLException e){
  73. e.printStackTrace();
  74. }
  75. }
  76. if(stmt!=null){//释放数据库操作对象
  77. try{
  78. stmt.close();
  79. }catch(SQLException e){
  80. e.printStackTrace();
  81. }
  82. }
  83. if(conn!=null){//释放数据库连接对象
  84. try{
  85. conn.close();
  86. }catch(SQLException e){
  87. e.printStackTrace();
  88. }
  89. }
  90. }
  91. }
  92. }

ResultSet rs 存的是执行sql语句后的查询结果集
遍历结果集:
遍历结果集.jpg

IDEA工具开发JDBC

将JDBC的jar包导入idea步骤

  • 第一种方式:
    • 打开模块设置

image.png

  • 鼠标点的这个英文单词为库

image.png

  • 添加Java库,选择 JDBC.jar 包路径 导入

说明:如果建立新的模块需要将,jar包重新导入

第二种方式:

  • 在需要导入的模块,建立目录,然后将JDBC的jar包粘贴到此目录

  • 第二步:将jar包,加入到这个模块就行

image.png

快捷键

  • ctrl +shift+F12
  • ifn

idea中第一个JDBC程序

数据库表的设计阶段

  1. PowerDesigner 数据库表设计 工具的安装

作用:物理建模的,系统设计时用 PowerDesigner 工具
image.png

  • 将激活文件到安装目录进行,替换
  1. 使用步骤:

image.png
快捷键:按住ctrl键+鼠标滑轮,就可以看见很多单元格

双击新建的表,在新的窗口进行设计
image.png

小项目

需求:模拟用户登录功能的实现
描述:

开发经验:能抽象成一个方法的最好抽象成一个方法

SQL注入问题

JDBCTest06 存在SQL注入问题

  1. package jdbc;
  2. import java.sql.*;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.Scanner;
  6. public class jdbc06 {
  7. public static void main(String[] args) {
  8. //初始化一个界面,可以让用户输入用户名和密码
  9. Map<String,String>userLoginInfo=initUI();
  10. //连接数据库验证用户和密码是否正确
  11. boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));
  12. System.out.println(ok?"登陆成功":"登陆失败");
  13. }
  14. private static boolean checkNameAndPwd(String loginName, String loginPwd) {
  15. boolean ok=false;//默认登录是失败的,
  16. Connection conn = null;
  17. Statement stmt = null;
  18. ResultSet rs = null;
  19. // 1、注册驱动
  20. try {
  21. Class.forName("com.mysql.cj.jdbc.Driver");
  22. // 2、获取连接
  23. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  24. // 3、获取数据库操作对象
  25. stmt = conn.createStatement();
  26. // 4、执行sql语句
  27. String sql = "select * from t_user where login_name='"+loginName+"'and login_pwd='"+loginPwd+"'";
  28. System.out.println(sql);
  29. //程序执行到此处,才会将以上的sql语句发送到DBMS上,DBMS进行sql语句的编译。
  30. rs = stmt.executeQuery(sql);//sql处理后会返回一个处理集,
  31. //如果以上sql语句中用户名和密码是正确的,那么结果集最多也就查询出一条记录,所以以下不需要while循环。if就够了
  32. if(rs.next()){//此条件如果成立,表示登录成功
  33. ok=true;
  34. }
  35. // 5、处理结果集
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }finally {
  39. // 6、释放资源
  40. if (rs != null) {
  41. try {
  42. rs.close();
  43. } catch (SQLException throwables) {
  44. throwables.printStackTrace();
  45. }
  46. }
  47. if (stmt != null) {
  48. try {
  49. stmt.close();
  50. } catch (SQLException throwables) {
  51. throwables.printStackTrace();
  52. }
  53. }
  54. if (conn!= null) {
  55. try {
  56. conn.close();
  57. } catch (SQLException throwables) {
  58. throwables.printStackTrace();
  59. }
  60. }
  61. }
  62. return ok;
  63. }
  64. private static Map<String, String> initUI(){
  65. System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");
  66. Scanner s=new Scanner(System.in);
  67. System.out.println("用户名:");
  68. String loginName=s.nextLine();
  69. System.out.println("密码:");
  70. String loginPwd=s.nextLine();
  71. //将用户名和密码放在map集合中
  72. Map<String,String> useLoginInfo=new HashMap<>();
  73. useLoginInfo.put("loginName",loginName);
  74. useLoginInfo.put("loginPwd",loginPwd);
  75. //返回map
  76. return useLoginInfo;
  77. }
  78. /*
  79. 随便输入一个用户名的密码,登录成功了,这种现象被称为SQL注入现象!
  80. 导致SQL注入的根本原因是:用户不是一般的用户,用户是懂程序的,输入的用户名信息以及密码信息中,
  81. 含有SQL语句的关键词,这个SQL语句的关键字和底层的SQL语句进行“字符串拼接”,导致原SQL语句的含义
  82. 被扭曲了。最最主要的原因是:用户提供的信息参与了SQL语句的编译。
  83. 主要因素,这个程序是先进行字符串的拼接,然后再进行sql语句的编译,正好彼注入。
  84. 用户名:
  85. fdsa
  86. 密码:
  87. fdsa' or '1'='1
  88. select * from t_user where login_name='fdsa'and login_pwd='fdsa' or '1'='1'
  89. */
  90. }

解决SQL注入问题(重点学习)

JDBCTest07

  1. package jdbc;
  2. import java.sql.*;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.Scanner;
  6. /*
  7. 怎么避免sql注入?
  8. sql注入的根本原因是,先进行了字符串的拼接,然后在进行的编译。
  9. java.sql.Statement接口的特点,先进行字符串的拼接。然后再进行sql语句的编译。
  10. 优点:使用Statement可以进行sql语句的拼接。
  11. 缺点:因为拼接的存在,导致可能给不法分子机会。
  12. java.sql.PreparedStatement接口的特点,先进行sql语句的编译,然后在进行sql语句的传值。
  13. 优点:避免sql注入。
  14. 缺点:没有办法进行sql语句的拼接,只能给sql语句传值。
  15. PreparedStatement预编译的数据库操作对象
  16. */
  17. public class jdbc07 {
  18. public static void main(String[] args) {
  19. //初始化一个界面,可以让用户输入用户名和密码
  20. Map<String,String>userLoginInfo=initUI();
  21. //连接数据库验证用户和密码是否正确
  22. boolean ok=checkNameAndPwd(userLoginInfo.get("loginName"),userLoginInfo.get("loginPwd"));
  23. System.out.println(ok?"登陆成功":"登陆失败");
  24. }
  25. private static boolean checkNameAndPwd(String loginName, String loginPwd) {
  26. boolean ok=false;//默认登录是失败的,
  27. Connection conn = null;
  28. PreparedStatement stmt = null;
  29. ResultSet rs = null;
  30. // 1、注册驱动
  31. try {
  32. Class.forName("com.mysql.cj.jdbc.Driver");
  33. // 2、获取连接
  34. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  35. // 3、获取预编译的数据库操作对象
  36. //一个问号是一个占位符,一个占位符只能接收一个值/数据
  37. String sql = "select * from t_user where login_name=? and login_pwd=?";
  38. stmt=conn.prepareStatement(sql);//此时会发送sql给DBMS,进行sql语句的编译
  39. //给占位符?传值
  40. //怎么解决sql注入的?即使用户信息中有sql关键字,但是不参加编译就没事。
  41. //stmt.setInt(1,100);//这样必须是填数字,↓下面那个必须填字符串。
  42. stmt.setString(1,loginName);//给第一个占位符传值
  43. stmt.setString(2,loginPwd);//给第二个占位符传值
  44. // 4、执行sql语句
  45. rs = stmt.executeQuery();//这个方法不需要将sql语句传递进去,不能是这样:rs = stmt.executeQuery(sql);因为上面已经把sql传过去了。
  46. if(rs.next()){//此条件如果成立,表示登录成功
  47. ok=true;
  48. }
  49. // 5、处理结果集
  50. } catch (Exception e) {
  51. e.printStackTrace();
  52. }finally {
  53. // 6、释放资源
  54. if (rs != null) {
  55. try {
  56. rs.close();
  57. } catch (SQLException throwables) {
  58. throwables.printStackTrace();
  59. }
  60. }
  61. if (stmt != null) {
  62. try {
  63. stmt.close();
  64. } catch (SQLException throwables) {
  65. throwables.printStackTrace();
  66. }
  67. }
  68. if (conn!= null) {
  69. try {
  70. conn.close();
  71. } catch (SQLException throwables) {
  72. throwables.printStackTrace();
  73. }
  74. }
  75. }
  76. return ok;
  77. }
  78. private static Map<String, String> initUI(){
  79. System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");
  80. Scanner s=new Scanner(System.in);
  81. System.out.println("用户名:");
  82. String loginName=s.nextLine();
  83. System.out.println("密码:");
  84. String loginPwd=s.nextLine();
  85. //将用户名和密码放在map集合中
  86. Map<String,String> useLoginInfo=new HashMap<>();
  87. useLoginInfo.put("loginName",loginName);
  88. useLoginInfo.put("loginPwd",loginPwd);
  89. //返回map
  90. return useLoginInfo;
  91. }
  92. }

一个 ? 表示一个占位符

规律:就是第三步写好SQL语句,用占位符,然后给占位符传值

知识点的补充:当写第一个SQL语句时,会编译然后执行,若你后面在写一模一样的SQL语句就不会编译,直接执行。

Statement使用场景

JDBCTest8 必须使用SQL注入

先使用PreparedStatement-

这个程序输入desc或者asc会出错,因为
select ename,sal from emp order by sal ?会被换成select ename,sal from emp order by sal ‘desc’而不是select ename,sal from emp order by sal desc ,

PreparedStatement比较适合传值,Statement比较适合进行字符串的拼接。

京东升降序那不让用户输入,就是不给你注入的机会。


  1. package jdbc;
  2. import java.sql.*;
  3. import java.util.Scanner;
  4. /*
  5. *需求:用户再控制台上输入desc则降序,输入asc则升序。
  6. *思考以下,这个应该选择Statement还是PreparedStatement
  7. 选Statement,y因为PreparedStatement只能传值,不能进行sql语句的拼接。
  8. */
  9. public class jdbc08 {
  10. public static void main(String[] args){
  11. Scanner s=new Scanner(System.in);
  12. System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");
  13. //用户输入的
  14. String orderKey=s.next();
  15. //先使用PreparedStatement
  16. Connection conn = null;
  17. PreparedStatement ps = null;
  18. ResultSet rs = null;
  19. try {
  20. //1、注册驱动
  21. Class.forName("com.mysql.cj.jdbc.Driver");
  22. //2、获取连接
  23. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  24. //3、获取预编译的数据库操作对象
  25. String sql="select ename,sal from emp order by sal ?";
  26. ps=conn.prepareStatement(sql);
  27. //给?传值
  28. ps.setString(1,orderKey);
  29. //4、执行sql语句
  30. rs=ps.executeQuery();
  31. while(rs.next()){
  32. String ename=rs.getString("ename");
  33. String sal=rs.getString("sal");
  34. System.out.println(ename+","+sal);
  35. }
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }finally {
  39. if(rs!=null){
  40. try {
  41. rs.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. if(ps!=null){
  47. try {
  48. ps.close();
  49. } catch (SQLException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. if(conn!=null){
  54. try {
  55. conn.close();
  56. } catch (SQLException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. }
  61. }
  62. }

JDBCTest09
再使用statement,此时可以执行了

  1. package jdbc;
  2. import java.sql.*;
  3. import java.util.Scanner;
  4. /*
  5. *需求:用户再控制台上输入desc则降序,输入asc则升序。
  6. *思考以下,这个应该选择Statement还是PreparedStatement
  7. */
  8. public class jdbc09 {
  9. public static void main(String[] args){
  10. Scanner s=new Scanner(System.in);
  11. System.out.print("请输入desc或asc[desc是表示降序,asc表示升序]:");
  12. //用户输入的
  13. String orderKey=s.next();
  14. //再使用Statement
  15. Connection conn = null;
  16. Statement stmt = null;
  17. ResultSet rs = null;
  18. try {
  19. //1、注册驱动
  20. Class.forName("com.mysql.cj.jdbc.Driver");
  21. //2、获取连接
  22. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  23. //3、获取数据库操作对象
  24. stmt = conn.createStatement();
  25. //4、执行sql语句
  26. String sql="select ename,sal from emp order by sal "+orderKey;
  27. rs=stmt.executeQuery(sql);
  28. while(rs.next()){
  29. String ename=rs.getString("ename");
  30. String sal=rs.getString("sal");
  31. System.out.println(ename+","+sal);
  32. }
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. }finally {
  36. if(rs!=null){
  37. try {
  38. rs.close();
  39. } catch (SQLException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. if(stmt!=null){
  44. try {
  45. stmt.close();
  46. } catch (SQLException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. if(conn!=null){
  51. try {
  52. conn.close();
  53. } catch (SQLException e) {
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. }
  59. }

使用PreparedStatement完成增删改

  1. package jdbc;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.SQLException;
  6. public class jdbc10 {
  7. public static void main(String[] args) {
  8. Connection conn=null;
  9. PreparedStatement ps=null;
  10. try {
  11. //1、注册驱动
  12. Class.forName("com.mysql.cj.jdbc.Driver");
  13. //2、获取连接
  14. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  15. //3、获取预编译的数据库操作对象
  16. //增加操作
  17. /*String sql="insert into dept(deptno,dname,loc) values(?,?,?)";
  18. ps=conn.prepareStatement(sql);
  19. //给?传值
  20. ps.setInt(1,50);
  21. ps.setString(2,"销售部");
  22. ps.setString(3,"天津");*/
  23. //更新操作
  24. /* String sql="update dept set dname=?,loc=? where deptno = ?";
  25. ps=conn.prepareStatement(sql);
  26. ps.setString(1,"软件研发部");
  27. ps.setString(2,"北京");
  28. ps.setInt(3,50);*/
  29. //删除操作
  30. String sql="delete from dept where deptno = ?";
  31. ps=conn.prepareStatement(sql);
  32. ps.setInt(1,50);
  33. // 4、执行sql
  34. int count=ps.executeUpdate();
  35. System.out.println(count);
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }finally {
  39. //6、释放资源
  40. if(ps!=null){
  41. try {
  42. ps.close();
  43. } catch (SQLException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. if(conn!=null){
  48. try {
  49. conn.close();
  50. } catch (SQLException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  55. }
  56. }

模糊查询

  1. package jdbc;
  2. import java.sql.*;
  3. public class jdbc11 {
  4. public static void main(String[] args) {
  5. Connection conn=null;
  6. PreparedStatement ps=null;
  7. ResultSet rs=null;
  8. try {
  9. //1、注册驱动
  10. Class.forName("com.mysql.cj.jdbc.Driver");
  11. //2、获取连接
  12. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  13. //3、获取预编译的数据库操作对象
  14. //找出名字中含有O的
  15. //以下第一种方法是错误的,因为?不能放在单引号内
  16. /*String sql="select ename from emp where ename like '%?%'";
  17. ps=conn.prepareStatement(sql);
  18. ps.setString(1, "O");*/
  19. String sql="select ename from emp where ename like ?";
  20. ps=conn.prepareStatement(sql);
  21. ps.setString(1, "%O%");
  22. // 4、执行sql
  23. rs=ps.executeQuery();
  24. while (rs.next()){
  25. System.out.println(rs.getString("ename"));
  26. }
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }finally {
  30. //6、释放资源
  31. if(ps!=null){
  32. try {
  33. ps.close();
  34. } catch (SQLException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. if(conn!=null){
  39. try {
  40. conn.close();
  41. } catch (SQLException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. if(ps!=null){
  46. try {
  47. ps.close();
  48. } catch (SQLException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. }
  53. }
  54. }

JDBC 里面的事务

JDBCTest10 测试JDBC里面的事务自动提交【需要手动关掉自动提交】

JDBCTest11 账户转账演示事务【JDBC的事务控制,基于单机事务】
知识点补充:有效数字,从左边起,不为0的数字为有效数字

快捷键补充:ait+shift+inster 可以复制前面不带 * 号的内容 也可以批量编辑

如果程序在执行过程中,有异常,就得手动回滚,保证数据的安全性

JDBC工具类的封装

  • 外部文件

    1. driver=com.mysql.cj.jdbc.Driver
    2. url=jdbc:mysql://127.0.0.1:3306/bjpowernode
    3. user=root
    4. password=123456
  • 封装类 ```css package jdbc.utils; //在一个没有结束的程序中,DBUtil这个类只加载一次

import java.sql.*; import java.util.ResourceBundle;

/ 数据库工具类,便于JDBC的代码编写 / public class DBUtil { //静态变量和静态代码块的执行时候是一样的,先出现的先执行 //构造方法私有化是为了防止new对象,为什么要防止用对象? //因为工具类中的方法都是静态的,不需要new对象,直接用“类名.”的方式调用 private DBUtil(){};//工具类的构造方法私有化的 //类加载时绑定属性资源文件 private static ResourceBundle bundle=ResourceBundle.getBundle(“jdbcc”);

  1. //保证注册驱动在类加载的时执行且只执行一次,则使用静态代码块

static{ try { Class.forName(bundle.getString(“driver”)); } catch (ClassNotFoundException e) { e.printStackTrace(); } }

  1. //获得数据库连接对象
  2. public static Connection getConnection() throws SQLException {
  3. String url=bundle.getString("url");
  4. String user=bundle.getString("user");
  5. String password=bundle.getString("password");
  6. Connection conn=DriverManager.getConnection(url,user,password);
  7. return conn;
  8. }
  9. /**
  10. * 释放资源
  11. * conn 连接对象
  12. * stmt 数据库操作对象
  13. * rs 查询结果集
  14. */
  15. public static void close(Connection conn, Statement stmt,ResultSet rs){
  16. if(rs!=null){
  17. try {
  18. rs.close();
  19. } catch (SQLException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. if(stmt!=null){
  24. try {
  25. stmt.close();
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. if(conn!=null){
  31. try {
  32. conn.close();
  33. } catch (SQLException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

}

  1. 测试类
  2. ```css
  3. package jdbc;
  4. import java.sql.*;
  5. public class jdbc11 {
  6. public static void main(String[] args) {
  7. Connection conn=null;
  8. PreparedStatement ps=null;
  9. ResultSet rs=null;
  10. try {
  11. //1、注册驱动
  12. Class.forName("com.mysql.cj.jdbc.Driver");
  13. //2、获取连接
  14. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bjpowernode", "root", "123456");
  15. //3、获取预编译的数据库操作对象
  16. //找出名字中含有O的
  17. //以下第一种方法是错误的,因为?不能放在单引号内
  18. /*String sql="select ename from emp where ename like '%?%'";
  19. ps=conn.prepareStatement(sql);
  20. ps.setString(1, "O");*/
  21. String sql="select ename from emp where ename like ?";
  22. ps=conn.prepareStatement(sql);
  23. ps.setString(1, "%O%");
  24. // 4、执行sql
  25. rs=ps.executeQuery();
  26. while (rs.next()){
  27. System.out.println(rs.getString("ename"));
  28. }
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }finally {
  32. //6、释放资源
  33. if(ps!=null){
  34. try {
  35. ps.close();
  36. } catch (SQLException e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. if(conn!=null){
  41. try {
  42. conn.close();
  43. } catch (SQLException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. if(ps!=null){
  48. try {
  49. ps.close();
  50. } catch (SQLException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  55. }
  56. }

JDBC 里面的行级锁

1.行级锁的理解:
image.png
在 select 语句后面添加了 for update 就表示 emp 表 中工作岗位等于 MANAGER 的行级记录谁都不能动,这叫行级锁
当前事务没有结束的时候,表中那三行记录,就不能动,其它事务无法对着三行记录,进行操作。
行级锁,又被称为悲观锁

关于DQL语句的悲观锁
对于一个DQL语句来说,末尾是可以添加这样一个关键字的:for update

select ename,sal from emp where job=‘MANAGER’ for update ;
以上sql语句的含义是:
在本次事务的执行过程中,job=’MANAGER’的记录被查询,
这些记录在我查询的过程中,任何人,任何事务都不能对
这些记录进行修改操作,直到我当前事务结束。

这种机制被称为:行级锁机制(又叫做悲观锁!)

在mysql中是这样的,
当使用select…where…for updare…时,mysql进行row lock(行锁)还是table lock(表锁)只取决于是否能使用索引(例如主键,unique字段),能则为行锁,否则为表锁:
未查到数据则无锁,而使用’<>’,’like’等操作时,索引会失效,自然进行的是table lock。

所以慎用for update。

整个表锁住的时候会导致性能性能降低,谨慎使用。

使用for update的时候,最好是锁主键值,或者具有unique约束的字段,
锁别的字段可能会导致整个表锁住

  • 逛敲逛练,不用 idea 开发工具,手写出JDBC开发的六步,熟练掌握JDBC里面的代码

  • 挑选一道作业题写到 Java 语句里面