Java基础回顾——JDBC

文章目录

  • 介绍
  • 使用
  • 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"); // 最大连接数:10DataSource 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.rhkb.cn/news/224934.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动物分类识别教程+分类释义+界面展示

1.项目简介 动物分类教程分类释义界面展示 动物分类是生物学中的一个基础知识&#xff0c;它是对动物进行分类、命名和描述的科学方法。本教程将向您介绍动物分类的基本原则和方法&#xff0c;并提供一些常见的动物分类释义。 动物分类的基本原则 动物分类根据动物的形态、…

分布式事务是什么

分布式事务是企业集成中的一个技术难点&#xff0c;也是每一个分布式系统架构中都会涉及到的一个东西&#xff0c;特别是在微服务架构中&#xff0c;几乎可以说是无法避免&#xff0c;本文就分布式事务来简单聊一下。 数据库事务 我们先从数据库事务说起。数据库事务可能大家…

(001)Unit 编译 UTF8JSON

文章目录 编译 Dll编译报错附录 编译 Dll 新建工程&#xff1a; 注意 UnityEngineDll 的选择&#xff01;2022 版本的太高了&#xff01;&#xff01;&#xff01; 下载包&#xff0c;导入unity : 3. 将 unf8json 的源码拷贝到新建的工程。 4. 编译发布版本&#xff1a; 编译…

ggkegg玩转KEGG数据 | 富集 | 可视化

本期内容 写在前面 今天分享一个关于KEGG通路图绘制的R包&#xff0c;也许在你后面的分析中可以使用得到。 在KEGG富集分析中&#xff0c;若我们要绘制某一个富集通路&#xff0c;一般回到KEGG官网中寻找该通路的富集图。然后&#xff0c;通过AI&#xff0c;PPT等等一系列手段…

【MySQL】数据库之小题练习(完全备份和增量备份的数据恢复,以及断点恢复)

目录 先创建库&#xff0c;创建表&#xff0c;完成三次数据的录入以及第一次的完全备份&#xff0c;第二次和第三次的增量备份&#xff1b; 第一次完全备份操作 第二次插入后做增量备份操作 第三次 插入后做增量备份操作 1、完全备份恢复&#xff0c;获取一班的人的成绩 …

内网穿透中微子代理搭建使用

内网穿透中微子代理搭建使用 环境准备服务器端部署客户端安装服务器开启端口 环境准备 中微子代理项目地址 最新版是2.0.1版本,需要java21的环境,考虑到现在项目大多数环境都是java8,稳重使用1.9版本搭建,jar下载地址: 准备一台有公网ip的服务器(或云服务器),本文中使用阿里…

【教程】从gitee或者github,下载单个文件或文件夹命令

1.打开git 2.初始化 git init 3.设置允许下载子目录 &#xff08;不需要修改任何&#xff0c;只要原样复制&#xff0c;需要按照个人状况修改的话我会标注&#xff09; git config core.sparseCheckout true 4. 选择要下载的单个文件夹的路径 这里单引号内部需要修改&…

