Java操作数据库(一)——JDBC的快速入门

2,972 阅读13分钟

本文使用数据库为Mysql 8+版本

Java操作数据库(二)——结果集映射,DbUtils的快速上手

1. JDBC是什么

JDBC 的全称是(Java Database Connectivity),即Java数据库连接。

简单来说,就是一组用于执行Sql语句的Java API。


2. 导入Mysql驱动的jar包

  1. 我们建立一个标准的Java Web项目,

  2. 在WEB-INF下面建立一个package并且命名为 lib

  3. mysql-connector-java-8.0.19.jar复制到lib(不要写成libs!!!)包下面

  4. 导入jar包到library中

    • 右键lib
    • 选中Add as Library
    • 点击OK


3. JDBC常见的使用流程

在导完jar包后,想使用jdbc主要有以下几个流程

  1. 注册Driver
  2. 建立Connection
  3. 获取Statement
  4. 使用Statement执行sql语句,并获取RestultSet
  5. 操作获取的ResultSet
  6. 关闭连接

这就是一般JDBC的使用流程,大家可以先有个概念,接下来我会逐个进行讲解。


4. 快速上手JDBC

首先,我们快速建立一个用于测试的表

这是sql语句,大家直接复制粘贴就行

create database if not exists jdbc_demo

use jdbc_demo

create table user
(
    id bigint auto_increment,
    username varchar(64) not null comment '帐号',
    password varchar(64) not null comment '密码',
    constraint user_pk
        primary key (id)
)
comment '用户表';

INSERT INTO jdbc_demo.user (username, password) VALUES ('user1', '123')
INSERT INTO jdbc_demo.user (username, password) VALUES ('user2', '456')
INSERT INTO jdbc_demo.user (username, password) VALUES ('user3', '123456')

我们先分步讲解,最后进行汇总,尽量通俗易懂。

前两部分内容会比较多,后面较少

我们新建一个MyJDBCDemo1.java,并进入Main方法


4.1 注册Driver

首先,我们来注册Driver,点开Driver的源码,我们可以看到其中的文档写着(这个是IDEA 2020+版本的新特色,可以预览JavaDoc文档)


一句话总结:当一个Driver 类被加载,需要创建自己的实例并且注册到DriverManager

那么,我们就先加载Driver类。


使用Class.forName 加载 driver,该方法是用来加载类(.class)文件。

Classs.forName("com.mysql.cj.jdbc.Driver")

当一个类被加载时,会执行其中的静态代码块

我们点开driver的源码可以发现:

在第 9 行,这个driver被注册到了DriverManager

package com.mysql.cj.jdbc;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            // 创建实例并注册
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

registerDriver方法的注释写着,该方法会将driver注册到driverManager中

DriverManager又是什么呢?

我们进一步点开DriverManager的源码,可以看到其中java doc 文档中的第一行写着

The basic service for managing a set of JDBC drivers

也就是说,它是用来管理一系列JDBC 驱动的,因为不只是Mysql,也有Oracle、SqlServer等等。


小坑:

com.mysql.cj.driver是Mysql8+版本使用的

如果是Mysql5+的话,使用com.mysql.jdbc.driver


4.2 建立Connection

注册好driver之后,我们来建立Connection

// 先定义好获取Connection需要的属性
// 这个Mysql url 大家随机应变,记住mysql8+要加入时区serverTimezone
public static final String JDBC_MYSQL_URL = "jdbc:mysql://localhost:3306/jdbc_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false";
public static final String USER = "root";
public static final String PASSWORD = "123456";

// 2. 建立Connection
Connection connection = DriverManager.getConnection(JDBC_MYSQL_URL, USER, PASSWORD);

DriverManager.getConnection()该方法中有三个参数:

  1. url——数据库url
  2. 数据库用户名
  3. 数据库密码


4.3 获取Statement

利用我们刚刚建立的Connection获取Statement

Statement可以用来执行我们的sql语句

还有一个可以配合占位符使用的PrepareStatement,我们下面会简单介绍使用

// 3. 获取Statement
Statement statement = connection.createStatement();


