JDBC从入门到精通-笔记(一):JDBC基本概念与开发基础

发布于:2024-06-21 ⋅ 阅读:(67) ⋅ 点赞:(0)

  视频资源:JDBC从入门到精通视频教程-JDBC实战精讲_哔哩哔哩_bilibili

JDBC定义与本质

概念

什么是JDBC:Java DataBase Connectivity

JDBC本质:SUN公司制定的一套接口(interface),java.sql.*。

                    面向接口调用,面向接口写实现类,都属于面向接口编程

                    接口相当于一种协议,调用者和使用者一般要遵守同一个接口的规则。

                    面向接口编程好处:解耦合-降低程序耦合度,提高程序扩展力。

                    多态机制是典型的面向抽象编程,使用时一般用父类引用对象,但调用子类方法。

                

JDBC接口的意义

为什么需要制定JDBC接口:因为每一个数据库的底层实现原理都不一样,如果没有接口,每连接一个新的数据库,都需要不同的代码实现。

数据库厂家编写JDBC接口的实现类,生成一组class文件,这组class文件称为驱动。所有的数据库驱动都是以jar包的形式存在,不是SUN公司提供,而是由各大数据库厂家提供,需要去各家官网下载。

数据库厂家编写JDBC接口的实现类,程序员调用这些类即可。

模拟JDBC本质

SUN公司 

/*
  SUN公司
*/
public interface JDBC {
    
    void getConnection(){}

}

 数据库厂家

        MySQL 

/*
    MySQL数据库厂家负责实现JDBC实现类
*/

public class MySQL implements JDBC {

    public void getConnection() {
        // 具体由MySQL实现
        System.out.println("连接MySQL数据库成功");
    }
}
// 实现类为MySQL驱动

        Oracle 

/*
    Oracle数据库厂家负责实现JDBC实现类
*/

public class Oracle implements JDBC {

    public void getConnection() {
        // 具体由Oracle实现
        System.out.println("连接Oracle数据库成功");
    }
}
// 实现类为Oracle驱动

 Java程序员

/*
    Java程序员
    只需要面向JDBC写代码,不用在意数据库是哪个品牌
*/
public class JavaProgrammer {
    public void static main(String[] args) throws Exception{
        // JDBC jdbc = new MySQL();
        // JDBC jdbc = new Oracle();
        // 通过反射创建对象
        Class c = Class.forName("Oracle");
        JDBC jdbc = (JDBC) c.newInstance();
        // 以下代码都是面向接口调用,不用修改
        jdbc.getConnection();
    }
}

 用反射机制就可以把数据库信息放在配置文件中,分离数据。

jdbc.properties

className = Oracle

然后调用

/*
    Java程序员
    只需要面向JDBC写代码,不用在意数据库是哪个品牌
*/
import java.util.*;

public class JavaProgrammer {
    public void static main(String[] args) throws Exception{
        // JDBC jdbc = new MySQL();
        // JDBC jdbc = new Oracle();
        // 通过反射创建对象
        // Class c = Class.forName("Oracle");
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        String className = bundle.getString("className");
        JDBC jdbc = (JDBC) c.newInstance();
        // 以下代码都是面向接口调用,不用修改
        jdbc.getConnection();
    }
}

这样,以后只要改配置文件就可以运行连接。

运行JavaProgrammer

java JavaProgrammer
> 连接Oracle数据库成功

 如果没有驱动的class文件直接运行,虽然编译能通过,但会报找不到类的错误,因为底层的实现类不存在。驱动非常重要。

使用JDBC进行开发

准备工作

从官网下载对应的驱动jar包,然后将其配置到环境变量中。

编程六步曲

  1. 注册驱动:告诉Java程序即将要连接的数据库是哪个
  2. 获取连接:表示JVM进程与数据库进程的通道打开,属于进程间通信,使用完后要关闭
  3. 获取数据库操作对象(执行sql语句的对象)
  4. 执行SQL语句:DQL DML
  5. 处理查询结果集:执行select语句后处理
  6. 释放资源:用完资源后一定要关闭资源

