跳至主要內容

MySQL数据库

wangdx大约 43 分钟

数据库简介

电脑之中对于所有的数据的操作都是围绕在 CPU 和内存之中的,也就是说一旦断电那么所有的数据一定会随之消失,所以对于数据的存储就特别重要了,在早期的时代需要通过各种打孔机来实现数据的记录,随后又有了软件,硬盘等存储的介质,数据是整个计算机行业之中的最为重要的核心基础。

既然已经可以实现了数据的存储,那么就需要想办法让这些数据可以以更好的结构的方式来存储,在早期的时候会将许多的数据以文件的形式进行保存,所以就造成了不同软件商彼此之间会指定不同的文件存储标准,这样的操作环境明显不符合于当前设计的主流,因为大家需要考虑的是公共的存储标准,那么在 70 年代的时候 IBM 的一个分析员发布了一篇非常重要的论文:《论关系型数据库的发展》,随后在世界上就产生了几十种的关系型数据库(也包括了 Oracle 数据库),到了 80 年代的时候虽然关系型数据库得到了良好的发展,可是不同的厂商针对于各自的数据库都提供有各自的处理命令,这样就使得很多数据库的工作人员不得不学习大量且重复的数据库使用,所以这个时候由 IBM 在 80 年代公布了 SQL 语句标准(Oracle 数据库是最早实现 SQL,标准的数据库),这样就确定了数据库未来的发展,一直到今天为止,数据库的 SQL 操作是在不断完善,数据库的功能也在不断加强。

提示

数据库(Database)是现代项目开发中所不可或缺的重要数据管理软件,在数据库中提供了数据的标准存放结构,这样所有的数据都可以按照有序的方式进行存储,同时也可以使用 SOL 实现数据操作(查询、更新、定义)。

SQL(Structured QueryLanguage、结构化查询语句)是由 IBM 开发并推广的数据库操作的标准语言,可以针对于数据库实现数据查询、数据更新、数据库对象定义以及授权管理等操作。

对于现代的软件开发来讲,是完全离不开数据库的,而只要你掌握了 SOL 语句,那么就可以掌握数据库的常规的使用

数据库主要用于数据存储记录,但是为了可以更加清晰的实现数据的存储,所以在数据库里面最为基础的存储单元--数据表(Table),每一张表都拥有若干个字段,每一个字段都可以保存特定的数据类型。

世界上的关系型数据库有几百种之多,而且除了关系型数据库之外还会存在有许多的非关系型数据库(NoSQL 数据库)又有几十种之多,所以本次选择讲解的是 MySOL 数据库。

提示

在国内比较常见的与 Java 匹配数据库有三种:Oracle 数据库、IBM-DB2 数据库、MySOL 数据库,在很多传统的项目开发之中,对于 Oracle、DB2 数据库使用特别的多(尤其是在许多的政务项目、财务项目),而在互联网行业的开发过程之中 MVSOL 数据库是最为常用的一种。

mysql 常用数据类型

mysl 数据库

本次在进行数据库编程讲解的时候主要使用的是 MVSOL 数据库,从历史的发展来讲,世界上有著名的商用数据库:Oracle、IBM DB2、MicrosofSOLServer,随着技术的发展,很多人发现这些商用数据库后面往往都需要非常昂贵价钱才可以正常购买到服务,不过随着时代的发展以及开源风潮普及,实际上许多的商用数据库都开始考虑免费提供服务了(软件免费、服务费用高昂)。

MySOL 天生就是一款开源的关系型数据库,并且使用的人群众多,同时在国内的使用比率也是非常高的,因为国内许多的开发公司为了节约软件开发成本,那么往往会使用大量免费开源的工具,所以 MSOL,这种小巧的而且免费的数据库就非常受欢迎(随着 MySQL 版本的不断提升,很多的功能也都在不断完善)、。

MySQL 是一个小型关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Orace 公司的数据库产品。在实际使用中由于 MVSOL 数据库体积小、速度快、开源等众多优点被许多互联网公司所使用,开发者如果要使用 MVSOL 数据库产品,直接登录“www.mysql.com”即可进行下载。

提示

MySOL 的坎坷历史:

  • 1.MySQL 是一款最为著名的开源软件,在 2008 年的时候被当时的 SUN 公司花费 10 亿美金收购;
  • 2、当 SUN 公司收购了 MySQL 之后实际上 SUN 公司并没有对 MySQL 发展起到决定性的作用;
  • 3.在 2009 年的时候,Oracle 公司又以 74 亿美金收购了 SUN 公司,于是 Orace 就拥有了 MySQL,数据库的版权;
  • 4.Oracle 当时是以收费数据库为主的,所以不会经营 MSOL 这样开源数据库,曾经一度想放弃 MVSOL 研发(后来世界的开源组织的人士发起了各种抗议,Oracle 才对 MySOL 继续保留);
  • 5、 后来 Oracle 开始加大 MySOL 开发,最终也推出了许多新的版本。

mysql 安装和配置

MySQL 是一个免费的开源数据库,但是需要注意的是,对于 MSQL 比较新的开发版本都需要开发者手工进行大量的配置,所以此部分讲解的内容之中会有很多的操作步骤,请所有的安装 MYSQL 的同学们一定要遵守我给出的操作步骤。

既然现在是在 Windows 系统下进行 MVSOL,数据库的安装,所以就选择默认的 Windows 系统即可(使用 Win10 系统安装,如果使用的是一些老系统安装新版本的 MySQL 的时候往往需要安装大量的系统补丁)。

