Java 使用 JDBC 连接mysql

news2024/9/22 9:28:41

之前我们学习了JavaSE,编写了Java程序,数据保存在变量、数组、集合等中,无法持久化,后来学习了IO流可以将数据写入文件,但不方便管理数据以及维护数据的关系;

后来我们学习了数据库管理软件MySQL,可以方便的管理数据。

那么如何将它俩结合起来呢?即Java程序<==>MySQL,实现数据的存储和处理。

那么就可以使用JDBC技术。

JDBC:Java Database Connectivity,它是代表一组独立于任何数据库管理系统(DBMS)的API,声明在java.sql与javax.sql包中,是SUN(现在Oracle)提供的一组接口规范。由各个数据库厂商来提供实现类,这些实现类的集合构成了数据库驱动jar。

即JDBC技术包含两个部分:

  1. java.sql包和javax.sql包中的API

    因为为了项目代码的可移植性,可维护性,SUN公司从最初就制定了Java程序连接各种数据库的统一接口规范。这样的话,不管是连接哪一种DBMS软件,Java代码可以保持一致性。

  2. 各个数据库厂商提供的jar

    因为各个数据库厂商的DBMS软件各有不同,那么内部如何通过sql实现增、删、改、查等管理数据,只有这个数据库厂商自己更清楚,因此把接口规范的实现交给各个数据库厂商自己实现。

导入MySQL驱动

在使用代码连接MySQL数据库时,需要先导入MySQL为Java语言编写的驱动。

  • MySQL驱动下载地址:MySQL :: Download MySQL Connector/J (Archived Versions)

    驱动版本与MySQL服务器以及JRE,JDK的对应关系。

    Connector/J versionMySQL Server versionJRE RequiredJDK Required for CompilationStatus
    5.15.61, 5.71, 8.01JRE 5 or higher1JDK 5.0 AND JDK 8.0 or higher2, 3General availability
    8.05.6, 5.7, 8.0JRE 8 or higherJDK 8.0 or higher2General availability. Recommended version.
  • 下载对应版本的Connector并解压,得到mysql-connector-java-8.0.33-bin.jar包。

  • 在项目中新建一个libs的文件夹,将解压后的jar包复制到这个文件夹中。

  • 打开IDEA,右键jar包,选择add as library,将jar包添加到library

代码实现

代码实现步骤:

1. 注册驱动

在将.jar文件标记为Library以后,需要先使用代码注册驱动。

Class.forName("com.mysql.jdbc.Driver"); // 加载 com.mysql.jdbc.Driver 这个类

Java6,也就是JDBC4.0以后,JavaSE的项目可以自动加载驱动。是因为数据库的厂商提供了MEAT-INFO-->services-->java.sql.Driver这个文件,在使用DriverManager类的getConnection方法获取数据库连接时,DriverManager将会尝试从初始化中加载的驱动程序中找到合适的驱动程序。

建议在使用前还是手动的注册一下MySQL的驱动。

2. 获取数据库连接

使用Java自带DriverManager类的getConnection(String url)或者getConncetion(String url,String user,String password)方法,可以获取到一个数据库连接,用来操作数据库。

参数解析:

  • url:数据库连接路径,DriverManager尝试从一组已经注册的JDBC驱动程序中选择适当的驱动程序。

    • 格式为: jdbc:subprotocol:subname
    • 常见数据库的url连接:
      • mysql: jdbc:mysql://<hostname>[:<port>]/<dbname>[?连接参数]
      • oracle: jdbc:oracle:thin:@<hostname>[:<port>]:<dbname>
      • sqlserver:jdbc:sqlserver://<hostname>[:<port>]:DatabaseName=<dbname>
  • user: 连接MySQL数据库时使用的用户名。

  • password:连接MySQL数据库时使用的密码。
DriverManager.getConnection("jdbc:mysql://localhost:3306/demo","root","Abcd1234");

// 调用 getConnection(String url) 方法,将用户名和密码以参数的形式传入
DriverManager.getConnection("jdbc:mysql://localhost/demo?user=root&password=Abcd1234");

3. 执行SQL语句

获取到connection的数据库连接以后,如果想要执行SQL语句,需要调用connection的的createStatement() 方法,创建一个Statement对象,用来和服务器传递SQL语句。

Statement对象执行SQL语句也分为两种情况:

  • 增删改数据使用executeUpdate(String sql)方法,得到的结果是一个int类型的数字,表示SQL语句影响的行数。
  • 查询数据使用executeQuery(String sql)方法,得到的结果是一个ResultSet类型的对象,配合next()getXXX()方法获取到每个字段的值。

4. 关闭连接

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