4.4 使用Statement执行sql语句,并获取RestultSet

// 4. 编写Sql,并执行
// 这里面打sql
String sql = "select count(*) from jdbc_demo.user";

ResultSet resultSet = statement.executeQuery(sql);

// 这里建议大家先定义String sql = "";
// 然后写下一行代码,再补全sql字符串,因为这样写sql语句会有提示。


4.5 操作获取的ResultSet

// 5. 操作结果集ResultSet
// 如果结果集还有数据
while (resultSet.next()) {
    // 进行操作
    String username = resultSet.getString("username");
    System.out.println(username);
}

我们来一起看下控制台的输出结果

当当当!!!

是不是拿到数据库的数据了!是不是感觉很神奇哈哈哈 😀


4.6 关闭连接,释放资源

我们按照建立 Connection、Statement、ResultSet的倒序进行关闭

resultSet.close();
statement.close();
connection.close();

到这里我们的快速上手就结束啦!

已经可以初步使用JDBC连接数据库啦~~


完整DEMO代码

public class MyJDBCDemo1 {
    public static final String JDBC_MYSQL_URL = "jdbc:mysql://localhost:3306/jdbc_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false";
    public static final String USER = "root";
    public static final String PASSWORD = "123456";

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1. 注册driver
        Class.forName("com.mysql.cj.jdbc.Driver");

        // 2. 建立Connection
        Connection connection = DriverManager.getConnection(JDBC_MYSQL_URL, USER, PASSWORD);

        // 3. 获取Statement
        Statement statement = connection.createStatement();

        // 4. 编写Sql,并执行
        String sql = "select * from jdbc_demo.user";

        ResultSet resultSet = statement.executeQuery(sql);

        // 5. 操作结果集ResultSet
        while (resultSet.next()) {
            String username = resultSet.getString("username");
            System.out.println(username);
        }

        // 6. 关闭连接,释放资源
        // 我们按照建立 Connection、Statement、ResultSet的倒序进行关闭
        resultSet.close();
        statement.close();
        connection.close();
    }
}



接下来我们介绍下JDBC常见的API使用




5. JDBC 常见CRUD API介绍

刚刚上面我们是使用sql的查询语句。

这部分我们简单介绍下JDBC的CRUD API,大家只需要替换下第 4、5 部分就可以


C——创建

除了select,我们都会使用statementexcuteUpdate方法

这里id 写成 null,是因为我们数据库设置了自增,所以不需要id,当然自己指定也是可以的

// 4. 编写Sql,并执行
String sql = "insert into jdbc_demo.user values(null,'user4','123456')";

int i = statement.executeUpdate(sql);

// 5. 获取结果,输出1说明成功。
System.out.println(i);

我们看到控制台的确输出1,并且数据库的确有新纪录。



R——读取

我们在4.5中使用了executeQuery,使用了getString,这个是获取字符串,如果大家想要获取int等等,使用getInt(“字段名”)等等即可


U——更新

// 4. 编写Sql,并执行
String sql = "update jdbc_demo.user set username = 'userUpdated' where username = 'user4'";

int i = statement.executeUpdate(sql);

// 5. 获取结果
System.out.println(i);

基本验证也是和create部分一样,我们直接看数据库是否进行了更新


我们可以看到刚刚的第四条记录已经被正确更新了。

但是,大家看到这里,可能有一个疑问:你这里的sql语句是写死的,万一我的条件是动态的怎么 办呢?

没错,如果这样写死sql语句,的确会有很多问题。

大家还记得上面说的PrepareStatement吗?我们下一部分会介绍使用用它来解决这个问题。


D——删除

// 4. 编写Sql,并执行
String sql = "delete from jdbc_demo.user where username = 'userUpdated'";

int i = statement.executeUpdate(sql);

// 5. 获取结果
System.out.println(i);

我们来直接看数据库结果

可以发现确实第四条记录被删除了。

接下来我们就介绍以下PrepareStatement的使用。

6. PreparedStatement

PrepardStatement可以解决sql语句被写死的问题

还记得我们上面使用Statement的顺序吗,我们是利用connection直接建立。