1.下载 https://dev.mysql.com/downloads/mysql/8.0.html

2.替换 my.ini 并配置系统环境变量

[mysqld]
#设置3306端口
port=3306
#设置mysq1的安装目录
basedir=C:\mysql8
#设置mysql数据库的数据的存放目录
datadir=D:\mysql-dc\data
#mysqlsock存储目录
socket=D:\mysq1-dc\data\mysql.sock
#允许最大连接数
max_connections=10000
#允许连接失败的次数。这是为了防止有人从该主机试图攻击数据
max_connect_errors=10
#服务端使用的字符集默认为UTF8
character-set-server=UTF8MB4
#创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
#默认使用“mysql native password”插件认证
default_authentication_plugin=mysql_native_password
[mysql]
#设置mysql客户端默认字符集
default-character-set=UTF8MB4
# mysqlsock存储目录
socket=D:\mysql-dc\data\mysql.sock
[client]
#设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8
[mysqld_safe]
log-error=D:\mysql-dc\logs\mysql.log
pid-file=D:\mysql-dc\logs\mysql.pid
#mysqlsock存储目录
socket=D:\mysql-dc\data\mysql.sock

3.【数据库初始化】MYSQL,如果要进行文件存储则一定要生成一些属于自己的结构性文件,而这些文件也都应该保存在数据目录下,如果要想生成这些内容,那么就必须通过 MySQL 提供的命令来完成。

mysqld --initialize --console

当进行 MySQL 数据库初始化的时候会自动生成一个临时的密码“QISglojUc6-I”,在没有修改之前就只能够通过此密码进行 MySQL 数据库访问

4.【服务安装】如果在 Windows 系统之中由于本身直接提供有系统服务管理,那么可以通过服务进行 MySQL 服务启动,所以可以考虑将当前的 MySQL 启动命令添加到服务之中。

mysqld install mysqld remove

使用命令控制

net start mysql net stop mysql

5.登数据库

mysql -uroot -pQfSglojUc6-I

6.修改密码和远程登录配置

alter user 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysqladmin' ;

use mysql update user set user.Host='%' where user.User='root' ; flush privileges ;

7.测试

mysql -uroot -pmysqladmin quit

mysql 操作命令

#数据库查询
SHOW DATABASES ;
#创建数据库
CREATE DATABASE yootk CHARACTER SET UTF8 ;
#使用数据库
USE yootk ;
##创建数据表
##判断user表是否存在了,如果存在则删除
DROP TABLE IF EXISTS user ;
CREATE TABLE user(
	uid BIGINT AUTO_INCREMENT COMMENT '主键列(自动增长)' ,
	name VARCHAR(30) COMMENT '用户姓名' ,
	age INT	 COMMENT '用户年龄' ,
	birthday DATE COMMENT '用户生日' ,
	salary FLOAT COMMENT '用户月薪' ,
	note TEXT COMMENT '用户说明' ,
	CONSTRAINT pk_uid PRIMARY KEY (uid)
) engine=INNODB ;
#查询当前数据引擎
SHOW ENGINES ;
#查询所有数据表
SHOW TABLES ;
#数据表结构查询
DESC user ;
#数据表数据插入
INSERT INTO user(name,age,birthday,salary,note) VALUES ('李兴华', 18, '2008-08-13', 8000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言优拓', 18, '2009-09-15', 9000.0, 'www.yootk.com') ;
#数据表数据查询,条件查询
SELECT * FROM user ;
SELECT * FROM user WHERE name LIKE '%沐言%' AND age=18 ;
#自增最大查询
SELECT LAST_INSERT_ID() ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-A', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-B', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-C', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-D', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-E', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-F', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-G', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-H', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-I', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-J', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-K', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-L', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-M', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-N', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-O', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-P', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-Q', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-R', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-S', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-T', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-U', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言童趣-V', 18, '2008-07-17', 3000.0, 'www.yootk.com') ;


SELECT * FROM user WHERE name LIKE '%沐言%' LIMIT 0,3 ;

#更新数据表数据
SELECT * FROM user WHERE uid=1 ;
UPDATE user SET age=20,salary=8100.0 WHERE uid=1 ;
SELECT * FROM user WHERE uid=1 ;

UPDATE user SET note='沐言优拓:www.yootk.com' ;
#数据表数据总数
SELECT COUNT(*) FROM user ;
#数据表删除
DELETE FROM user WHERE uid IN (5,6,7) ;

JDBC 连接 MySQL 数据库

通过之前的操作已经可以在项目里面通过 MySQL 数据库实现相关的数据处理操作了,但是这个时候会有一个问题,MySQL 数据库所提供的客户端的操作环境(一般会使用一些第三方工具作为前端展示,而 MySQL 本身提供的只是命令的前端)来实现数据的相关操作,但是这种操作仅仅适合于几个特定的用户,如果说现在有成千上万的用户要进行数据库的访问,那么就不可能让这些用户直接进行数据库的操作,因为数据库的资源太重要了,这个重要的资源一定要通过一些其他的途径来进行控制。

Java 是一门设计非常完善的编程语言,如果使用 Java 语言进行数据库的开发是可以更加实现业务上的信息描述的,这样就可以为数据库追加一个程序的外壳,所有的用户都通过这个外壳来实现相关的业务功能,在 Java 程序设计之中提供有一个 JDBC(JavDatabase Connective)服务组件,这是一套标准的 Java 数据库访问操作,不同的数据库生厂商依据此标准实现各自数据库的开发。最终就能够通过 Java 来实现所有数据库的控制了。

