百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

JDBC Batch Updates(二) jdbc批量更新三种模式

yuyutoo 2024-10-28 20:21 3 浏览 0 评论

最近在看一本书《high performance java persistence》,做一下笔记

这章不会太长,也是拓展一下大家的知识。

java.sql.Statement: 执行SQL语句并获取执行结果集,记住喔,这个接口的实现类执行的静态SQL语句喔。

java.sql.PreparedStatement:如果你翻开JDK,里面指的是一个预编译的SQL语句,文绉绉的,其实就是动态传参的SQL语句。

java.sql.CallableStatement:执行存储过程的接口。

Batch updates,中文译过来就是批量更新。我们平时都是用框架去做这些东西,却对底层了解的很少,下面我就和大家介绍一下。

JDBC2.0引入指量更新。这里于多条的DML statements(DML 语句)可以组合在一个请求里面发送给数据库。

看一段代码:

statement.addBatch(
"INSERT INTO post (title, version, id) " + "VALUES ('Post no. 1', 0, 1)");
statement.addBatch(
"INSERT INTO post_comment (post_id, review, version, id) " + "VALUES (1, 'Post comment 1.1', 0, 1)");
int[] updateCounts = statement.executeBatch();

这里就要敲黑板了,是扩充你的知识面的时候。不同的数据库厂商实现的会有所差异的,下面我是根据书还有一些文章来给你解释一下:

首先是Oracle,对于Statement和CallableStatement,其实是没并没有真正的像我上面说的合成一个请求,其实是每一条语句独立执行并没有批量执行,所以性能上面并没有提升的。PrepareStatment是有能进行批量处理的,但是那个batch size你要注意了,官方提出是50-100最佳。原因就是如果批次太大会造成占用太大的内存,通常会导致系统性能下降。

书中原文:

Oracle

For Statement and CallableStatement, the Oracle JDBC Driver doesn’t actually support batching For anything but PreparedStatement, the driver ignores batching, and each statement is executed separately.

然后我又去了官方文档找了一下:http://docs.oracle.com/cd/E11882_01/java.112/e16548/oraperf.htm#JJDBC28752

文档提及

The Oracle implementation of standard update batching does not implement true batching for generic statements and callable statements. Even though Oracle JDBC supports the use of standard batching for Statement and CallableStatement objects, you are unlikely to see performance improvement.

因为我说的不一定正确,书中也不一定正确,所以官方文档是最靠谱的。下面我解析其他数据库厂商的实现再不会贴英文了,但是我会将官方文档贴链接贴着,方便你去查证。

对于Mysql:

https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html

Mysql默认是没有将多条语句合成一个batch发送给数据库。但是为了达到batch,驱动提供了一个属性rewriteBatchedStatements,当设置为true的时候,你的批处理才会生效,不然你用框架傻傻的写代码,然后会发现怎么性能没上来,换个框架还是没有上来。其实在你jdbc.url拼接的时候加上rewriteBatchedStatements=true就大大的提升了性能了。我就在网上随便找一条sample

master.jdbc.url=jdbc:mysql://112.126.84.3:3306/platform?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true

但是这个参数也会带来一定副作用。但是根据官文我也不是很了解是什么意思,如果你知道,评论区留言一下让我知道。

Bulk Operations的操作性能会比batch update好,但是灵活性不如batch update.工作当中我也没涉及到这一块。

主键的生成通常都交给数据库,但是如果获取回生成的主键呢。

通过PrepareStatment有三种方式:

第一种:

PreparedStatement postStatement = connection.prepareStatement(
  "INSERT INTO post (title, version) VALUES (?, ?)",
  Statement.RETURN_GENERATED_KEYS
);

第二种:

PreparedStatement postStatement = connection.prepareStatement( 
  "INSERT INTO post (title, version) VALUES (?, ?)",
	new int[] {1}
);

第三种:

PreparedStatement postStatement = connection.prepareStatement( 
  "INSERT INTO post (title, version) VALUES (?, ?)",
	new String[] {"id"}
);

根据JDBC4.2的规范,每个driver都必须实现supportsGetGeneratedKeys()来说明是否支持获取主键。是不是觉得很有意思。平时写代码的时候根本没有注意这一块。但是这个对于Statment是强制性要求的,但是对于PrepareStatment是没有要求的。下图算是拓展知识吧。


序列,有一些数据库提供序列就是sequence来将主键的生成和数据插入进行分离。

下面是几种数据分别创表和获取序列的语法

创表:

#Oracle 12c 之前的创建表
CREATE SEQUENCE post_seq;
CREATE TABLE post (
id NUMBER(19,0) NOT NULL, title VARCHAR2(255 CHAR), version NUMBER(10,0) NOT NULL, PRIMARY KEY (id));
CREATE OR REPLACE TRIGGER post_identity BEFORE INSERT ON post
FOR EACH ROW
BEGIN
SELECT post_seq.NEXTVAL INTO :NEW.id
FROM dual;
end;

#Oracle 12c 之后

CREATE TABLE post (
id NUMBER(19,0) NOT NULL GENERATED ALWAYS AS IDENTITY, title VARCHAR2(255 CHAR),
version NUMBER(10,0) NOT NULL,
PRIMARY KEY (id));