参考Java API 文档 - java.sql:Java Platform SE 8

注册驱动

        方法一:registerDriver(Driver driver) in class DriverManager

        注意点:

  • registerDriver是静态方法,可以直接用类名调用
  • 调用registerDriver时,其参数类型为Driver,但是在java.sql中,Driver只是一个接口,因此调用时必须使用对应驱动的实现类
  • 注意registerDriver可能存在异常,因此需要做异常处理。由于SqlException继承Exception,是受检异常,适合用try catch处理

public static void main(String[] args) {
        try {
            // 1、注册驱动
            Driver driver = new com.mysql.jdbc.Driver();// 多态,父类型引用指向子类型
            DriverManager.registerDriver(driver); // 不能直接new Driver,因为Driver是接口,需要new的Driver是实现类中的Driver
            // 2、获取数据库连接
            // 3、获取数据库操作对象
            // 4、执行sql
            // 5、处理查询结果集
            // 6、释放资源
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

        方法二:注意mysql的Driver实现类中,有静态代码块,会在类加载的时候执行一次。

 因此可以用反射机制调用该方法,方便将数据库驱动写到配置文件中去,此方法不需要接收返回值,更常用。

// 1、注册驱动
            // DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
            Class.forName("com.mysql.jdbc.Driver"); 

获取数据库连接

         方法:getConnection(String url, String user, String password) in DriverManager

        注意点:

  • getConnection为静态方法,可以直接用类名调用
  • url是数据库地址,由 协议:// ip地址:端口号/数据库名称   组成
    • url拓展:url是统一资源定位符,其中通信协议表示规定好的数据传输格式,ip地址表示计算机地址,端口号表示app代号,资源名表示要访问的资源是什么。

  • 如果不是用mysql而是oracle数据库,其格式为jdbc:oracle:thin:@127.0.0.1:1521/数据库名称,相应的,调用时Driver也需要指向oracle的driver实现类。其余也是类似的,都有指定的协议,资源
  • 返回的数据库对象com.mysql.cj.jdbc.JDBC4Connection@xxxxx中,@之前的表示类名。实际使用发现com.mysql.jdbc.Driver已经过时,被com.mysql.cj.jdbc.Driver替代,所以得到的返回对象类名是com.mysql.jdbc.ConnectionImpl。
// 2、获取数据库连接
            String url = "jdbc:mysql://127.0.0.1:3306";
            String user = "root";
            String password = "333";
            Connection connection = DriverManager.getConnection(url, user, password);// 此时connection指向的是子类对象
            System.out.println("数据库连接对象:" + connection); // 返回数据库连接对象:com.mysql.cj.jdbc.ConnectionImpl@xxxxx

获取数据库操作对象

        方法:createStatement() in Connection

// 3、获取数据库操作对象
       Statement statement= connection.createStatement();

执行sql

        如果是增删改语句,使用Statement类中的executeUpdate(String sql)方法 

        JDBC中的sql语句不用写分号

// 4、执行sql
            // String sql = "select * from tableA";
            // 专门执行DML语句 - insert, update, delete
            // 返回值为影响数据库中的记录条数
            String sql = "insert into tableA ('USER_ACCOUNT', 'TEAM') VALUES ('abc@mail.com', 'IT')";
            int count = statement.executeUpdate(sql);

        如果是查询语句,使用Statement类中的executeQuery(String sql)方法,并把结果存储到ResultSet类中,保存结果集

//4、执行sql
            String sql = "select * from tableA";
            // int executeUpdate(delete/insert/update)
            // ResultSet executeQuery(select)
            set = statement.executeQuery(sql); // executeQuery专门用于处理查询语句

处理结果集

         ResultSet中存在方法next(),是用于遍历结果集的迭代器,返回bool值。如果存在数据返回true,否则返回false。

 用rs.next()取出一行数据后,还需要通过rs中的get方法取出具体字段的value。

get方法有:getString(), getInt(),getDate()等。

getString()方法取出的数据无论在数据库是什么类型,返回的就是String类型。取数据时,可以通过列的下标(下标从1开始),也可以通过列名。推荐用列名,因为下标可能因为取顺序的数据发生改变。如果查询的时候对列名重命名了,必须用新的列名获取数据,否则会返回列不存在的错误。

getInt(),getDate()等方法不能随便使用,必须是数据库的底层数据类型与之相同的时候,才能正确执行,否则会返回数据类型无法转换的错误。

            //4、执行sql
            String sql = "select id, name a, salary b from tableA";
            // int executeUpdate(delete/insert/update)
            // ResultSet executeQuery(select)
            rs = statement.executeQuery(sql); // executeQuery专门用于处理查询语句
            //5、处理结果集
            while (rs.next()) {
                // getString()方法:不管数据库数据类型是什么,都以String类型返回
//                String flow = rs.getString(2); // jdbc中所有下标从1开始, 2表示第二列
//                String scenario = rs.getString(3); // 第三列
                // 以查询结果的列名获取(因为查询结果可以给列名重命名)
                // 除了getString, 还可以用getInt, getDate等特定类型取出数据,但必须与数据库中的数据类型对应
                int id = rs.getInt("id");
                String name = rs.getString("a");
                String salary = rs.getDouble("b");
                System.out.println("id: " + (id+200) + " - name is '" + name + "' with salary '" + salry+ "'");
                // 返回 id: 1 - name is 'Jack' with salary '5000'

关闭资源

        写在finally中,需要释放的资源提前定义,否则finally中无法调用。 

        如果是查询语句,需要先关闭ResultSet。

public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet rs = null;
        try {
            /*
            precondition
            */
            connection = DriverManager.getConnection(url, user, password);// 此时connection指向的是子类对象
            System.out.println("数据库连接对象:" + connection);
            // 3、获取数据库操作对象
            statement= connection.createStatement();
            // 4、执行sql
            // do sth
            // 5、处理查询结果集
            // do sth
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6、释放资源
            // 在finally中释放资源,从小到大关闭,关闭时分别对其try catch
            // 为了能关闭资源,定义的时候就要把需要释放的资源放在try外面定义
            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

 将连接信息放入配置文件中

jdbc.properties

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/xxx
user = root
password = 333

用ResourceBundle调用数据 

package JDBCTest;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

// 将连接数据库的所有信息放到配置文件中
/*
实际开发不建议把连接数据库信息写死到程序中
 */
public class JDBCTest04 {
    public static void main(String[] args) {
        // 使用资源绑定器绑定配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        Connection connection = null;
        Statement statement = null;
        try {
            // 1、注册驱动
            Class.forName(driver);
            // 2、获取数据库连接
            connection = DriverManager.getConnection(url, user, password);
            System.out.println("数据库连接对象:" + connection);
            // 3、获取数据库操作对象
            statement= connection.createStatement();
            // 4、执行sql
            // 专门执行DML语句 - insert, update, delete
            // 返回值为影响数据库中的记录条数
            String sql = "delete from users where id = '200'";
            // String sql = "update users set TEAM = 'a' where id = '200'";
            int count = statement.executeUpdate(sql);
            System.out.println(count == 1 ? "删除成功":"删除失败");
            // 5、处理查询结果集

        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 6、释放资源
            // 在finally中释放资源,从小到大关闭,关闭时分别对其try catch
            // 为了能关闭资源,定义的时候就要把需要释放的资源放在try外面定义
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

但实际开发不建议把连接数据库信息写死到程序中,用户体验很差。

注意:properties文件不能放错位置,否则会出现"Can't find bundle for base name jdbc, locale en_US" 的错误。要确保 jdbc.properties 文件位于类路径下。如果是标准的 Java 项目,将.properties 文件放在 src 目录下。对于 Maven 项目,应该放在 src/main/resources 目录下。

使用IDEA进行JDBC配置

新建Project后,File->Project Structure->Project Settings->Libraries

点击加号, 添加Java,选择数据库的jar包

 选择要导入的模块,如果有其他新模块新建的话,需要再导入一次。否则运行时会报类找不到错误。

然后就能在External libraries里看到了