在 Java 的数据库编程开发过程之中,实际上提供有四种 JDBC 的访问模式。

  • 1、【Java 原生实现】JDBC-ODBC 连接。通过 JDBC-ODBC 驱动程序模式来实现数据库的连接,此时的数据库要先连接到微软的 ODBC 上,随后再 通过 Java 访问 ODBC 实现数据库的开发操作。

此时的做法需要中间经历其他的数据库的操作标准实现 Java 数据库的处理开发,很明显,这种操作的机制一定会存在有性能上的问题,所以现实的正规项目开发过程之中是不会采用此类模式的。

  • 2、【第三方实现】JDBC 本地连接,既然 ODBC 的模式性能很差,所以最佳的做法是直接通过 JDBC 标准去连接数据库进行处理操作,所以这种 性能是最佳的。这种方式最大的缺点在于需要进行第三方组件包的配置(数据库生产商要手工实现 JDBC 标准子类)。
  • 3.【第三方实现】JDBC 网络。在现实的项目开发过程里面,都需要通过专门的数据库主机实现数据库信息的存放,所以所有 3 的程序所在的主机都需要通过远程的网络方式进行数据库的连接控制,这样最为常用的数据库的开发模式就是网络连接方式。
  • 4.【自定义实现】利用 JDBC 协议标准创建属于自己的连接模式,不过一般这种的开发难度较高,大部分的公司是不会使用的。

在整个的 JDBC 的开发过程之中,最为常用的开发包为 java.sql 包,在这个包中就定义有数据库的连接标准、数据库的操作标 准以及数据库的结果集的处理标准。

对于 SQL 数据库来讲如果要想操作则肯定要先的功能就是进行数据库的连接操作,但是在 Java 之中除了 JDBC-ODBC 之外所有的数据库都必须下载相应的数据库驱动程序后才可以实现数据库的操作,那么这个时候首先 一定要先去下载 MVSOL 数据库驱动程序,本次的数据库的版本是 MySOL8.0.18,版本一定要与驱动进行匹配。

如果要想获得 MySQL 的驱动程序那么可以直接登录 Maven 中央仓库:htps://mvnrepository.com/,

找到与当前的 MySQL 相匹配的数据库的驱动版本(如果不匹配某些版本可以使用,但是不确定是否可以正常用)。

1.idea 下载完成之后可以得到“mysql-connector-java-8.0.18.jar”驱动程序包,直接将这个驱动程序的“*.jar”文件直接在项目中进行 配置定义即可。

2.text 以上所实现的 MySOL,数据库的驱动配置仅仅是在开发工具的环境下完成的,如果说你现在需要通过手工记事本的方式进行代 码的开发,那么就需要将驱动程序配置到项目的 CLASSPATH 之中

那么现在驱动程序配置完成之后,随后就可以实现数据库的连接定义了,如果要想实现数据库的连接,这个时候需要使用到 DriverManager 类以及 Connection 接口,来观察程序的实现 JavaDoc 文档,java.sql 开发包并不是在“java.base”模块之中提供的,它是在“java.sql”模块里面提供的。

-- 1.数据库驱动管理:java.sql.DirverManager 类,在此类中提供有如下一个获取数据库连接的操作方法:

public static Connection getConnection(String url, String user, String password) throws SOLException

  • 通过 getConnection()方法的定义可以发现如果要想获得数据库的连接需要提供有三个重要的参数内容:

    • 数据库连接地址:不同的数据库有不同的数据库连接地址,整个的 JDBC 依靠地址来区分数据库:
      • MySOL 连接地址:jdbc:mysql://主机名称:3306/数据库名称;
    • 数据库用户名:root;
    • 数据库密码:mysqladmin
  • 2.数据库连接:java.sql.Connection 接口,这个接口对象实例负责保存每一个具体的数据库的连接对象。

案例
package com.yix.mysql.w01;

import java.sql.Connection;
import java.sql.DriverManager;

/**
 * @author wangdx
 */
public class Demo {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        System.out.println(conn); // 如果连接对象不为空,则表示连接成功
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

JDBC 连接分析

通过之前的讲解已经可以非常清晰的实现了整个 JDBC 连接管理,但是现在肯定有人不太理解了,为什么在使用 JDBC 进行数据库连接的时候需要这么多步骤,那么下面就对于当前的程序的执行结果进行一次完整的说明。

  • 1.不同的数据库如果要想实现 JDBC 的访问,则肯定要求提供有数据库的驱动程序包,首先来打开 MySQL 数据库连接驱动程序的类定义:

    public class Driver extends NonRegisteringDriver implements java.sql.Driver {}

  • 2 不同的数据库的驱动程序被封装在 jar 文件里面,这样一旦将其设置在了 CLASSPATH 属性范围之内,就可以通过反射实现加载,而这个时候 DriverManager 和这些具体的子类都没有直接的耦合,因为是通过类名称实现的加载;