PreparedStatement的使用则有一些不同

  • 我们需要先写sql语句
  • 然后直接利用connection获取preparedStatement并装配sql语句
// 3. 编写Sql(?就是占位符)
String sql = "delete from jdbc_demo.user where username = ?";

// 4. 获取PreparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(sql);

// 5. 设置占位符(这里index是从1开始,不是从0!!!)
preparedStatement.setString(1"user1");

// 6. 执行
int i = preparedStatement.executeUpdate();

// 7. 输出结果
System.out.println(i);

我们来看下数据库的结果

我们可以看到user1的确被删除了。

平常如果是要做登录案例什么的,就可以使用PreparedStatement


7. 封装简单的JDBC工具类

看完上面的内容,大家可能还是有疑惑,我难道每使用一次statement,都要写属性,创建连接,释放连接,这么麻烦吗?

为了解决刚刚说的问题,我们可以封装一个简单的工具类,让我们更加专注于编写业务逻辑。

这是工具类的代码,大家简单看下,直接复制就可以。

这里获取属性没有使用Properties文件,大家可以根据自己需要,自行修改

package utils;

import java.sql.*;

/**
 * @author Lemonfish
 * @version V1.0
 * @Package utils
 * @date 2020/5/14 10:29
 */

public class JDBCUtil {
    /**
     * 数据库URL
     */

    public static final String JDBC_MYSQL_URL = "jdbc:mysql://localhost:3306/jdbc_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false";
    /**
     * 数据库帐号
     */

    public static final String USER = "root";
    /**
     * 数据库密码
     */

    public static final String PASSWORD = "123456";

    // 静态代码块,用于初始化
    static {
        // 注册driver
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Connection
     * @return Connection
     */

    public static Connection getConnection(){
        Connection connection = null;
        try {
            // 建立Connection
            connection = DriverManager.getConnection(JDBC_MYSQL_URL, USER, PASSWORD);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

    /**
     * @Description  关闭全部
     * @param connection connection
     * @param statement statement
     * @param resultSet resultSet
     * @return void
     */

    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
        closeResultSet(resultSet);
        closeStatement(statement);
        closeConnection(connection);
    }

    /**
     * @Description 除了ResultSet,关闭其他全部
     * @param connection connection
     * @param statement statement
     * @return void
     */

    public static void closeWithoutResultSet(Connection connection, Statement statement) {
        closeStatement(statement);
        closeConnection(connection);
    }

    /**
     * @Description  关闭Connection
     * @param connection connection
     * @return void
     */

    public static void closeConnection(Connection connection) {
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    /**
     * @Description 关闭Statement
     * @param statement statement
     * @return void
     */

    public static void closeStatement(Statement statement) {
        try {
            statement.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    /**
     * @Description 关闭ResultSet
     * @param resultSet resultSet
     * @return void
     */

    public static void closeResultSet(ResultSet resultSet) {
        try {
            resultSet.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

接下来,我们使用刚刚封装的工具类,看看效果怎么样

public class MyJDBCDemo6 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        // 1.获取连接
        Connection connection = JDBCUtil.getConnection();

        // 2.获取statement
        Statement statement = connection.createStatement();

        // 3. 编写Sql,并执行
        String sql = "delete from jdbc_demo.user where username = 'user3'";

        // 4 执行
        int i = statement.executeUpdate(sql);

        // 5. 输出结果
        System.out.println(i);

        // 6. 断开连接
        JDBCUtil.closeWithoutResultSet(connection,statement);
    }
}

这样代码是不是看起来会清爽很多?OvO

我们来看下数据库的结果,可以发现user2确实被删掉了。


8. 写在最后

本文就到这里结束啦~

简单介绍了一些JDBC的使用方法,但是JDBC还有其他内容,大家可以自己探索。

如果想要获取实体类对象的话,可以使用commons-dbutilsQueryRunner

再往后使用框架会更加方便,比如Spring Data Jpa / Mybatis(建议配合Mybatis-Plus使用)

如果觉得对你有帮助的话,欢迎点个👍赞喔,谢谢支持!

希望大家能一起进步~~