JDBC的“那些事“之应当注意的问题(中)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JDBC的“那些事“之应当注意的问题(中)

3.2 问题演示

👉问题描述:

当我们尝试给上述刚建好的数据表t_user中的blob类型的字段photo存储图片时,可能发生以下问题:

  • A.blob类型的字段装不下很大的图片(比如6MB的图片)
  • B.数据表的字段的数据类型可以容纳JDBC传送的图片,但是传送图片的数据产生了异常,例如(com.mysql.cj.jdbc.exceptions.PacketTooBigException)

💡小tips:

在Mysql里,BLOB类型可以存储0-64K(小图片)的二进制字符串数据

MEDIUMBLOB类型可以存0-16MB的二进制形式的长文本数据(大图片)LONGBLOB类型可以存储0-4GB的二进制形式的极大文本数据(大图片)

案例:演示A问题

代码演示如下:

👉①测试64kb以下的图片:

@Test
    public void test01() throws SQLException, FileNotFoundException, UnsupportedEncodingException {
        Scanner input=new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username=input.next();
        System.out.print("请输入密码:");
        String password=input.next();
        System.out.print("请输入图片路径:");
        String path=input.next();
        //连接数据库
        String url="jdbc:mysql://localhost:3306/0225db?serverTimezone=UTC";
        Connection root = DriverManager.getConnection(url, "root", "123456");
        String sql="INSERT INTO t_user VALUES(?,md5(?),?)";
        //测试图片路径:C:\Users\king\Desktop\桌面清理\starsky.png
        PreparedStatement pst = root.prepareStatement(sql);
        pst.setObject(1,username);
        pst.setObject(2,password);
        pst.setObject(3,new FileInputStream(path));//文件字节IO流包含文件,它自动把文件写进去了
        int len = pst.executeUpdate();
        System.out.println(len>0?"更新成功":"更新失败");
        pst.close();
        root.close();
    }

❓这里存在一个问题?

在sqlyog中对应的blob类型的字段接收来自JDBC传送的图片字节数据后,显示RIFF�,我的MySQL数据库的默认字符集已经是utf8mb4,我的sql yog上的字段确实是blob类型的,就是无法显示图片,只有图片的字节数据

💡tips:

为了时间效率,这个问题我先搁置一旁,如果有知道的大佬,欢迎评论区指正

👉② 测试6MB的图片:

代码演示:还是在刚才的代码上运行

👉 解决措施:将数据表photo字段的数据类型修改为"MEDIUMBLOB"类型,它可以容纳16MB及以下的图片字节数据。

  • ⭐sql yog改变字段数据类型的步骤如下:

  • ⭐ sql语句修改: ALTER TABLE t_user MODIFY photo MEDIUMBLOB;

代码演示:再次运行代码成功

案例:演示B问题

👉测试图片:

代码演示如下:

还是刚才上面的案例代码

/*
com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (6,671,689 > 4,194,304).
You can change this value on the server by setting the 'max_allowed_packet' variable.
*/

👉原因分析:

MySQL 8.0的默认max_allowed_packet参数值为4MB。

这个参数控制着MySQL服务器能够接收和发送的最大数据包大小。

👉解决措施:

  1. 管理员身份运行cmd命令,执行net stop 你自己的mysql的服务名称 命令,以停止MySQL服务,不然改了参数也没用。
net  stop  mysql80  #(mysql80是我自己起的服务名称)

2. 找到你的MySQL服务端的配置文件my.ini,修改max_allowed_packet的参数为16MB,保存更改,然后执行"net start 你自己的MySQL服务名称"命令重启mysql的服务,

再执行代码演示如下:


四、获取自增长键值

4.1 准备测试数据

👉创建数据表t_employee