  • 3.当 DriverManager 类获得了 Driver 接口的子类之后就可以直接进行该类对象实例化,实例化完成后再通过 Driver 接口提供的 connect()方法获取 Connection 接口对象实例。

而通过整体的分析的操作就可以明确的发现原来 DriverManager 类是一个 JDBC 工厂类,该类的主要功能就是创建若干个 Conection 接口对象实例,而最关键的问题在于每当通过“DriverManage.getConnection()”方法获取连接的时候都表示要进行一个新的数据库连接的创建,这一个过程是需要进行若干次的 Socket 连接处理的,即:数据库的连接本身是属于一种非常耗时的操作。

Statement 数据操作接口

既然现在已经获得了数据库的连接,那么并不是说连接获得之后就直接关闭数据库,那么在 DBC 里面针对于数据库的数据操作提供有一个 Statement 接口,而如果要想获得 Statement 接口对象实例,就可以通过 Connection 接口完成,首先来观察一下 Connection 接口中提供的获取 Statement 接口对象方法:

当获得了 Statement 接口对象实例之后就可以通过 Statement 接口中的方法实现数据库中两个重要操作。

public boolean execute(String sql)throwsSOLException . public ResultSet executeQuery(String sql) throwsSOLException .

那么此时就可以通过 Statement 实现数据库的更新与査询处理,但是需要注意的是,每一个 Statement 接口对象实例实际上都会包含有一个要执行的 SOL 语句。

数据更新

在 SQL 数据库之中对于数据的更新操作一共分为三类:数据增加、数据修改、数据删除,而且这三类的处理操作只要编写正常的 SQL 语句即可,而 Statement 接口最大的特点是可以直接执行完整的 SQL 语句。

案例

1.初始化数据库

DROP DATABASE IF EXISTS yootk ;
CREATE DATABASE yootk CHARACTER SET UTF8 ;
USE yootk ;
-- 【注释】
CREATE TABLE user(
	uid BIGINT AUTO_INCREMENT COMMENT '主键列(自动增长)' ,
	name VARCHAR(30) COMMENT '用户姓名' ,
	age INT	 COMMENT '用户年龄' ,
	birthday DATE COMMENT '用户生日' ,
	salary FLOAT COMMENT '用户月薪' ,
	note TEXT COMMENT '用户说明' ,
	CONSTRAINT pk_uid PRIMARY KEY (uid)
) engine=INNODB ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('李兴华', 18, '2008-08-13', 8000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('沐言优拓', 18, '2009-09-15', 9000.0, 'www.yootk.com') ;
INSERT INTO user(name,age,birthday,salary,note) VALUES ('VIP学院', 18, '2009-09-15', 78000.0, 'yootk.ke.qq.com') ;
COMMIT ;

2.java 新增数据

package com.yix.mysql.w02;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
 * @author wangdx
 */
public class Demo {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement stmt = conn.createStatement() ; // 创建数据库的操作对象
        // 在以后编写SQL语句的中如果要追加换行,最佳的做法是在前后多追加一个空格
        String sql = " INSERT INTO user(name,age,birthday,salary,note) VALUES " +
                "  ('小李老师', 18, '2008-08-13', 3000.0, 'www.yootk.com') " ;
        // 所有的数据库的更新处理都会有一个影响的数据行数信息提示,而此时的方法返回值就是影响的数据行个数
        int count = stmt.executeUpdate(sql) ; // 执行SQL并返回更新的数据行数
        System.out.println("【数据更新操作】影响的数据行数:" + count);
        // 如果现在直接关闭了数据库连接,那么整个的数据库的所有的Statement对象也就自动关闭了
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

观察数据更新错误

....
String sql = " INSERT INTO user(name,age,birthday,salary,note) VALUES " +
                "  ('小李'老师', 18, '2008-08-13', 3000.0, 'www.yootk.com') " ;

....

此时的程序执行之后由于是在整个的 SOL 命令中存在有错误的代码,所以当程序执行完毕之后就会出现有“SQLSyntaxErrorException”错误信息,而这就属于整个 JDBC 中的异常,观察此异常的继承结构:

java.lang.Object |- java.lang.Throwable |- java.lang.Exception |- java.sql.SQLException |- java.sql.SQLNonTransientException |- java.sql.SQLSyntaxErrorException

按照整个异常处这个时候通过整个的异常类的继承结构可以发现,在 DBC 里面最大的异常类型实际上是“SQLException”,理的流程来讲话,这个时候如果要想进行全部 JDBC 异常捕获的话,最简单的做法就是直接捕获“SQLException”

3.java 更新数据

// 在以后编写SQL语句的中如果要追加换行,最佳的做法是在前后多追加一个空格
String sql = "UPDATE user SET name='李兴华编程训练营', age=1 WHERE uid=3" ;
// 所有的数据库的更新处理都会有一个影响的数据行数信息提示,而此时的方法返回值就是影响的数据行个数
int count = stmt.executeUpdate(sql) ; // 执行SQL并返回更新的数据行数

4.java 更新数据

String sql = "DELETE FROM user WHERE name LIKE '%李兴华%'" ;
// 所有的数据库的更新处理都会有一个影响的数据行数信息提示,而此时的方法返回值就是影响的数据行个数
int count = stmt.executeUpdate(sql) ; // 执行SQL并返回更新的数据行数

所有的数据更新操作都会根据影响到的数据行来进行相应更新行数字的统计,在以后的实际项目开发过程之中,如果要想明确的知道某一个更新操作是否可以正确的执行,那么只要判断其影响的数据行数是否大于 0 即可。

5.查询数据

在整个数据库的开发过程之中数据的査询操作是最复杂的,因为查询会牵扯到各种复杂査询的管理,例如:多表查询、子查询、统计查询、集合操作等等,但是从现代的开发来讲,对于数据的查询如果非必须的情况下建议以简单查询为主。

class QueyDemo{
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement stmt = conn.createStatement() ; // 创建数据库的操作对象
        // 在以后编写SQL语句的中如果要追加换行,最佳的做法是在前后多追加一个空格
        String sql = " SELECT uid,name,age,birthday,salary,note FROM user " ;
        ResultSet rs = stmt.executeQuery(sql) ; // 数据库查询
        while (rs.next()) { // 判断是否还有数据
            long uid = rs.getLong("uid") ;
            String name = rs.getString("name") ;
            int age = rs.getInt("age") ;
            Date birthday = rs.getDate("birthday") ;
            double salary = rs.getDouble("salary") ;
            String note = rs.getString("note") ;
            System.out.printf("【查询结果】编号:%s、姓名:%s、年龄:%d、生日:%s、工资:%f、介绍:%s\n", uid, name, age, birthday, salary, note);
        }
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

class QueyDemo1{
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement stmt = conn.createStatement() ; // 创建数据库的操作对象
        // 在以后编写SQL语句的中如果要追加换行,最佳的做法是在前后多追加一个空格
        String sql = " SELECT uid,name,age,birthday,salary,note FROM user " ;
        ResultSet rs = stmt.executeQuery(sql) ; // 数据库查询
        while (rs.next()) { // 判断是否还有数据
            long uid = rs.getLong(1) ;
            String name = rs.getString(2) ;
            int age = rs.getInt(3) ;
            Date birthday = rs.getDate(4) ;
            double salary = rs.getDouble(5) ;
            String note = rs.getString(6) ;
            System.out.printf("【查询结果】编号:%s、姓名:%s、年龄:%d、生日:%s、工资:%f、介绍:%s\n", uid, name, age, birthday, salary, note);
        }
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

class QueyDemo2{
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement stmt = conn.createStatement() ; // 创建数据库的操作对象
        // 在以后编写SQL语句的中如果要追加换行,最佳的做法是在前后多追加一个空格
        String sql = " SELECT uid,name,age,birthday,salary,note FROM user " ;
        ResultSet rs = stmt.executeQuery(sql) ; // 数据库查询
        while (rs.next()) { // 判断是否还有数据
            Object uid = rs.getObject(1) ;
            Object name = rs.getObject(2) ;
            Object age = rs.getObject(3) ;
            Object birthday = rs.getObject(4) ;
            Object salary = rs.getObject(5) ;
            Object note = rs.getObject(6) ;
            System.out.printf("【查询结果】编号:%s、姓名:%s、年龄:%d、生日:%s、工资:%f、介绍:%s\n", uid, name, age, birthday, salary, note);
        }
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

class QueyDemo3{
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement insertStatement = conn.createStatement() ; // 创建数据库的操作对象
        String insertSQL = " INSERT INTO user(name,age,birthday,salary,note) VALUES " +
                " ('李兴华', 18, '2008-08-13', 8000.0, 'www.yootk.com')" ;
        String selectSQL = "SELECT LAST_INSERT_ID()" ;
        int count = insertStatement.executeUpdate(insertSQL) ; // 更新SQL语句
        insertStatement.close(); // 关闭第一个数据库操作对象,释放资源
        if (count > 0) {    // 已经有了更新行数
            Statement selectStatement = conn.createStatement() ; // 创建数据库的操作对象
            ResultSet rs = selectStatement.executeQuery(selectSQL) ; // 数据查询
            if (rs.next()) {    // 只有一个结果
                System.out.println("【数据更新成功】当前新数据的ID内容为:" + rs.getLong(1));
            }
        }
        conn.close();
    }
}

在执行的过程之中由 Statement 接口的对象实例向数据库发出一条査询指令,随后这个数据库的查询返回的结果会自动通过 Resutset 接口对象实例进行包装,这些数据就被加载到内存之中了,如果此时数据查询返回的结果过多的话,那么就会造成 JVM 的内存占用率过高,从而导致程序有可能出现内存溢出的问题。

如果要想通过 ResultSet 获取数据直接使用 getXxx()方法即可,其中“Xxx”对应的是不同的数据类型,例如:getLong()、getString()、getDate()等。

此时由于查询语句上已经明确的给出了查询列的定义,这样就可以通过索引号方便的实现结果集中列数据的获取了。虽然通过具体的 getXxxO 的形式可以获得相应的列数据信息,但是在 Resultset 接口里面针对于结果列的获取还有另外一个简单方法:

提示

提示:现在所使用的 JDBC 操作形式属于 JDBC 10 的时候所具备的流程,但是相比较原始的 JDBC 版本来讲,现在的 JDBC 开发要方便许多,因为有如下两个问题解决了:

  • 在 JDBC 早期版本里面,所有的列数据必须按照顺序的方式获取,如果顺序错乱,则无法获取:
  • 所有的数据只能够获取一次,如果重复获取也会出错。

通过以上的程序已经实现了完整的数据的 CRUD 处理,那么下面尝试创建两个 Statement 对象一个实现数据的增加,另外一个 实现获取增长后 ID 的内容(数据库查询)。

PreparedStatement 数据操作接口

在 java.sql 包中已经提供了一个 Statement 数据操作接口实现数据的 CRUD 操作,那么为什么又在 java.sql 包里面提供有另外 个 PreparedStatement 接口实现数据操作呢?如果要想解决当前的疑问,首先最佳的做法是来研究一下 Statement 操作问题

Statement 使用问题分析

Statement 接口是 JDBC 之中提供的标准数据操作接口,并且在这个接口中可以直接执行 SQL 语句,但是在使用这个接口会有个非常麻烦的问题:它必须执行标准的 SQL 语句。

问题引出
public class Demo {
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String name = "Mr'Lee'" ; // 终极问题:内容包含有单引号
        int age = 16 ;
        String birthday = "2009-08-13" ; // 问题1:日期使用字符串描述
        double salary = 6900.0 ; // 工资
        String note = "宇宙无敌超级可爱的小李老师在沐言科技任教:www.yootk.com" ;

        Statement statement = conn.createStatement() ; // 创建数据库的操作对象
        String sql = "INSERT INTO user(name,age,birthday,salary,note) VALUES " +
                " ('" + name + "', " + age + ", '" + birthday + "', " + salary +
                ", '" + note + "')";    // 问题2:字符串的定义结构看起来很麻烦
        System.out.println("【拼凑的SQL】" + sql);
        int count = statement.executeUpdate(sql) ; // 更新SQL语句
        System.out.println("【数据更新行数】" + count);
        statement.close(); // 关闭第一个数据库操作对象,释放资源
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}

对于当前给定的程序 SQL 语句来讲,最大的问题出现在拼凑之后的 SQL 是错误的,因为这个时候给出的 SQL 语句中多了一个单引号“'”,而在 SQL 语法里面单引号所的是字符串的分隔符。即使现在整个的程序可以正常的执行,但是也会发现这种利用拼凑的方式实现的 SQL 从结构上来讲是非常难以维护的,所以为了解快这些问题才推出了一个新的接口-- PreparedStatement,在实际项目开发过程之中基本上使用最多的数据操作接口就是 PreparedStatement。

利用 PreparedStatement 接口是可以解决 Statement 接口所存在的问题的,但是如果要想使用 PreparedStatement 之前首先需要观黎、下其继承的结构以及相关的对象实例化的处理操作。

public interface PreparedStatement extends Statement

通过继承结构可以发现 PreparedStatement 属于 Statement 子接口,而要想获取 PreparedStatement 子接口的对象实例,则依然需要通过 Connection 接口所提供的方法来完成:

public PreparedStatement prepareStatement(String sql) throws SQLException

通过此方法的对比可以发现与创建 Statement 接口对象实例的方法不同,在创建 PreparedStatement 接口实例的时候需要明确的传入一个 SQL,因为这个 SQL 需要进行预处理,所谓的预处理非常的好理解,就是指针对于要执行的 SQL 语句格式进行一个解析执行,但是对于要处理的数据还不能够操作,在获取了 PreparedStatement 接口对象实例之后再考虑获取相关的数据内容

数据更新

在之前分析 Statement 接口的时候所采用的就是一种数据增加的更新处理才发现的问题,同样现在将通过 PreparedStatement 接口来解决之前所遇到的问题。 在使用 PreparedStatement 接口的时候由于需要准确的设置数据的操作类型,所以在进行日期设置的时候就需要有一个非常重要的说明:PreparedStatement 支持的是 java.sql.Date,而不支持 java.util.Date 对象实例,观察具体的方法定义。

详情
class PreparedStatementDemo{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        String name = "Mr'Lee'" ; // 终极问题:内容包含有单引号
        int age = 16 ;
        Date birthday = new Date() ; // 日期就使用java.util.Date描述
        double salary = 6900.0 ; // 工资
        String note = "宇宙无敌超级可爱的小李老师在沐言科技任教:www.yootk.com" ;
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "INSERT INTO user(name,age,birthday,salary,note) VALUES (?, ?, ?, ?, ?)" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setString(1, name);
        preparedStatement.setInt(2, age);
        preparedStatement.setDate(3, new java.sql.Date(birthday.getTime()));
        preparedStatement.setDouble(4, salary);
        preparedStatement.setString(5, note);
        int count = preparedStatement.executeUpdate() ; // 执行SQL操作
        System.out.println("【数据更新】影响到的数据行数:" + count);
        conn.close();
    }
}

class PreparedStatementDemo1{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        String name = "Mr'Lee'" ; // 终极问题:内容包含有单引号
        int age = 16 ;
        Date birthday = new Date() ; // 日期就使用java.util.Date描述
        double salary = 6900.0 ; // 工资
        String note = "宇宙无敌超级可爱的小李老师在沐言科技任教:www.yootk.com" ;
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "INSERT INTO user(name,age,birthday,salary,note) VALUES (?, ?, ?, ?, ?)" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setObject(1, name);
        preparedStatement.setObject(2, age);
        preparedStatement.setObject(3, new java.sql.Date(birthday.getTime()));
        preparedStatement.setObject(4, salary);
        preparedStatement.setObject(5, note);
        int count = preparedStatement.executeUpdate() ; // 执行SQL操作
        System.out.println("【数据更新】影响到的数据行数:" + count);
        conn.close();
    }
}

以上的操作是针对于不同的数据类型使用了不同的 setXxx()方法,而在 Preparedstatement 接口中为了简化这一繁琐的数据类型的区分问题,所以可以通过 setObiectO)方法实现占位符数据的配置。

数据查询

所有数据的操作过程之中数据更新和数据的查询操作如果可以使用,那么基本上就可以直接上手开发了,如果使用 PreparedStatement 接口来实现数据査询本质和 Statement 接口中的数据査询的实现机制是非常类似的,唯一的区别就在于,执行查询的时候 Preparedstatement 不再需要重复配置 SQL,下面通过几个实际的开发案例讲解具体的查询实现。

详情
class PreQueryDemo{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "SELECT uid,name,age,birthday,salary,note FROM user WHERE name=?" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setObject(1, "Mr'Lee'"); // 设置查询占位符的数据
        ResultSet rs = preparedStatement.executeQuery() ; // 执行数据查询
        while (rs.next()) {
            System.out.printf("【查询结果】uid = %s、name = %s、age = %s、salary = %s、note = %s\n", rs.getObject(1), rs.getObject(2), rs.getObject(3), rs.getObject(4), rs.getObject(5), rs.getObject(6));
        }
        conn.close();
    }
}
class PreQueryDemo1{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "SELECT uid,name,age,birthday,salary,note FROM user WHERE uid=?" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setObject(1, 2); // 设置查询占位符的数据
        ResultSet rs = preparedStatement.executeQuery() ; // 执行数据查询
        while (rs.next()) { // if (rs.next())
            System.out.printf("【查询结果】uid = %s、name = %s、age = %s、salary = %s、note = %s\n", rs.getObject(1), rs.getObject(2), rs.getObject(3), rs.getObject(4), rs.getObject(5), rs.getObject(6));
        }
        conn.close();
    }
}
class PreQueryDemo2{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "SELECT uid,name,age,birthday,salary,note FROM user" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        ResultSet rs = preparedStatement.executeQuery() ; // 执行数据查询
        while (rs.next()) { // if (rs.next())
            System.out.printf("【查询结果】uid = %s、name = %s、age = %s、salary = %s、note = %s\n", rs.getObject(1), rs.getObject(2), rs.getObject(3), rs.getObject(4), rs.getObject(5), rs.getObject(6));
        }
        conn.close();
    }
}
class PreQueryDemo3{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        long currentPage = 1 ; // 当前所在页
        int lineSize = 2 ; // 每页获取的数据行
        String column = "name" ; // 查询列名称,而不是数据
        String keyword = "李" ; // 模糊关键字
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        // 如果是将SQL中要使用的字段定义为变量,不能够通过占位符的形式进行设置
        String sql = "SELECT uid,name,age,birthday,salary,note FROM user WHERE " + column + " LIKE ? LIMIT ?, ?" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setObject(1, "%" + keyword + "%"); // 设置模糊查询关键字
        preparedStatement.setObject(2 , (currentPage - 1) * lineSize); // 开始记录行索引
        preparedStatement.setObject(3, lineSize); // 获取的长度
        ResultSet rs = preparedStatement.executeQuery() ; // 执行数据查询
        while (rs.next()) { // if (rs.next())
            System.out.printf("【查询结果】uid = %s、name = %s、age = %s、salary = %s、note = %s\n", rs.getObject(1), rs.getObject(2), rs.getObject(3), rs.getObject(4), rs.getObject(5), rs.getObject(6));
        }
        conn.close();
    }
}
class PreQueryDemo4{
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码

