Java基础回顾——JDBC

news2025/2/8 11:31:48

文章目录

  • 介绍
  • 使用
  • JDBC事务
  • JDBC Batch
  • JDBC连接池

介绍

Java为关系数据库定义了一套标准的访问接口:JDBC(Java Database Connectivity)

JDBC是Java程序访问数据库的标准接口

好处:

  • 各数据库厂商使用相同的接口,Java代码不需要针对数据库分别开发
  • Java程序编译期仅依赖java.sql包,不依赖具体数据库的jar包
  • 可随时替换底层数据库,访问数据库的Java代码基本不变

使用

maven导入依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    <scope>runtime</scope>
</dependency>
import java.sql.*;

public class JDBCTest {
    public static void main(String[] args) throws SQLException {
        String jdbc_url="jdbc:mysql://localhost:3306/learnjdbc?useSSL=false&characterEncoding=utf8";
        String jdbc_user="root";
        String jdbc_password="123456";
        try (Connection conn = DriverManager.getConnection(jdbc_url, jdbc_user, jdbc_password)) {
            try (Statement stmt = conn.createStatement()) {
                try (ResultSet rs = stmt.executeQuery("SELECT id, grade, name, gender FROM students WHERE gender=1")) {
                    while (rs.next()) {
                        long id = rs.getLong(1); // 注意:索引从1开始
                        long grade = rs.getLong(2);
                        String name = rs.getString(3);
                        int gender = rs.getInt(4);
                        System.out.println(id+","+grade+","+name+","+gender);
                    }
                }
            }
        }
    }
}

使用Statement拼字符串非常容易引发SQL注入的问题,这是因为SQL参数往往是从方法参数传入的。

解决办法:
使用PreparedStatement。使用PreparedStatement可以完全避免SQL注入的问题,因为PreparedStatement始终使用?作为占位符,并且把数据连同SQL本身传给数据库,这样可以保证每次传给数据库的SQL语句是相同的,只是占位符的数据不同,还能高效利用数据库本身对查询的缓存。

        try (Connection conn = DriverManager.getConnection(jdbc_url, jdbc_user, jdbc_password)) {
            try (PreparedStatement ps = conn.prepareStatement("SELECT id, grade, name, gender FROM students WHERE gender=? AND grade=?")) {
                ps.setObject(1, "M"); // 注意:索引从1开始
                ps.setObject(2, 3);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        long id = rs.getLong("id");
                        long grade = rs.getLong("grade");
                        String name = rs.getString("name");
                        String gender = rs.getString("gender");
                        System.out.println(id+","+grade+","+name+","+gender);
                    }
                }
            }
        }

使用PreparedStatement,必须首先调用setObject()设置每个占位符?的值,最后获取的仍然是ResultSet对象

插入和删除操作

        try (Connection conn = DriverManager.getConnection(jdbc_url, jdbc_user, jdbc_password)) {
//            try (PreparedStatement ps = conn.prepareStatement(
//                    "INSERT INTO students (id, grade, name, gender,score) VALUES (?,?,?,?,?)")) {
//                ps.setObject(1, 999); // 注意:索引从1开始
//                ps.setObject(2, 1); // grade
//                ps.setObject(3, "Bob"); // name
//                ps.setObject(4, 0); // gender
//                ps.setObject(5, 80); // gender
//                int n = ps.executeUpdate(); // 1
//            }
            try (PreparedStatement ps = conn.prepareStatement("DELETE FROM students WHERE id=?")) {
                ps.setObject(1, 999); // 注意:索引从1开始
                int n = ps.executeUpdate(); // 删除的行数
            }
        }

JDBC事务

数据库系统保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行,即数据库事务具有ACID特性:

  • Atomicity:原子性
  • Consistency:一致性
  • Isolation:隔离性
  • Durability:持久性