public class Main {
    public static void main(String[] args) {

        try {
            // 加载 MySQL 驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 连接到 MySQL 数据库
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "12345678");
            DatabaseMetaData metaData = connection.getMetaData();

            // 在这里执行其他数据库操作
            System.out.println("数据库名称:" + metaData.getDatabaseProductName());
            System.out.println("数据库版本:" + metaData.getDatabaseProductVersion());
            System.out.println("驱动名称:" + metaData.getDriverName());
            System.out.println("驱动版本:" + metaData.getDriverVersion());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PreparedStatement的使用

调用Connection类的prepareStatement()方法可以获取到一个PrepareStatement类的对象。PerparedStatement对象继承自Statement类,也可以调用executeUpdateexecuteQuery方法来执行SQL语句。

Statement类相比,PreparedStatement能够实现以下几个需求:

1. 避免SQL注入

SQL注入是指对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

假设user表中存储了一个name值为zhangsan,密码为123的数据。

直接使用 Statement类的executeQuery()方法,会有SQL注入的风险。

Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");  // 如果用户输入的是 zhangsan'#
String name = scanner.next();
System.out.print("请输入密码:");  // 这里无论输入的密码是否正确,都能获取到用户张三的信息
String pwd = scanner.next();

// 这里使用的是字符串拼接的形式得到一个 SQL 语句,有sql注入的风险
String sql = "select * from user where name='" + name + "' and password='" + pwd + "';";
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);

boolean isPass = false;
while (rs.next()) {
    isPass = true;
    System.out.println("用户名密码正确!");
    System.out.println("id:" + rs.getInt(1) + ",姓名:" + rs.getString(2) + ",密码" + rs.getString(3));
}
if (!isPass) {
    System.out.println("用户名或者密码错误!");
}

rs.close();
statement.close();
connection.close();

使用PreparedStatement类可以避免SQL注入。

Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");
String name = scanner.next();
System.out.print("请输入密码:");
String pwd = scanner.next();

// 不再使用字符串的 + 拼接 SQL 字符串,而是使用 ? 进行占位
String sql = "select * from user where name=? and password=?;";

PreparedStatement pst = connection.prepareStatement(sql);
// 调用 PreparedStatement 对象 setXXX() 方法,给指定的 ? 传参,可以避免SQL注入
pst.setString(1, name);
pst.setString(2, pwd);

// 调用 executeQuery() 方法时,不要再传入 SQL 语句
ResultSet rs = pst.executeQuery();

2. 存储Blob类型

String sql = "insert into person values(null,?,?)";
PreparedStatement pst = connection.prepareStatement(sql);
FileInputStream fis = new FileInputStream("1.jpeg");
pst.setString(1, "张三");
pst.setObject(2, fis);  // 可以将一个文件写入到数据库中

注意两个问题:

  1. my.ini关于上传的字节流文件有大小限制,可以在my.ini中配置变量

​ max_allowed_packet=16M

  1. 每一种blob有各自大小限制:tinyblob:255字节、blob:65k、mediumblob:16M、longblob:4G

3. 插入数据后获取自增键的值

在插入数据时,自增键的值可以直接使用 null 来表示。如果现在需要知道插入以后,这条数据的自增值是多少时,要怎样实现呢?

String sql = "insert into user values(null,?,?)";

// 调用 prepareStatement()方法时,传入 RETURN_GENERATED_KEYS 参数,可以获取到插入数据以后自增键的值
PreparedStatement pst = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pst.setString(1, "jack");
pst.setString(2, "234345");
pst.executeUpdate();

// 调用 getGeneratedKeys() 可以获到自增键
ResultSet generatedKeys = pst.getGeneratedKeys();
while (generatedKeys.next()) {
    System.out.println(generatedKeys.getInt(1));
}
Copy

4. 提高批处理效率

在连接MySQL数据库的url里添加rewriteBatchedStatements=true参数,可以进行快速批处理操作,当插入多条数据时,效率会有明显的提升。

// 在连接数据库时,要添加 rewriteBatchedStatements=true 参数,可以提升批处理的效率
String url = "jdbc:mysql://localhost/demo?rewriteBatchedStatements=true";
String user = "root";
String password = "Abcd1234";
Connection connection = DriverManager.getConnection(url, user, password);

String sql = "insert into user values(null,?,?)";
PreparedStatement pst = connection.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 2; i < 10000; i++) {
    pst.setString(1, "jack" + i);
    pst.setString(2, "34irosef0eio");
    pst.addBatch();
}
pst.executeBatch();

long end = System.currentTimeMillis();
System.out.println(end - start);

5. 事务处理

使用代码实现事务处理分为三步:

  1. 关闭MySQL的事务自动提交。connection.setAutoCommit(false);
  2. 调用Connection对象的commit方法提交事务,或者rollback方法回滚事务。
  3. 事务处理完成以后,再调用connection.setAutoCommit(true)打开自动提交事务。避免后续从连接池获取数据库连接时可能出现的问题。
Scanner scanner = new Scanner(System.in);
System.out.print("请输入转账金额:");
float money = scanner.nextFloat();
String sql1 = "select balance from account where id=1;";


PreparedStatement pst = connection.prepareStatement(sql1);
ResultSet resultSet = pst.executeQuery();
System.out.println(resultSet.next());
float balance = resultSet.getFloat(1);

// 关闭MySQL自动提交事务
connection.setAutoCommit(false);

String sql2 = "update account set balance=balance-? where id=1;";
pst = connection.prepareStatement(sql2);
pst.setFloat(1, money);
pst.executeUpdate();

String sql3 = "update account set balance=balance+? where id=2;";
pst = connection.prepareStatement(sql3);
pst.setFloat(1, money);
pst.executeUpdate();

if (balance > money) {
    System.out.println("转账成功!");
    connection.commit();  // 成功就直接提交事务
} else {
    System.out.println("余额不足,转账失败!");
    connection.rollback(); // 失败就让事务回滚
}
resultSet.close();
pst.close();
connection.setAutoCommit(true);  // 在关闭连接之前,将自动提交修改为默认值
connection.close();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1381340.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

POI-tl 知识整理:整理1 -> 利用模板向word中写入数据