    public static void main(String[] args) throws Exception{
        String column = "name" ; // 查询列名称,而不是数据
        String keyword = "李" ; // 模糊关键字
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        // 如果是将SQL中要使用的字段定义为变量,不能够通过占位符的形式进行设置
        String sql = "SELECT COUNT(*) FROM user WHERE " + column + " LIKE ?" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql); // 创建PreparedStatement接口实例
        preparedStatement.setObject(1, "%" + keyword + "%"); // 设置模糊查询关键字
        ResultSet rs = preparedStatement.executeQuery() ; // 执行数据查询
        if (rs.next()) {    // 使用COUNT()函数永远都有返回值
            long count = rs.getLong(1) ; // 新一代的开发中对于数据行的记录都使用long
            System.out.println("满足判断条件的数据行:" + count);
        }
        conn.close();
    }
}

数据批处理

不管现在使用的是 Statement 接口还是 PreparedStatement 接口最终执行批处理的时候都会使用“executeBatch()”方法完成,此时批处理操作返回的数据类型是一个整型数组,接收所有更新的返回结果,对于每一条更新的结果在 JDBC 中给出了若干常量:

  • 执行成功:public static int SUCCESS NO INFOI
  • 执行失败:public static intEXECUTE FAILED
详情
public class Demo {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement statement = conn.createStatement() ;
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - A')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - B')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - C')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - D')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - E')"); // 追加批处理
        int result [] = statement.executeBatch() ; // 执行批处理
        System.out.println("【批处理的执行结果】" + Arrays.toString(result));
        conn.close(); // 数据库资源极为宝贵一定要及时关闭
    }
}
现在执行了5次的增加操作,所以5次的增加操作每一次都会影响一行的数据信息,以上全部都属于增加操作所以不会出现多行的更新结果的提示,那么下面对程序做一些修改。
class Demo1 {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement statement = conn.createStatement() ;
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - A')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - B')"); // 追加批处理
        statement.addBatch("UPDATE user SET name='沐言科技'"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - C')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - D')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - E')"); // 追加批处理
        statement.addBatch("DELETE FROM user"); // 追加批处理
        int result [] = statement.executeBatch() ; // 执行批处理
        System.out.println("【批处理的执行结果】" + Arrays.toString(result));
        conn.close();
    }
}