SQL Server

CREATE TABLE post (
	id BIGINT IDENTITY NOT NULL, 
  title VARCHAR(255),
	version INT NOT NULL, 
  PRIMARY KEY (id));

PostgreSQL 9.5

CREATE TABLE post (
	id SERIAL NOT NULL, 
  title VARCHAR(255),
  version INT4 NOT NULL, 
  PRIMARY KEY (id)
);
#另外一种创表

CREATE TABLE post (
id INTEGER DEFAULT NEXTVAL('post_id_seq') NOT NULL, title VARCHAR(255),
version INT4 NOT NULL,
PRIMARY KEY (id));
);

MysSQL 5.7


CREATE TABLE post (
id BIGINT NOT NULL AUTO_INCREMENT,
title VARCHAR(255),
version INTEGER NOT NULL,
PRIMARY KEY (id));

获取序列:

#Oracle
SELECT post_seq.NEXTVAL FROM dual; 

#SQL Server
SELECT NEXT VALUE FOR post_seq; 

#PostgreSQL
SELECT NEXTVAL('post_seq');

可以看到PostgresSQL使用SERIAL,底层还是用序列实现。

下一篇我会聊一下Statement Caching 语句缓存。

相关推荐

Java开发中如何优雅地避免OOM(OutOfMemoryError)

Java开发中如何优雅地避免OOM(OutOfMemoryError)在这个信息化高速发展的时代,内存就像程序员手中的笔,缺了它就什么都写不出来。而OOM(OutOfMemoryError)就像是横在...

常见的JVM调优方法和步骤

1、内存调优堆内存设置:通过-Xms和-Xmx参数调整初始和最大堆内存大小-Xms:初始堆大小(如-Xms512M)-Xmx:最大堆大小(如-Xmx2048M)调整新生代和老年代的比例...

Java中9种常见的CMS GC问题分析与解决(一)

目前,互联网上Java的...

JDK21新特性:Prepare to Disallow the Dynamic Loading of Agents

PreparetoDisallowtheDynamicLoadingofAgentsJEP451:准备禁止动态加载代理摘要...

Java程序GC垃圾回收机制优化指南

Java程序GC垃圾回收机制优化指南作为一个Java开发者,我们经常会在任务管理器里看到Java进程占用内存不断增长,然后突然下降的现象。这其实就是在Java虚拟机中运行的垃圾回收(GC)机制在起作用...

Java Java命令学习系列(一)——Jps

jps位于jdk的bin目录下,其作用是显示当前系统的java进程情况,及其id号。jps相当于Solaris进程工具ps。不象”pgrepjava”或”ps-efgrepjava”,jps...

面试题专题:头条一面参考答案(003)

前两篇文章也都是介绍头条一面的内容及参考答案...

Java JVM原理与性能调优:从基础到高级应用

一、JVM基础架构与内存模型1.1JVM整体架构概览Java虚拟机(JVM)是Java程序运行的基石,它由以下几个核心子系统组成:...

死锁攻防战:阿里架构师教你用3种核武器杜绝程序僵死

从线程转储分析到银行家算法,彻底掌握大厂必考的死锁解决方案以下是为Java死锁问题设计的结构化技术解析方案,包含代码级解决方案与高频追问应对策略:...

Java 1.8 虚拟机内存分布详解

Java1.8虚拟机内存分布详解Java1.8的JVM内存布局相比早期版本有显著变化(如永久代被元空间取代)。以下是其核心内存区域的划分、作用及配置参数:一、JVM内存整体结构...

Java 多线程开发难题?这篇文章给你答案!

作为互联网大厂的后端开发人员,在Java多线程开发过程中,必然会面临诸多复杂且具有挑战性的问题。在高并发场景下,各类潜在问题对系统的稳定性与性能产生严重影响,本文将深入探讨这些问题,并提供全面且有...

软件性能调优全攻略:从瓶颈定位到工具应用

性能调优是软件测试中的重要环节,旨在提高系统的响应时间、吞吐量、并发能力、资源利用率,并降低系统崩溃或卡顿的风险。通常,性能调优涉及发现性能瓶颈、分析问题根因、优化代码和系统配置等步骤,调优之前需要先...

JVM性能优化实战技巧

JVM性能优化实战技巧在现代企业级应用开发中,JavaVirtualMachine(JVM)作为承载Java应用程序的核心引擎,其性能直接决定了系统的响应速度、吞吐量以及资源利用率。因此,掌握一些...

JVM 深度解析:运行时数据区域、分代回收与垃圾回收机制全攻略

共同学习,有错欢迎指出。JVM运行时数据区域1.程序计数器程序计数器是一块较小的内存空间,可看作当前线程所执行的字节码的行号指示器。在虚拟机概念模型里,字节码解释器通过改变这个计数器的值选取下一条...

JVM内存管理详解与调优实战

JVM内存管理详解与调优实战Java虚拟机(JVM)作为Java程序运行的核心组件,其内存管理机制直接影响着应用程序的性能表现。今天,咱们就来一场既严肃又有趣的JVM内存管理之旅,看看这个“幕后英雄”...

取消回复欢迎 发表评论: