使用步骤

  • 导入包:需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够了。
  • 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道
    • 注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存 中,并将其自动注册
  • 打开连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表 示与数据库的物理连接。
    • url:jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC
    • url:jdbc:mysql://localhost:3306/数据库名? useSSL=false&useUnicode=true&characterEncoding=UTF-8
  • 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
  • 从结果集中提取数据:需要使用相应的 ResultSet.getXXX() 方法从结果集中检索数据
  • 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集

    • 为确保连接关闭,您可以在代码中提供一个“finally”块。一个finally块总是执行,不管是否发生异常。 要关闭上面打开的连接,你应该调用close()
      1. package com.jdbc;
      2. import java.sql.*;
      3. public class Demo1 {
      4. public static void main(String[] args) {
      5. Connection connection = null;
      6. Statement statement = null;
      7. ResultSet resultSet = null;
      8. try {
      9. //1. 加载驱动
      10. Class.forName("com.mysql.cj.jdbc.Driver");
      11. //2. 获得链接
      12. String userName = "root";
      13. String passWord = "123456 ";
      14. String url = "jdbc:mysql://localhost:3306/practice?serverTimezone=UTC";
      15. connection = DriverManager.getConnection(url, userName, passWord);
      16. //3. 定义 sql,创建状态通道(进行sql语句的发送)
      17. statement = connection.createStatement();
      18. resultSet = statement.executeQuery("select * from department");//执行查询
      19. //4. 取出结果集信息
      20. while(resultSet.next()){
      21. // 取出数据
      22. System.out.println(resultSet.getString("departmentName"));
      23. }
      24. } catch (ClassNotFoundException e) {
      25. e.printStackTrace();
      26. } catch (SQLException throwables) {
      27. throwables.printStackTrace();
      28. } finally {
      29. try {
      30. if (resultSet != null) {
      31. resultSet.close();
      32. }
      33. if (statement != null) {
      34. statement.close();
      35. }
      36. if (connection != null) {
      37. connection.close();
      38. }
      39. } catch (SQLException throwables) {
      40. throwables.printStackTrace();
      41. }
      42. }
      43. }
      44. }

      curd

  • 对于查询数据,使用 statement.executeQuery 返回一个ResultSet对象

  • 对于增删改,使用 statement.executeUpdate 返回的是受影响的列数 int

    SQL 注入

通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令
具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎 执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据 库,而不是按照设计者意图去执行SQL语句。

  1. String username ="admin";
  2. String password=" 'abc' or 1=1 ";
  3. String sql="select * from users where username= '"+username+"' and password="+password;

PreparedStatement(预状态通道)

该PreparedStatement的接口扩展了Statement接口
JDBC中的所有参数都由?符号,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。
所述的setXXX()方法将值绑定到所述参数,其中XXX代表要绑定到输入参数的值的Java数据类型。如果 忘记提供值,将收到一个SQLException。
每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。该方法与Java数组索引不 同,从0开始。
关闭 PreParedStatement 对象

  1. String sql = "select * from parctice where userName=? and passWord=?";
  2. prepareStatement pps = connection.prepareStatement(sql);
  3. String uname='aa';
  4. String pword='123123';
  5. //给占位符赋值
  6. pps.setString(1, uname);
  7. pps.setString(2, pword);
  8. //给占位符赋值
  9. resultSet = pps.exeucteQuery();
  • statement属于状态通道,PreparedStatement属于预状态通道
  • 预状态通道会先编译sql语句,再去执行,比statement执行效率高
  • 预状态通道支持占位符?,给占位符赋值的时候,位置从1开始
  • 预状态通道可以防止sql注入,
    • 原因:预状态通道在处理值的时候以字符串的方式处理

多表操作

  • 数据库通过外键建立两表关系
  • 实体类通过属性的方式建立两表关系 实体类要求:类名=表名,列名=属性名

一对多(老师->学生)

多对一

一对一

多对多

数据库事务

一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个执行单元

四大特点

  • 原子性 actomicity
  • 一致性 consistency
  • 隔离性 isolation
  • 持久性 durability

自动提交

要启用手动事务支持,而不是JDBC驱动程序默认使用的自动提交模式,请使用Connection对象的 setAutoCommit()方法。如果将boolean false传递给setAutoCommit(),则关闭自动提交。我 们可以传递一个布尔值true来重新打开它
完成更改后,我们要提交更改,然后在连接对象上调用commit()方法,如下所示: conn.commit( );
否则,要使用连接名为conn的数据库回滚更新,请使用以下代码 -conn.rollback( );

Savepoints

JDBC 批处理

Statement批处理

以下是使用语句对象的批处理的典型步骤序列

  • 使用createStatement()方法创建Statement对象。
  • 使用setAutoCommit()将auto-commit设置为false 。
  • 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
  • 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
  • 最后,使用commit()方法提交所有更改。

PreparedStatement批处理

  1. 使用占位符创建SQL语句。
  2. 使用prepareStatement() 方法创建PrepareStatement对象。
  3. 使用setAutoCommit()将auto-commit设置为false 。
  4. 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
  5. 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
  6. 最后,使用commit()方法提交所有更改。

反射处理结果集

  1. //得到数据库中的所有的列有哪些?
  2. ResultSetMetaData metaData = rs.getMetaData();//返回数据库中的相关信息
  3. int count=metaData.getColumnCount();//得到列数
  4. String[] columnnames=new String[count];
  5. for (int i = 0; i < count; i++) {
  6. // System.out.println(metaData.getColumnName(i+1));//列的位置从1开始
  7. columnnames[i]=metaData.getColumnName(i+1);
  8. }
  9. //得到实体类中的所有的方法
  10. Method[] methods =cla.getDeclaredMethods();
  11. while(rs.next()){
  12. Object s=cla.newInstance();//调取无参构造创建对象
  13. for (String columnname : columnnames) {
  14. String name="set"+columnname;//setstuid
  15. for (Method method : methods) {
  16. if(method.getName().equalsIgnoreCase(name)){
  17. method.invoke(s,rs.getObject(columnname));//执行了对应set方法
  18. break;
  19. }
  20. }
  21. }
  22. list.add(s);
  23. }

工具类的定义

properties文件保存数据库信息-特点:key-value存储方式

db.properties

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/yhp
  3. user=root
  4. password=123456

工具类中读取属性文件

  1. InputStream inputStream = 当前类名.class.getClassLoader().getResourceAsStream("db.properties");
  2. Properties properties = new Properties();
  3. properties.load(inputStream);
  4. dirverName = properties.getProperty("driver");
  5. url = properties.getProperty("url");
  6. username = properties.getProperty("user");
  7. password = properties.getProperty("password");
  8. static{
  9. //参数只写属性文件名即可,不需要写后缀
  10. ResourceBundle bundle = ResourceBundle.getBundle("db");
  11. driver = bundle.getString("driver");
  12. url = bundle.getString("url");
  13. username = bundle.getString("user");
  14. password = bundle.getString("password");
  15. }

使用ResourceBundle访问本地资源 在设计时,我们往往需要访问一些适合本地修改的配置信息,如果作为静态变量,那么每次修改都 需要重新编译一个class,.config保存此类信息并不适合,这时我们需要ResourceBundle。 通过ResourceBundle,我们需要访问位于/WEB-INF/classes目录下的一个后缀名为properties的文本 类型文件,从里面读取我们需要的值。

连接池

连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数 据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户 也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。
而连接的建立、断开都由连接池自身来管理。
同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数 以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的 数量、使用情况等。

自定义连接池

最小连接数:

是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库 资源被浪费

初始化连接数:

连接池启动时创建的初始化数据库连接数量。

最大连接数:

是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队 列中。

最大等待时间:

当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)。

DBCP

C3P0

德鲁伊