如果现在使用的是 Preparedstatement 实现数据的批处理的操作(非常重要),那么在程序执行的过程之中对于预处理就必须使用相同的 SOL命今,但是不同的语句有不同的数据而已
class Demo2 {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "INSERT INTO user (name) VALUES (?)" ;
        PreparedStatement preparedStatement = conn.prepareStatement(sql) ;
        for (int x = 0 ; x < 10 ; x ++) {
            preparedStatement.setObject(1, "李兴华 - " + x);
            preparedStatement.addBatch(); // 追加批处理
        }
        int result [] = preparedStatement.executeBatch() ; // 执行批处理
        System.out.println("【批处理的执行结果】" + Arrays.toString(result));
        conn.close();
    }
}

事务控制

所有的 SOL,数据库都有一个非常重要的技术亮点:拥有完善的事务,实际上所谓的事务本质上来讲就是若干个数据更新操作要么一起成功,要么一起失败。

事务本身具有:原子性(Atomicity)、一致性( Consistency)、隔离性或独立性(Isolation)、持久性(Durabilily)四个特征,以上的四个特征,也被称为 ACID 特征。.

public class Demo {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        Statement statement = conn.createStatement() ;
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - A')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - B')"); // 追加批处理
        // 假设这5条的数据增加描述的是一个完整的事务,现在有一条语句执行出现了错误
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - 'C')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - D')"); // 追加批处理
        statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - E')"); // 追加批处理
        int result [] = statement.executeBatch() ; // 执行批处理
        System.out.println("【批处理的执行结果】" + Arrays.toString(result));
        conn.close();
    }
}