1 文本传值 Testpublic void testText() throws Exception {XWPFTemplate template XWPFTemplate.compile("D:\\Idea-projects\\POI_word\\templates.docx");Map<String, Object> map new HashMap<>();map.put("title", "Hi, girl"…

针对大规模服务日志敏感信息的长效治理实践

文章目录 1 背景2 目标与措施3 实施3.1 脱敏工具类3.2 JSON脱敏3.3 APT自动脱敏3.3.1 本地缓存问题3.3.2 JDK序列化问题 3.4 弃用方案 4 规划5 总结 1 背景 近年来&#xff0c;国家采取了多项重要举措来加强个人数据保护&#xff0c;包括实施《中华人民共和国网络安全法》和《…

JAVA毕业设计632—基于Java+ssm的宠物店商城系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于Javassm的宠物店商城系统(源代码数据库)632 一、系统介绍 本项目分为用户、营养师、管理员三种角色 1、用户&#xff1a; 登录、注册、宠物信息、宠物粮食、宠物用品、宠物疫…

imx6ull基于yocto工程的l汇编点亮ed

通过汇编点亮led 在裸机状态下通过汇编点亮led&#xff0c;即没有操作系统&#xff0c;(uboot kernel rootfs 都不需要实现&#xff09;。 led点亮原理 1.GPIO复用 根据原理图&#xff0c;找到led对应的引脚&#xff08;pin)&#xff0c;复用为GPIO&#xff08;只有GPIO才能…

平衡搜索二叉树(AVL树)

目录 前言 一、AVL树的概念 二、AVL树的定义 三、AVL树的插入 四、AVL树的旋转 4.1、右单旋 4.2、左单旋 4.3、左右双旋 4.4、右左双旋 五、AVL树的验证 5.1、 验证其为二叉搜索树 5.2、 验证其为平衡树 六、AVL树的性能 前言 二叉搜索树虽可以缩短查找的效率&…

对快速排序思想的进一步理解,分而治之,欧几里得算法(常用求最大公约数的方法)

自己找到的最优的快排的代码 快速排序 思想 分而治之使用欧几里得算法&#xff08;辗转相除法&#xff09;来求解一个应用题 假设有一块地&#xff0c;现在用这个同样大小的正方形来铺满&#xff0c;求所可用的最大的正方形地砖的面积 这两个方法放在一起是因为这个欧几里得要…

JS中的File(二):TypedArray和ArrayBuffer详解

目录 一、TypedArray 1、定义 2、注意事项 二、ArrayBuffer 1、定义和构造 2、属性 3、方法 4、使用意义 三、Blob、TypedArray和ArrayBuffer的互相转换 1、websocket接收arrayBuffer 2、blob转arrayBuffer 3、arrayBuffer to Blob 4、ArrayBuffer to Uint8数组&am…

两周掌握Vue3(五):自定义指令、路由、ajax

文章目录 一、自定义指令1.创建和使用自定义指令2.钩子函数3.使用参数 二、路由1.创建一个router实例2.在components目录中创建组件3.将路由实例挂载到应用4.使用路由 三、Ajax 代码仓库&#xff1a;跳转 当前分支&#xff1a;05 一、自定义指令 自定义指令是Vue.js框架提供的…

掌握WPF控件:熟练常用属性(一)

WPF布局常用控件&#xff08;一&#xff09; Border Border控件是一个装饰控件&#xff0c;用于围绕其他元素绘制边框和背景。它提供了一种简单的方式来为其他控件添加边框和背景样式&#xff0c;而无需自定义控件的绘制逻辑。 常用属性描述Background用于设置背景颜色或图像…

增删改查管理系统 总结1

//提醒&#xff1a; 管理员也要有增删改查 新增员工代码完善2可能需要用到 目录 细节1 pom文件出现奇怪页面&#xff1f; 细节2 如何联系DataGrip与idea&#xff1f; 细节3 Yapi?接口文档&#xff1f;如何有以下画面&#xff1f; ​细节4 如何将时间转化为好看的时间&…

【.NET Core】Lazy<T> 实现延迟加载详解

【.NET Core】Lazy 实现延迟加载详解 文章目录 【.NET Core】Lazy<T> 实现延迟加载详解一、概述二、Lazy<T>是什么三、Lazy基本用法3.1 构造时使用默认的初始化方式3.2 构造时使用指定的委托初始化 四、Lazy.Value使用五、Lazy扩展用法5.1 实现延迟属性5.2 Lazy实现…

语义分割miou指标计算详解

文章目录 1. 语义分割的评价指标2. 混淆矩阵计算2.1 np.bincount的使用2.2 混淆矩阵计算 3. 语义分割指标计算3.1 IOU计算方式1(推荐)方式2 3.2 Precision 计算3.3 总体的Accuracy计算3.4 Recall 计算3.5 MIOU计算 参考 MIoU全称为Mean Intersection over Union&#xff0c;平均…

山西电力市场日前价格预测【2024-01-13】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-13&#xff09;山西电力市场全天平均日前电价为231.81元/MWh。其中&#xff0c;最高日前电价为345.71元/MWh&#xff0c;预计出现在00:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

大模型实战笔记04——XTuner 大模型单卡低成本微调实战

大模型实战笔记04——XTuner 大模型单卡低成本微调实战 1、Finetune简介 2、XTuner 3、8GB显存玩转LLM 4、动手实战环节 注&#xff1a; 笔记内容均为截图 课程视频地址&#xff1a;https://www.bilibili.com/video/BV1yK4y1B75J/?spm_id_from333.788&vd_source2882acf…

行为型设计模式——备忘录模式

备忘录模式 备忘录模式提供了一种状态恢复的实现机制&#xff0c;使得用户可以方便地回到一个特定的历史步骤&#xff0c;当新的状态无效或者存在问题时&#xff0c;可以使用暂时存储起来的备忘录将状态复原&#xff0c;很多软件都提供了撤销&#xff08;Undo&#xff09;操作…

计算机网络NCEPU复习资料

目录 一&#xff0e;概述&#xff1a; 计算机网络组成&#xff1a; 计算机网络分类&#xff1a; 计算机网络体系结构&#xff1a; C/S架构与P2P架构区别&#xff1a; OSI开放式系统互连参考模型&#xff1a; OSI开放式系统互连参考模型 相关协议&#xff1a; 五层协议网…

【Vue2】一个数组按时间分割为【今年】和【往年】俩个数组

一. 需求 后端返回一个数组&#xff0c;前端按时间维度将该数组的分割为【今年】和【往年】俩个数组后端返回的数组格式如下 timeList:[{id:1,billTime:"2024-01-10",createTime:"2024-01-10 00:00:00",status:0},{id:2,billTime:"2022-05-25"…

(收藏)数据治理:一文讲透数据安全

数据治理&#xff1a;一文讲透数据安全 数据安全是数据治理的核心内容之一&#xff0c;随着数据治理的深入&#xff0c;我不断的碰到数据安全中的金发姑娘问题&#xff08;指安全和效率的平衡&#xff09;。 DAMA说&#xff0c;降低风险和促进业务增长是数据安全活动的主要…

详解Java信号量-Semaphore

第1章&#xff1a;引言 大家好&#xff0c;我是小黑。今天&#xff0c;咱们一起来深入探讨一下Semaphore。在Java中&#xff0c;正确地管理并发是一件既挑战又有趣的事情。当谈到并发控制&#xff0c;大家可能首先想到的是synchronized关键字或者是ReentrantLock。但其实&…

Open3D 获取点云坐标最值(17)

Open3D 获取点云坐标最值(17) 一、算法介绍二、算法实现1.代码2.结果人生天地间,忽如远行客 一、算法介绍 快速获取点云块,沿着 x y z 各方向的坐标最值,这些在点云处理中的应用范围是如此广泛,这也是点云最常被用到的关键信息,后续的很多算法都会设置到这一处理方法。…