CREATE TABLE `t_employee` (
  `eid` int NOT NULL AUTO_INCREMENT COMMENT '员工编号',
  `ename` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '员工姓名',
  `salary` double NOT NULL COMMENT '薪资',
  `commission_pct` decimal(3,2) DEFAULT NULL COMMENT '奖金比例',
  `birthday` date NOT NULL COMMENT '出生日期',
  `gender` enum('男','女') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '男' COMMENT '性别',
  `tel` char(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '手机号码',
  `email` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邮箱',
  `address` varchar(150) DEFAULT NULL COMMENT '地址',
  `work_place` set('北京','深圳','上海','武汉') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '北京' COMMENT '工作地点',
  `hiredate` date NOT NULL COMMENT '入职日期',
  `job_id` int DEFAULT NULL COMMENT '职位编号',
  `mid` int DEFAULT NULL COMMENT '领导编号',
  `did` int DEFAULT NULL COMMENT '部门编号',
  PRIMARY KEY (`eid`),
  KEY `job_id` (`job_id`),
  KEY `did` (`did`),
  KEY `mid` (`mid`),
  CONSTRAINT `t_employee_ibfk_1` FOREIGN KEY (`job_id`) REFERENCES `t_job` (`jid`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `t_employee_ibfk_2` FOREIGN KEY (`did`) REFERENCES `t_department` (`did`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `t_employee_ibfk_3` FOREIGN KEY (`mid`) REFERENCES `t_employee` (`eid`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `t_employee_chk_1` CHECK ((`salary` > 0)),
  CONSTRAINT `t_employee_chk_2` CHECK ((`hiredate` > `birthday`))
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

4.2 问题演示

👉问题描述:

希望自增长的字段在添加完成后,可以及时的反馈给Java程序端。

👉解决方案:

(1)

Preparedstatement pst =   conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS):

ps:这里的statement是一个接口,它是Preparedstatement的父接口。

为何不用statement?因为它不支持占位符 ”?“的写法

Statement接口中有一个常量值

RETURN GENERATED KEYS,表示执行sql的同时,返回自增长的键值

(2)

ResultSet rs = pst.getGeneratedKeys();//返回的是一个结果集

👉注意:要想拿到ResultSet rs的内容,必须要先遍历判断一下,因为它的游标在刚开始时指向的是表头,而不是指向第一个自增列

案例:尝试给t_employee添加一条记录,并返回它的员工编号(自增长列

代码演示如下:

import org.junit.Test;
import java.sql.*;
import java.util.Date;
import java.util.Scanner;
public class TestSqlAuto {
    @Test
    public void test01() throws SQLException {
        Scanner input=new Scanner(System.in);
        System.out.print("请输入姓名:");
        String ename=input.next();
        System.out.print("请输入薪资:");
        String salary=input.next();
        System.out.print("请输入出生日期:");
        String birthday=input.next();
        System.out.print("请输入性别:");
        String gender=input.next();
        System.out.print("请输入电话:");
        String tel=input.next();
        System.out.print("请输入邮箱:");
        String email=input.next();
        //连接数据库,类似于网络编程中的socket
        String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
        Connection root = DriverManager.getConnection(url, "root", "123456");
        //多加一步,把?用具体的变量、表达式等值代替
        String sql="insert into t_employee(ename,salary,birthday,gender,tel,email,hiredate) values(?,?,?,?,?,?,?)";
        //此时对sql进行预编译,里面是带?的
        PreparedStatement pst = root.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//Statement.RETURN_GENERATED_KEYS表示,执行sql后,返回自增长键值
        pst.setObject(1,ename);//这里的1代替第一个?,用ename变量的值代替第一个?的位置,下面的依次类推
        pst.setObject(2,salary);
        pst.setObject(3,birthday);
        pst.setObject(4,gender);
        pst.setObject(5,tel);
        pst.setObject(6,email);
        pst.setObject(7,new Date());
        int len = pst.executeUpdate();//执行sql语句
        System.out.println(len>0?"添加成功":"添加失败");
        //执行完毕后,通过 PreparedStatement对象pst获取它的自增长键值对
        ResultSet generatedKeys = pst.getGeneratedKeys();//返回的是一个结果集
        while (generatedKeys.next()){//它必须要先遍历一下,让游标指向首行记录
            System.out.println("你的员工编号:"+generatedKeys.getObject(1));//此处只有一个自增长的键值
        }
        //释放资源
        input.close();
        pst.close();
        root.close();
    }
}

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
SQL Java 关系型数据库
|
2月前
|
SQL 数据库
jdbc10
jdbc10
21 1
|
6月前
|
Java 关系型数据库 MySQL
JDBC是真的啰里啰嗦啊-但是很重要!(上)
JDBC是真的啰里啰嗦啊-但是很重要!
40 1
|
6月前
|
SQL Java 数据库连接
JDBC是真的啰里啰嗦啊-但是很重要!(下)
JDBC是真的啰里啰嗦啊-但是很重要!
28 1
|
XML 存储 Java
什么是jdbc?为什么要用jdbc
什么是jdbc?为什么要用jdbc
|
6月前
|
存储 Java 数据库连接
JDBC简单总结
JDBC简单总结
|
SQL Oracle 数据可视化
|
缓存 druid Java
JDBC2.0
JDBC2.0在1.0版本java.sql.*上增加了一个扩展包javax.sql.*包,这个包里面包含两个接口: 1.DataSource,数据源。 2.ConnectionPoolDataSource,数据池。 DataSource的源码可以看到,这个接口的作用就是拿来获取connection连接的。 各个数据库厂商只负责实现connection, 至于获取connection,在JDBC1.0里面是由DriverManager来负责的。 JDBC2.0版本之所新增DataSource,原因很简单——数据库连接池。1.0版本时每用一次connection都需要重新new,而da
130 0
JDBC2.0
|
Java 关系型数据库 MySQL
JDBC1.0
JDBC是JAVA十三大规范之一,由JAVA定义顶级接口API,各个数据库厂商去实现。常用的四大接口——Driver,DriverManager,Connection,Statement。 这里先给出结论: 所谓的JAVA制定标准,就是指JAVA给出接口,厂家各自去实现。 比如Driver,Connection,Statement等都是有接口,有实现。 通过向DriverManager注册不同Driver来确定Connection,Statement的类型
65 0
|
SQL Java 关系型数据库
JDBC介绍
JDBC介绍
113 0