此时在追加第三条数据的时候就已经产生了错误,所以按照正常的设计结构来说,这个时候的错误应该将所有的更新操作进行全部的回滚处理,而之所以没有回滚是因为默认处理结构中的 JDBC 连接采用自动事务处理模式:自动提交更新。

如果要想进行合理的事务控制,那么就必须将自动提交的操作功能关闭,即“setAutoCommit(false)”,当所有的更新操作全部配置完成之后则可以通过 commit() 方法手工提交,如果提交更新的过程中出现了异常,那么就可以利用 rollback() 回滚当前事务。

class Demo1 {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        conn.setAutoCommit(false); // 取消自动提交
        Statement statement = conn.createStatement() ;
        try {
            statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - A')"); // 追加批处理
            statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - B')"); // 追加批处理
            // 假设这5条的数据增加描述的是一个完整的事务,现在有一条语句执行出现了错误
            statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - 'C')"); // 追加批处理
            statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - D')"); // 追加批处理
            statement.addBatch("INSERT INTO user (name) VALUES ('李兴华 - E')"); // 追加批处理
            int result [] = statement.executeBatch() ; // 执行批处理
            System.out.println("【批处理的执行结果】" + Arrays.toString(result));
            conn.commit(); // 没有异常则进行事务更新提交
        } catch (Exception e) {
            e.printStackTrace(); // 输出异常
            conn.rollback(); // 回滚事务
        }
        conn.close();
    }
}