redis基本用法学习(C#调用FreeRedis操作redis)

FreeRedis属于常用的基于.net的redis客户端&#xff0c;EasyCaching中也提供适配FreeRedis的包。根据参考文献4中的说法&#xff0c;FreeRedis和CsRedis算是近亲&#xff08;都是GitHub中账号为2881099下的开源项目&#xff09;&#xff0c;因此其用法特别相似。FreeRedis的主要…

论文阅读<CF-YOLO: Cross Fusion YOLO for Object Detection in Adverse Weather.....>

论文链接&#xff1a;https://arxiv.org/pdf/2309.08152.pdfhttps://arxiv.org/pdf/2206.01381.pdfhttps://arxiv.org/pdf/2309.08152.pdf 代码链接&#xff1a;https://github.com/DiffPrompter/diff-prompter 目前没有完整代码放出。 恶劣天气下的目标检测主要有以下三种解…

docker笔记1-安装与基础命令

docker的用途&#xff1a; 可以把应用程序代码及运行依赖环境打包成镜像&#xff0c;作为交付介质&#xff0c;在各种环境部署。可以将镜像&#xff08;image&#xff09;启动成容器&#xff08;container&#xff09;&#xff0c;并提供多容器的生命周期进行管理&#xff08;…

iPad绘画之旅:从小白到文创手账设计的萌系简笔画探索

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 iPad的出现&#xff0c;不仅改变了我们对电子设…

孔夫子二手书采集

文章目录 项目演示软件采集单本数据网页搜索数据对比 使用场景概述部分核心逻辑Vb工程图数据导入与读取下拉框选择参数设置线程 使用方法下载软件授权导入文件预览处理后的数据 项目结构附件说明 项目演示 操作视频详见演示视频&#xff0c;以下为图文演示 软件采集单本数据 …

mac传输文件到windows

前言 由于mac系统与windows系统文件格式不同&#xff0c;通过U盘进行文件拷贝时&#xff0c;导致无法拷贝。 几种文件格式说明&#xff1a; NTFS 文件格式&#xff1a;只适用于 windows 系统&#xff0c;不适用于 mac 系统&#xff1b; APFS 文件格式&#xff1a;mac 系统格式…

云HIS源码 云HIS解决方案 支持医保功能

云HIS系统重建统一的信息架构体系&#xff0c;重构管理服务流程&#xff0c;重造病人服务环境&#xff0c;向不同类型的医疗机构提供SaaS化HIS服务解决方案。 云HIS作为基于云计算的B/S构架的HIS系统&#xff0c;为基层医疗机构&#xff08;包括诊所、社区卫生服务中心、乡镇卫…

Anylogic Pro 8.8.x for Mac / for Linux Crack

Digital twins – a step towards a digital enterprise AnyLogic是唯一一个支持创建模拟模型的方法的模拟建模工具&#xff1a;面向过程&#xff08;离散事件&#xff09;、系统动态和代理&#xff0c;以及它们的任何组合。AnyLogic提供的建模语言的独特性、灵活性和强大性使…

IP应用场景的规划

IP地址作为互联网通信的基石&#xff0c;在现代社会中扮演着至关重要的角色。本文将深入探讨IP地址在不同应用场景中的规划与拓展&#xff0c;探讨其在网络通信、安全、商业、医疗和智能城市等领域的关键作用与未来发展趋势。 IP地址的基本原理 IP地址是分配给网络上设备的数…

基于flask和echarts的新冠疫情实时监控系统源码+数据库,后端基于python的flask框架,前端主要是echarts

介绍 基于flask和echarts的新冠疫情实时监控系统 软件架构 后端基于python的flask框架&#xff0c;前端主要是echarts 安装教程 下载到本地&#xff0c;在python相应环境下运行app.py,flask项目部署请自行完成 使用说明 flaskProject文件夹中 app.py是flask项目主运行文…

自动驾驶中的“雷达”

自动驾驶中有好几种雷达&#xff0c;新手可能会混淆&#xff0c;这里统一介绍一下它们。 首先&#xff0c;所有雷达的原理都是发射波&#xff0c;接收回波&#xff08;可能是声波或电磁波&#xff09;&#xff0c;并通过发射和接收的时间差以及波的速度计算距离。只不过发射的…

普中STM32-PZ6806L开发板(烧录方式)

前言 有两种方式, 串口烧录和STLink方式烧录;串口烧录 步骤 开发板USB转串口CH340驱动板接线到USB连接PC使用自带工具普中自动下载软件.exe烧录程序到开发板 ST Link方式 这种方式需要另外进行供电&#xff0c; 我买的如下&#xff0c;当年用于调试STM8的&#xff0c;也可…

vsetvli/vsetivli/vsetvl

转载自&#xff1a;【《RISC-V “V“ Vector Extension Version 1.0》阅读笔记】_risc v的rvv-CSDN博客 上述指令的作用&#xff1a;快速配置 vl 和 vtype 中的值以匹配应用程序需求&#xff1b; vset{i}vl{i} 指令根据参数设置 vtype 和 vl CSR&#xff0c;并将 vl 的新值写入…