数据库系统从效率考虑,对事务定义了不同的隔离级别。SQL标准定义了4种隔离级别,分别对应可能出现的数据不一致的情况:
在这里插入图片描述

要在JDBC中执行事务,本质上就是如何把多条SQL包裹在一个数据库事务中执行。,默认情况下,获取到Connection连接后,总是处于“自动提交”模式,也就是每执行一条SQL都是作为事务自动执行的。

Connection conn = openConnection();
try {
    // 关闭自动提交:
    conn.setAutoCommit(false);
    // 执行多条SQL语句:
    insert(); update(); delete();
    // 提交事务:
    conn.commit();
} catch (SQLException e) {
    // 回滚事务:
    conn.rollback();
} finally {
    conn.setAutoCommit(true);
    conn.close();
}

如果要设定事务的隔离级别,可以使用如下代码:

// 设定隔离级别为READ COMMITTED:
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

如果没有调用上述方法,那么会使用数据库的默认隔离级别。MySQL的默认隔离级别是REPEATABLE_READ。

JDBC Batch

批量操作

通过一个循环来执行每个PreparedStatement虽然可行,但是性能很低。SQL数据库对SQL语句相同,但只有参数不同的若干语句可以作为batch执行,即批量执行,这种操作有特别优化,速度远远快于循环执行每个SQL。

try (PreparedStatement ps = conn.prepareStatement("INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)")) {
    // 对同一个PreparedStatement反复设置参数并调用addBatch():
    for (Student s : students) {
        ps.setString(1, s.name);
        ps.setBoolean(2, s.gender);
        ps.setInt(3, s.grade);
        ps.setInt(4, s.score);
        ps.addBatch(); // 添加到batch
    }
    // 执行batch:
    int[] ns = ps.executeBatch();
    for (int n : ns) {
        System.out.println(n + " inserted."); // batch中每个SQL执行的结果数量
    }
}

执行batch和执行一个SQL不同点在于,需要对同一个PreparedStatement反复设置参数并调用addBatch(),这样就相当于给一个SQL加上了多组参数,相当于变成了“多行”SQL。

第二个不同点是调用的不是executeUpdate(),而是executeBatch(),因为设置了多组参数,相应地,返回结果也是多个int值,因此返回类型是int[],循环int[]数组即可获取每组参数执行后影响的结果数量。

JDBC连接池

执行JDBC的增删改查的操作时,如果每一次操作都来一次打开连接,操作,关闭连接,创建和销毁JDBC连接的开销就太大了。为了避免频繁地创建和销毁JDBC连接,可以通过连接池(Connection Pool)复用已经创建好的连接

JDBC连接池有一个标准的接口javax.sql.DataSource,注意这个类位于Java标准库中,但仅仅是接口。要使用JDBC连接池,必须选择一个JDBC连接池的实现。常用的JDBC连接池有:

  • HikariCP
  • C3P0
  • BoneCP
  • Druid

依赖:com.zaxxer:HikariCP:2.7.1

        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/learnjdbc");
        config.setUsername("root");
        config.setPassword("123456");
        config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒
        config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒
        config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10
        DataSource ds = new HikariDataSource(config);

//有了连接池以后,获取Connection时,把DriverManage.getConnection()改为ds.getConnection()
        try (Connection conn = ds.getConnection()) { // 在此获取连接
            try (PreparedStatement ps = conn.prepareStatement("SELECT id, grade, name, gender FROM students WHERE gender=? AND grade=?")) {
                ps.setObject(1, "M"); // 注意:索引从1开始
                ps.setObject(2, 3);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        long id = rs.getLong("id");
                        long grade = rs.getLong("grade");
                        String name = rs.getString("name");
                        String gender = rs.getString("gender");
                        System.out.println(id+","+grade+","+name+","+gender);
                    }
                }
            }
        } // 在此“关闭”连接

通过连接池获取连接时,并不需要指定JDBC的相关URL、用户名、口令等信息,因为这些信息已经存储在连接池内部了(创建HikariDataSource时传入的HikariConfig持有这些信息)。一开始,连接池内部并没有连接,所以,第一次调用ds.getConnection(),会迫使连接池内部先创建一个Connection,再返回给客户端使用。当调用conn.close()方法时(在try(resource){…}结束处),不是真正“关闭”连接,而是释放到连接池中,以便下次获取连接时能直接返回。

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

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

相关文章

基于SSM+Vue的教材信息管理系统(Java毕业设计)

点击咨询源码 大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的…

Python遥感影像深度学习指南(2)-在 PyTorch 中创建自定义数据集和加载器

在上一篇 文章中,我们Fast.ai 在卫星图像中检测云轮廓,检测物体轮廓被称为语义分割。虽然我们用几行代码就能达到 96% 的准确率,但该模型无法考虑数据集中提供的所有输入通道(红、绿、蓝和近红外)。问题在于,深度学习框架(如 Keras、Fast.ai 甚至 PyTorch)中的大多数语…

OAuth2授权码模式---详解

OAuth2简介 是一个业界标准的授权协议&#xff08;authorization protocol&#xff09;&#xff0c;这里的授权是以委派代理&#xff08;delegation&#xff09;的方式。可以这样理解&#xff0c;OAuth 2.0提供一种协议交互框架&#xff0c;让某个应用能够以安全地方式获取到用…

利用html2Canvas将表格下载为html

给到我的需求是点击按钮时请求后端接口&#xff0c;根据后端返回的数据&#xff0c;生成表格,并将表格的内容直接下载为html,如下图。 平常做的下载都是后端返回二进制流&#xff0c;这次前端做下载那就必须把页面先画出来&#xff0c;因为下载下来的表格在页面上是不显示的&a…

知网查重链接(知网个人版)

该系统支持毕业设计&#xff08;本科专科&#xff09;、学位论文&#xff08;研究生&#xff09;、课程作业&#xff08;本科专科&#xff09;、课程作业&#xff08;研究生&#xff09;、职称评审、学术出版、学术研究、基础教育、政务公文、党团材料、新闻稿件、总结报告等各…

关于Python里xlwings库对Excel表格的操作(十九)

这篇小笔记主要记录如何【取消合并单元格】。 前面的小笔记已整理成目录&#xff0c;可点链接去目录寻找所需更方便。 【目录部分内容如下】【点击此处可进入目录】 &#xff08;1&#xff09;如何安装导入xlwings库&#xff1b; &#xff08;2&#xff09;如何在Wps下使用xlwi…

【Spring实战】05 CommandLineRunner

文章目录 1. 简介2. 用法1&#xff09;单个 CommandLineRunner2&#xff09;多个 CommandLineRunner 3. 优点4. 缺点总结 CommandLineRunner 是 Spring Boot 提供的一个接口&#xff0c;用于在 Spring Boot 应用程序启动后执行一些任务。通过实现 CommandLineRunner 接口&#…

IntelliJ IDEA [设置] 隐藏 .idea 等 .XXX 文件夹

文章目录 1. 问题描述2. 解决办法3. 最后效果总结 我们使用 IntelliJ IDEA 导入项目的时候&#xff0c;经常会看到一些 .XXX 的文件夹&#xff08;例如&#xff1a;.idea&#xff0c;.mvn&#xff0c;.gradle 等&#xff09;。其实这些文件夹和我们代码编写是无关的&#xff0c…

5G NR无线蜂窝系统的信道估计器设计

文章目录 DMRS简介DMRS类型DMRS频域密度 信道估计实验仿真实验参数实验实验结论 DMRS简介 DMRS类型 类型A&#xff1a;DMRS位于时隙的第二个或第三个OFDM符号&#xff0c;由14个OFDM符号组成&#xff0c;当数据占据大部分时隙时使用A型映射。 类型B&#xff1a;用在URLLC中&a…

JSON在Java中的使用

目录 第一章、快速了解JSON1.1&#xff09;JSON是什么1.2&#xff09;json的语法格式①键值对、字符串、数字、布尔值、数组、对象②嵌套的格式 1.3&#xff09;为什么使用JSON 第二章、发送和接收JSON格式数据2.1&#xff09;postman发送JSON格式数据2.2&#xff09;Java后端接…

开源verilog模拟 iverilog verilator +gtkwave仿真及一点区别

开源的 iverilog verilator 和商业软件动不动几G几十G相比&#xff0c;体积小的几乎可以忽略不计。 两个都比较好用&#xff0c;各有优势。 iverilog兼容性好。 verilator速度快。 配上gtkwave 看波形&#xff0c;仿真工具基本就齐了。 说下基本用法 计数器 counter.v module…

根文件系统制作-移植

【1】概念 根文件系统&#xff1a;系统运行所必须依赖的一些文件 &#xff08;比如脚本、库、配置文件...&#xff09;&#xff0c;本质就是目录和文件。根文件系统镜像&#xff1a;将根文件系统按照某种格式进行打包压缩后生成的单个文件 rootfs-----> ramdisk.img 文件系…

多行文本(多行字符串)中,如果每行文本前都有空格,各行文本前空格数最小为n,则删除每行文本前的n个空格。textwrap.dedent(多行字符串)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 多行文本(多行字符串)中&#xff0c; 如果每行文本前都有空格&#xff0c; 各行文本前空格数最小为n&#xff0c; 则删除每行文本前的n个空格。 textwrap.dedent(多行字符串) 请问以下代…

汽车项目管理

项目节点&#xff1a; MR (Management Review)——管理层评审 KO (Kick Off)——项目正式启动 SI (Strategy Intent)——战略意图 SC (Strategy Confirmation)——战略确认 PA (Program Approval)——项目批准 PR (Product Readiness)——产品就绪 VP (Verification Prototype)…

在Vue3中使用vue-qrcode库实现二维码生成

本文主要介绍在Vue3中使用qrcode库实现二维码生成的方法。 目录 一、基础用法实现vue-qrcode库的参数介绍 在Vue3中实现二维码生成需要使用第三方库来处理生成二维码的逻辑。常用的库有 qrcode和 vue-qrcode。 一、基础用法实现 在Vue3中使用vue-qrcode库实现二维码生成的方…

人大金仓助力某市公积金核心业务系统国产化升级

近日&#xff0c;在金仓数据库的支撑下&#xff0c;某市住房公积金管理中心多个核心业务系统顺利上线&#xff0c;服务该市330余万常住人口&#xff0c;进一步“让信息多跑路&#xff0c;群众少跑路”&#xff0c;提升公积金服务效率。 “ 适应信息技术应用创新趋势的重点示范项…

Docker部署Nexus Maven私服并实现远程访问Nexus界面

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定N…

arduino声波测距

先安装&#xff1a;Ultrasonic库&#xff1b; #include <Arduino.h> #include <U8g2lib.h> #include <Wire.h> #include <Ultrasonic.h>U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0,A5,A4, U8X8_PIN_NONE); // SDA:21 scl:22 Ultrasonic ul…

MyBatis——MyBatis的缓存

MyBatis的缓存 创建工程&#xff1a; 1缓存介绍 为什么使用缓存&#xff1f; 首次访问时&#xff0c;查询数据库&#xff0c;并将数据存储到内存中&#xff1b;再次访问时直接访问缓存&#xff0c;减少IO、硬盘读写次数、提高效率 Mybatis中的一级缓存和二级缓存&#xff1f;…

计算机网络简述

前言 计算机网路是一个很庞大的话题。在此我仅对其基础概述以及简单应用进行陈述。后续或有补充以形成完善的计算机网络知识体系。 一.计算机网络的定义 根据百度词条的描述&#xff0c;计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过…