目录
引入:USB技术介绍
USB,是英文Universal Serial Bus(通用串行总线)的缩写,是一个外部总线标准,用于规范与外部设备的连接和通讯
USB是一个技术统称,由三部分组成
第一部分:USB的规范和设计标准(概念)
第二部分:电脑端的USB接口(接口)
第三部分:外设的USB接口和具体发送信号的驱动程序(实现类)
正题
JDBC:Java Database Connectivity(Java连接数据库技术)
通俗点说,在Java代码中,使用JDBC提供的方法,可以发送字符串类型的SQL语句到数据库管理软件(MySQL、Oracle等),并且获取语句执行结果,进而实现数据库数据CURD的技术
JDBC概述来说就是Java程序与数据库软件之间连接的桥梁
JDBC规范和接口 | JDBC | 第三方数据库厂商 |
Java语言只提供规范(接口),规定数据库操作方法;标准的类库存在于java.sql,javax.sql包下 | java连接数据库技术统称 | 各数据库厂商,根据Java的JDBC规范(接口),完成具体的实现驱动代码(jar),实现代码可以不同,但是方法都相同 |
总结:
1.JDBC由两部分组成:
一是Java提供的JDBC规范(接口)
二是各个数据库厂商的实现驱动jar包(jar包是java程序打成的一种压缩包格式,你可以将这些jar包引入你的项目中,然后你可以使用这个java程序中类和方法以及属性了)
2.JDBC技术是一种典型的面向接口编程
优势:
我们只要学习JDBC接口规定方法,即可操作所有数据库软件
项目中期需要切换数据库,我们只需要更新第三方驱动jar包,不需要更改代码
具体核心类和接口
DriverManager
1.将第三方数据库厂商的实现驱动jar注册到程序中
2.可以根据数据库连接信息获取connection
Connection
1.和数据库建立的连接,在连接对象上,可以多次执行数据库curd操作
2.可以获取statement(静态SQL路线,没有动态值语句)和preparedStatement(预编译SQL路线,有动态值语句)、callablestatement(执行标准存储过的SQL语句)对象
Statement、PreparedStatement、CallableStatement
1.具体发送SQL语句到数据库管理软件的对象
2.不同发送方式稍有不同
Result
1.面向对象思维的产物(抽象成数据库的查询结果表)
2.存储DQL查询数据库结果的对象
3.需要我们进行解析,获取具体的数据库数据
1.驱动jar版本选择
2.java工程导入依赖
a.项目创建lib文件夹
b.导入驱动依赖jar包
c.jar包右键-添加为项目依赖
1.注册驱动-将依赖的jar包,进行安装
2.获取连接-Connection
3.创建发送SQL语句对象-statement
4.发送SQL语句,并获取返回结果-ResultSet结果对象
5.结果集解析
6.资源关闭-释放(由内向外关)
1.准备数据库数据
2.查询目标
3.基于statement实现查询
- package com.jiayifeng.api.statement;
-
- import com.mysql.cj.jdbc.Driver;
-
- import java.sql.*;
-
- /**
- * author 爱编程的小贾
- * create 2023-10-15 14:20
- */
- public class StatementQueryPart {
- public static void main(String[] args) throws SQLException {
- // 1.注册驱动
- /*
- 注册驱动
- 依赖:
- 驱动版本8+ com.mysql.cj.jdbc.Driver
- 驱动版本5+ com.mysql.jdbc.Driver
- */
- DriverManager.registerDriver(new Driver());//8.0+(8.0.27)
-
- // 2.获取连接
- /*
- Java程序要和数据库创建连接
- Java程序,连接数据库,肯定是调用某个方法,方法也需要填入连接数据库的基本信息:
- 数据库ip地址:127.0.0.1
- 数据库端口号:3306
- 账号:root
- 密码:passwd
- 连接数据库的名称:MySQLName
- */
-
- /*
- 参数1:url
- jdbc:数据库厂商名://ip地址:port/数据库名
- 参数2:username 数据库软件的账号
- password 数据库软件的密码
- */
- // java.sql 接口 = 实现类
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/studentdb", "root", "ASUS010519");
-
- // 3.创建statement
- Statement statement = connection.createStatement();
-
- // 4.发送SQL语句,并且获取返回结果
- String sql = "select * from student;";
- ResultSet resultSet = statement.executeQuery(sql);
-
- // 5.进行结果集解析
- // 看有没有下一行数据,有,你就可以获取
- while(resultSet.next()){
- String sno = resultSet.getString("sno");
- String sname = resultSet.getString("sname");
- String ssex = resultSet.getString("ssex");
- String sage = resultSet.getString("sage");
- String sdept = resultSet.getString("sdept");
- int sclass = resultSet.getInt("sclass");
- System.out.println(sno + sname + ssex + sage + sdept + sclass);
- }
-
- // 6.关闭资源
- resultSet.close();
- statement.close();
- connection.close();
- }
- }
存在问题:
①SQL语句需要字符串拼接,比较麻烦
② 只能拼接字符串类型,其他的数据库类型无法处理
③可能发生注入攻击
动态值充当了SQL语句结构,影响了原有的查询结果
- package com.jiayifeng.api.statement;
-
- import com.mysql.cj.jdbc.Driver;
-
- import java.sql.*;
- import java.util.Properties;
- import java.util.Scanner;
-
- /**
- * author 爱编程的小贾
- * create 2023-10-15 15:03
- *
- * 一:模拟用户登录
- * 1.明确jdbc的使用教程和详细讲解内部设计API方法
- * 2.发现问题,引出preparedStatement
- *
- * TODO:
- * 1.输入账号和密码
- * 2.进行数据库信息查询(t_user)
- * 3.反馈登陆成功还是登录失败
- *
- * TODO:
- * 1.键盘输入事件,收集账号和密码信息
- * 2.注册驱动
- * 3.获取连接
- * 4.创建statement
- * 5.发送查询SQL语句,并获取返回结果
- * 6.结果判断,显示登录成功还是失败
- * 7.关闭资源
- */
- public class StatementUserLoginPart {
- public static void main(String[] args) throws Exception {
- // 1.获取用户输入信息
- Scanner scanner = new Scanner(System.in);
- System.out.println("请输入账号:");
- String account = scanner.nextLine();
- System.out.println("请输入密码:");
- String password = scanner.nextLine();
-
- // 2.注册驱动
- /*
- 方案一:
- DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
- 问题:会注册两次驱动
- 1.DriverManager.registerDriver() 方法本身会注册一次
- 2.Driver.static{ DriverManager.registerDriver()} 静态代码块,也会注册一次!
- 解决:只想注册一次驱动
- 只触发静态代码块即可 Driver
- 触发静态代码块:
- 类加载机制:类加载的时刻,会触发静态代码块!
- 加载 [class 文件 -> jvm虚拟机的class对象]
- 连接 [验证(检查文件类型) -> 准备(静态变量默认值) -> 解析(触发静态代码块)]
- 初始化(给静态属性赋真实值)
- 如何触发类加载:
- 1.new 关键字
- 2.调用静态方法
- 3.调用静态属性
- 4.接口1.8 default默认实现
- 5.反射
- 6.子类触发父类
- 7.程序的入口main
- */
-
- // 方案一:
- // DriverManager.registerDriver(new Driver());
-
- // 方案二:mysql新版本的驱动 | 换成oracle
- // new Driver();
-
- // 字符串 -> 提取到外部的配置文件 -> 可以在不改变代码的情况下,完成数据库驱动的切换
- Class.forName("com.mysql.cj.jdbc.Driver");//触发类加载,触发静态代码块的调用
-
- // DriverManager.registerDriver(new Driver());//8.0+(8.0.27)
- // 3.获取数据库连接
- /*
- 核心属性:
- 1.数据库软件所在的主机的IP地址:localhost | 127.0.0.1
- 2.数据库软件的主机的端口号:3306
- 3.连接的具体库:studentdb
- 4.连接的账号:root
- 5.连接的密码:passwd
- 6.可选的信息:没有
- 三个参数:
- String url 数据库软件所在地址的信息,连接的具体库,以及其它可选信息
- 语法:jdbc:数据库管理软件名称[mysql,oracle]://ip地址|port端口号/数据库名?key=value&key=value
- String user 数据库的账号
- String passwd 数据库的密码
- 两个参数:
- String url:同上
- Properties info:存储账号和密码
- Properties类似于Map,只不过key = value都是字符串形式!
- 一个参数:
- String url
- */
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/studentdb","root","ASUS010519");
-
- Properties info = new Properties();
- info.put("user","root");
- info.put("passwd","ASUS010519");
- Connection connection1 = DriverManager
- .getConnection("jdbc:mysql://localhost:3306/studentdb", info);
-
- Connection connection2 = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/studentdb?user=root&passwd=ASUS010519");
-
- // 4.创建发送SQL语句的statement对象
- // statement可以发送SQL语句到数据库,并且获取返回结果
- Statement statement = connection.createStatement();
-
- // 5.发送SQL语句(1.编写SQL语句 2.发送SQL语句)
- String sql1 = "select * from student where account = '" + account + "' and password = '" + password + "';";
- // String sql1 = "select * from student;";
- /*
- SQL分类:
- DDL(容器创建、修改、删除)
- DML(插入、删除、修改)
- DQL(查询)
- DCL(权限控制)
- TPL(事务控制语言)
- 参数:sql 非DQL
- 返回:int
- 情况一:DML 返回影响的行数,例如:删除了三条数据 return 3;
- 情况二:非DML return 0;
- int row = executeUpdate(sql);
- 参数:sql DQL
- 返回:resultSet 结果封装对象
- ResultSet resultSet = executeQuery(sql);
- */
- // int i = Statement.executeUpdate(sql);
- ResultSet resultSet = statement.executeQuery(sql1);
-
- // 6.查询结果集解析
- /*
- java是一种面向对象的思维,将查询结果封装成了resultSet对象,我们应该理解,内部一定也是有行和列的!
- resultSet -> 逐行获取数据,行 —> 行的列的数据
- 想要进行数据解析,我们需要进行两件事情:
- 1.移动游标指定获取数据行
- 2.获取指定数据行的列数据即可
- 1.游标移动问题:
- resultSet内部包含一个游标,指定当前行数据
- 默认游标指定的是第一行数据之前
- 我们可以调用next()方法向后移动一行游标
- 如果我们有很多行数据,我们可以使用while(next()){获取每一行数据}
- boolean = next() true:有更多行数据,并且向下移动一行
- false:没有更多行数据
- 2.获取列的数据问题(获取光标指定的行中的列的数据)
- resultSet.get类型(String columnLable | int columnIndex);
- columnLable:列名 如果有别名 写别名
- columnIndex:列的下角标获取 从左向右 从1开始
- */
-
- while(resultSet.next()){
- String sno = resultSet.getString("sno");
- String sname = resultSet.getString("sname");
- String ssex = resultSet.getString("ssex");
- String sage = resultSet.getString("sage");
- String sdept = resultSet.getString("sdept");
- int sclass = resultSet.getInt("sclass");
- System.out.println(sno + sname + ssex + sage + sdept + sclass);
- }
-
- // 移动一次光标,只要有数据,就代表登录成功
- if (resultSet.next()) {
- System.out.println("登录成功!");
- }else{
- System.out.println("登录失败!");
- }
-
- // 7.关闭资源
- resultSet.close();
- statement.close();
- connection.close();
- }
- }
- package com.jiayifeng.preparedStatement;
-
- import java.sql.*;
- import java.util.Scanner;
-
- /**
- * author 爱编程的小贾
- * create 2023-10-24 16:20
- */
- public class PSUerLoginPart {
- public static void main(String[] args) throws ClassNotFoundException, SQLException {
- // 1.获取用户输入信息
- Scanner scanner = new Scanner(System.in);
- System.out.println("请输入账号:");
- String account = scanner.nextLine();
- System.out.println("请输入密码:");
- String password = scanner.nextLine();
-
- // 2.ps的数据库流程
- // 2.1:注册驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- // 2.2:获取连接
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/studentdb?user=root&password=ASUS010519\");");
-
- /*
- statement
- 1.创建statement
- 2.拼接SQL语句
- 3.发送SQL语句,并且获取返回结果
- preparedStatement
- 1.编写SQL语句结果,不包含动态值部分的语句,动态值部分使用占位符 ? 替代
- 注意:? 只能替代动态值
- 2.创建preparedStatement,并且传入动态值
- 3.动态值 占位符 赋值 ? 单独赋值即可
- 4.发送SQL语句即可,并获取返回结果
- */
- // 2.3:编写SQL语句结果
- String sql = "select * from student where accouont = ? and password = ?";
-
- // 2.4:创建预编译statement并且设置SQL语句结果
- PreparedStatement preparedStatement = connection.prepareStatement(sql);
-
- // 2.5:单独的占位符进行赋值
- /*
- 参数1:index 占位符的位置 从左向右数 从1开始 账号 ? 1
- 参数2:object 占位符的值 可以设置任何类型的数据,避免了我们拼接和使类型更加丰富
- */
- preparedStatement.setObject(1,account);
- preparedStatement.setObject(2,password);
-
- // 2.6:发送SQL语句,并获取返回结果
- // statement.executeUpdate | executeQuery(String sql);
- // preparedStatement.executeUpdate | executeQuery(); TODO:因为它已经知道语句并且知道语句动态值
- ResultSet resultSet = preparedStatement.executeQuery();
-
- // 2.7:结果集解析
- if(resultSet.next()){
- System.out.println("登录成功");
- }else{
- System.out.println("登录失败");
- }
-
- // 2.8:关闭资源
- resultSet.close();
- preparedStatement.close();
- connection.close();
- }
- }
-
-
- package com.jiayifeng.preparedStatement;
-
- import org.junit.Test;
-
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.SQLException;
-
- /**
- * author 爱编程的小贾
- * create 2023-10-24 16:49
- *
- * 一:使用preparedStatement进行student表的增删改查(curd操作)
- */
- public class PSCURDPart {
- @Test
- public void testInsert() throws ClassNotFoundException, SQLException {
- /*
- student表中插入一条数据
- */
- Class.forName("com.mysql.cj.jdbc.Driver");
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/jiayifeng", "root", "ASUS010519");
-
- String sql = "insert into t_user(account,password,nickname) values(?,?,?);";
- PreparedStatement preparedStatement = connection.prepareStatement(sql);
- preparedStatement.setObject(1,"test");
- preparedStatement.setObject(2,"test");
- preparedStatement.setObject(3,"二狗子");
-
- int rows = preparedStatement.executeUpdate();
- if(rows > 0){
- System.out.println("数据插入成功");
- }else {
- System.out.println("数据插入失败");
- }
- preparedStatement.close();
- connection.close();
- }
-
- @Test
- public void testUpdate() throws ClassNotFoundException, SQLException {
- Class.forName("com.mysql.cj.jdbc.Driver");
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/jiayifeng", "root", "ASUS010519");
-
- String sql = "update t_user set nickname=? where id=?;";
- PreparedStatement preparedStatement = connection.prepareStatement(sql);
- preparedStatement.setObject(1,"三狗子");
- preparedStatement.setObject(2,"3");
-
- int rows = preparedStatement.executeUpdate();
- if(rows > 0){
- System.out.println("数据更新成功");
- }else {
- System.out.println("数据更新失败");
- }
- preparedStatement.close();
- connection.close();
- }
-
- @Test
- public void testDelete() throws ClassNotFoundException, SQLException {
- Class.forName("com.mysql.cj.jdbc.Driver");
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/jiayifeng", "root", "ASUS010519");
-
- String sql = "delete from t_user where id = ?;";
- PreparedStatement preparedStatement = connection.prepareStatement(sql);
- preparedStatement.setObject(1,"3");
-
- int rows = preparedStatement.executeUpdate();
- if(rows > 0){
- System.out.println("数据删除成功");
- }else {
- System.out.println("数据删除失败");
- }
- preparedStatement.close();
- connection.close();
- }
- }
①注册驱动
②获取连接
③编写SQL语句
④创建preparedStatement并且传入SQL语句结构
⑤占位符赋值
⑥发送SQL语句,并且获取结果
⑦结果集解析
⑧关闭资源
功能需求:
1.Java程序获取插入数据时,MySQL维护自增长维护的主键id值,这就是自增长
2.作用:在多表关联插入数据时,一般主表的主键都是自动生成的。所以在插入数据之前无法知道这条数据的主键,但是从表需要在插入数据之前就绑定主表的主键,这时可以使用主键回显技术
- package com.jiayifeng.preparedStatement;
-
- import org.junit.Test;
-
- import java.sql.*;
-
- /**
- * author 爱编程的小贾
- * create 2023-10-24 17:59
- *
- * TODO:
- * t_user插入一条数据!并且获取数据库自增长的主键
- *
- * TODO:
- * 总结:
- * ①创建prepareStatement的时候,告知,携带回数据库自增长的主键
- * ②获取司机装主键值的结果集对象,一行一列,获取对应的数据库即可
- *
- */
- public class PSOtherPart {
- @Test
- public void returnPrimaryKey() throws Exception {
- Class.forName("com.mysql.cj.jdbc.Driver");
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/jiayifeng", "root", "ASUS010519");
-
- String sql = "insert into t_user(account,password,nickname) values(?,?,?);";
- PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
- preparedStatement.setObject(1,"test");
- preparedStatement.setObject(2,"123456");
- preparedStatement.setObject(3,"狗蛋");
-
- int i = preparedStatement.executeUpdate();
- if(i > 0){
- System.out.println("数据插入成功");
-
- // 可以获取回显的主键
- // 获取司机装主键的结果集对象,一行 一列 id=值
- ResultSet resultSet = preparedStatement.getGeneratedKeys();
- resultSet.next();//移动下光标
- int id = resultSet.getInt(1);
- System.out.println("id = " + id);
- }else {
- System.out.println("数据插入失败");
- }
- preparedStatement.close();
- connection.close();
- }
-
- // 使用批量插入的方式插入10000条数据
- /*
- TODO:总结批量插入
- 1.路径后面添加?rewriteBatchedStatements=true 允许批量插入
- 2.insert into values [必须写] 语句不能添加;结束
- 3.不是执行语句每条,是批量添加addBatch();
- 4.遍历添加完毕以后,统一批量执行 executeBatch()
- */
- @Test
- public void testBatchInsert() throws ClassNotFoundException, SQLException {
- Class.forName("com.mysql.cj.jdbc.Driver");
- Connection connection = DriverManager.
- getConnection("jdbc:mysql://localhost:3306/jiayifeng?rewriteBatchedStatements=true", "root", "ASUS010519");
-
- String sql = "insert into t_user(account,password,nickname) values(?,?,?);";
- PreparedStatement preparedStatement = connection.prepareStatement(sql);
-
- long start = System.currentTimeMillis();
- for(int i = 0;i < 10000;i++){
- preparedStatement.setObject(1,"dd"+i);
- preparedStatement.setObject(2,"dd"+i);
- preparedStatement.setObject(3,"驴蛋蛋"+i);
- preparedStatement.addBatch();//不执行,追加到values后面
- }
-
- preparedStatement.executeBatch();//执行批量操作
-
- long end = System.currentTimeMillis();
-
- System.out.println("执行10000次数据插入消耗的时间:" + (end - start));
- preparedStatement.close();
- connection.close();
- }
- }
错误一:java.lang.ClassNotFoundException:com.mysql.cj.jdbc.Driver
原因:JDBC的依赖(jar包)没有导入
错误二:java.sql.SQLException:Access denied for user 'root'@'localhost'(using password:YES)
原因:连接数据库密码错误
错误三:java.sql.SQLSyntaxErrorException:Unknown database 'databasename'
原因:连接数据库找不到
错误四:java.sql.SQLSyntaxErrorException:Table 'studentdb.users' doesn't exist
原因:数据库中找不到指定的表
①com.mysql.cj.jdbc.Driver 这个类中只有静态代码块 注册了当前驱动
②为何注释了当前驱动代码仍然可以正常运行?
java6以后不需要显式的书写加载驱动内容
③MySQL5和MySQL8驱动连接数据库的区别?
mysql5的驱动:com.mysql.jdbc.Driver
mysql5的URL:jdbc:mysql://127.0.0.1:3306/databasename
④如果我们想要更换数据库,比如说更换Oracle/sql server
只需要更改:
A、驱动
B、类加载、url、用户名、密码即可