jdbc 元数据

public class Demo {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        DatabaseMetaData metaData = conn.getMetaData();// 获取元数据
        System.out.println("【数据库主版本号】" + metaData.getDatabaseMajorVersion());
        System.out.println("【数据库子版本号】" + metaData.getDatabaseMinorVersion());
        System.out.println("【数据库产品名称】" + metaData.getDatabaseProductName());
        ResultSet resultSet = metaData.getPrimaryKeys(null, "root", "user");// 获取表信息
        if (resultSet.next()) {
            System.out.println("【catalog】" + resultSet.getObject(1));
            System.out.println("【表名称】" + resultSet.getObject(3));
            System.out.println("【主键字段】" + resultSet.getObject(4));
        }
        conn.close();
    }
}

class Demo1 {
    // 旧的驱动程序:com.mysql.jdbc.Driver,在新版本的JDBC连接里面已经不推荐使用了
    public static final String DRIVER = "com.mysql.cj.jdbc.Driver" ; // 数据库驱动程序
    public static final String URL = "jdbc:mysql://192.168.16.8:3306/yootk" ; // 连接地址
    public static final String USER = "root" ; // 用户名
    public static final String PASSWORD = "root" ; // 密码
    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER) ; // 将数据库的驱动程序加载到容器内部
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) ; // 获取数据库连接
        String sql = "SELECT uid,name,age,birthday,salary,note FROM user WHERE uid=?" ; // 查询SQL
        PreparedStatement preparedStatement = conn.prepareStatement(sql) ;
        preparedStatement.setObject(1, 36); // 设置查询占位
        ResultSet rs = preparedStatement.executeQuery() ; // 查询
        ResultSetMetaData metaData = rs.getMetaData();// 获取查询结果集元数据
        System.out.println("获取返回数据的列数:" + metaData.getColumnCount());
        for (int x = 1 ; x < metaData.getColumnCount() ; x ++) {
            System.out.printf("列名称:%s、列类型:%s、列常量值:%s\n", metaData.getColumnName(x), metaData.getColumnTypeName(x), metaData.getColumnType(x));
        }
        conn.close();
    }
}

案例

数据批量存储

详情
DROP DATABASE yootk ;
CREATE DATABASE yootk CHARACTER SET UTF8 ;
USE yootk ;
CREATE TABLE dept (
    deptno  BIGINT,
    dname   VARCHAR(30) ,
    loc     VARCHAR(30) ,
    CONSTRAINT pk_deptno PRIMARY KEY (deptno)
) engine=INNODB ;
CREATE TABLE emp (
    empno   BIGINT  AUTO_INCREMENT ,
    ename   VARCHAR(30) ,
    salary  FLOAT ,
    deptno  BIGINT ,
    CONSTRAINT pk_empno PRIMARY KEY (empno),
    CONSTRAINT fk_deptno FOREIGN KEY(deptno) REFERENCES dept(deptno) ON DELETE SET NULL
) engine=INNODB ;

代码地址open in new window

动态 DDL 操作(CRUD)

详情
DROP DATABASE yootk ;
CREATE DATABASE yootk CHARACTER SET UTF8 ;
USE yootk ;
CREATE TABLE user (
    uid     VARCHAR(50) ,
    name    VARCHAR(30) ,
    note    TEXT,
    CONSTRAINT pk_uid PRIMARY KEY (uid)
) engine=INNODB ;

代码地址open in new window

上次编辑于: