jdbcTemplate.batchUpdate在批量执行的时候,性能差没有效果,看看怎么解决的。

本文通过调整rewriteBatchedStatements参数,显著提升了使用JdbcTemplate在MySQL中的批量插入性能,比较了不同配置下的执行效率,并提供了具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我用的阿里druid数据库连接池(其实这个和连接池毛线关系没得 大笑),创建jdbctemplate在执行insert 15000条数据时 ,我发现还是30条,20条,35条这样提交。 完全没有batch的效果。



 查看数据库,5秒才267条。

在等20秒看,才5130条。


说明这个批量执行,没有生效。


================

================

1. 我们再来,我改造了参数。(截图中是5431毫秒, 写错了)



15000条,数据5秒就搞定。



2.、再试一次 。1秒(1294毫秒)就搞定。






我们对比下。我url修改了什么参数。

修改前:

server.port=29098
  
user.userServicePath=http://localhost:29097/simple/

# 驱动配置信息
spring.datasource.url = jdbc:mysql://192.168.15.44:3306/ml_test?useSSL=false
spring.datasource.username = root
spring.datasource.password = br
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.initialize = true
spring.datasource.init-db = true
spring.datasource.timeout = 60000
spring.datasource.MaxActive = 20
spring.datasource.initActive = 2
spring.datasource.minActive = 0

修改后:

server.port=29098
  
user.userServicePath=http://localhost:29097/simple/

# 驱动配置信息
spring.datasource.url = jdbc:mysql://192.168.15.44:3306/ml_test?useSSL=false&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&autoReconnect=true
spring.datasource.username = root
spring.datasource.password = bro
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.initialize = true
spring.datasource.init-db = true
spring.datasource.timeout = 60000
spring.datasource.MaxActive = 20
spring.datasource.initActive = 2
spring.datasource.minActive = 0


没错,就是

rewriteBatchedStatements=true

jdbcTemplate.batchUpdate 调用的地方:

	public int[] BatchInsertMuser(List<Muser> list, String v_sql) {

		System.out.println("list.size()=" + list.size());
			return jdbcTemplate.batchUpdate(v_sql, new BatchPreparedStatementSetter() {
				public void setValues(PreparedStatement ps, int i) throws SQLException {
					ps.setInt(1, list.get(i).getId());
					ps.setString(2, list.get(i).getName());
					ps.setString(3, list.get(i).getEmail());
				}
				@Override
				public int getBatchSize() {
					// TODO Auto-generated method stub
					return list.size();
				}
			});
			 
	}




--------------------------------结论---------------------------------

MySql   非批量10万条记录,                5700条/秒

MySql   批量(batch)10万条记录,       62500条/秒

oracle   非批量插入10万条记录,            4464条/秒

oracle   批量(batch)插入10万条记录,   27778条/秒




补充:

public int[] batchUpdate(java.lang.String sql,
                         BatchPreparedStatementSetter pss)
                  throws DataAccessException
Description copied from interface: JdbcOperations
Issue multiple update statements on a single PreparedStatement, using batch updates and a BatchPreparedStatementSetter to set values.
Will fall back to separate updates on a single PreparedStatement if the JDBC driver does not support batch updates.

Specified by:
batchUpdate in interface JdbcOperations
Parameters:
sql - defining PreparedStatement that will be reused. All statements in the batch will use the same SQL.
pss - object to set parameters on the PreparedStatement created by this method
Returns:
an array of the number of rows affected by each statement
Throws:
DataAccessException - if there is any problem issuing the update


返回的int[] it .但是里面的值都是-2 ,-2表示成功。没有具体的行数。

但是从目前测试来看,一条成功,就返回-2,  那么可以用it.length() 记录插入成功多少条记录。


15000条,就有15000个 -2






<think>嗯,用户想知道在Java单线程环境下如何实现多SQL的并行执行,而不借助多线程。这个问题看起来有点挑战性,因为通常并行执行需要多线程或者异步处理,但用户明确排除了多线程的使用。首先,我需要仔细理解用户的需求。 首先,用户可能是在一个受限的环境下,比如某些不允许创建新线程的框架或服务器环境中,或者他们希望避免多线程带来的复杂性,比如线程安全和资源竞争的问题。这时候,如何在单线程中模拟并行执行多条SQL语句就成了关键。 接下来,我得回忆一下Java中除了多线程之外,有没有其他的并发模型。比如异步编程或者非阻塞IO。不过,通常异步操作可能会隐式地使用线程池,这算不算多线程呢?比如CompletableFuture默认使用的是ForkJoinPool,如果用户不允许任何多线程的话,这可能不符合要求。但是,如果用户只是不想自己显式地管理线程,那么使用异步框架可能是一个折中的办法。 另外,数据库本身是否有并行处理的能力?比如,使用存储过程或者批量操作,让数据库在内部并行执行多个SQL语句。这可能是一个方向,但需要数据库的支持,比如MySQL的存储过程是否支持并行执行?或者是否可以通过JDBC的批量操作来一次性提交多个语句,让数据库优化执行? 还有一种可能是使用非阻塞的数据库驱动,比如异步JDBC驱动,这样在单线程中通过事件循环的方式发送多个SQL请求,然后等待它们的回调。不过,这样的驱动是否存在呢?比如,像R2DBC这样的反应式驱动,但这是否属于多线程的范畴呢?因为底层可能还是用了线程池,但用户层面是单线程的代码结构。 然后,用户提到的引用中,有关于jdbcTemplate.batchUpdate是否是并行的讨论。根据引用[1],jdbcTemplate.batchUpdate()默认是顺序执行的,但用户可能想利用某种方式让它并行。不过,如果不使用多线程的话,这似乎不可能,除非数据库本身支持并行处理批量语句。 另外,引用[5]提到使用多线程并发插入数据,但用户希望单线程下实现类似的效果。这时候,可能需要依赖数据库的批量处理能力,比如将多个INSERT语句合并成一个批量操作,这样数据库可能会优化执行,虽然这在单线程中还是顺序发送,但减少了网络往返时间,提高了效率。 还有一个思路是使用事务,将多个SQL语句包裹在一个事务中,让数据库在事务内部进行优化。不过,事务通常保证ACID,但不一定并行执行语句,除非数据库引擎支持并行事务处理,但单线程提交事务的话,可能还是顺序执行。 总结一下,可能的解决方案包括: 1. 使用JDBC批量操作,减少网络开销,虽然不是真正的并行,但能提高效率。 2. 利用数据库存储过程,在数据库内部并行执行多个SQL。 3. 使用异步非阻塞驱动,如R2DBC,在单线程事件循环中处理多个请求,但这可能底层使用了线程池。 4. 检查数据库配置,如连接池设置,允许多个语句通过同一个连接并行执行,但这可能受限于JDBC驱动和数据库的支持。 接下来,我需要验证这些思路的可行性。比如,JDBC的批量操作确实是一次发送多个语句,但执行顺序可能还是串行的。存储过程是否支持并行,这取决于数据库,比如Oracle可能有并行查询选项,但MySQL可能不支持。异步驱动如R2DBC是否符合用户的不使用多线程的要求,因为虽然用户代码是单线程,但驱动内部可能用了线程池,用户可能不希望这样。 另外,用户可能混淆了“并行”和“并发”。在单线程中,可以通过异步IO实现并发,即非阻塞地发送多个请求,然后等待它们的响应。这在像Node.js这样的环境中很常见,但Java中需要相应的库支持,比如使用NIO的Channel和Selector,或者异步JDBC驱动。 例如,使用CompletableFuture结合异步JDBC驱动,可以在单线程中触发多个SQL执行,并等待所有结果返回。虽然底层可能有线程池,但用户代码中没有显式创建线程,这样是否满足用户需求呢?需要看用户的具体限制条件。 另外,Java的NIO库允许单线程管理多个IO操作,但这通常用于网络通信,数据库访问是否可以利用这一点呢?如果JDBC驱动支持非阻塞模式,那么可能实现。但大多数JDBC驱动是阻塞式的,所以这可能不可行。 最后,可能需要明确告诉用户,在严格单线程且不借助任何异步线程的情况下,无法实现真正的并行执行SQL,但可以通过批量操作或数据库特性来优化执行速度,虽然不是并行,但能提升性能。</think>### Java单线程环境下实现多SQL并行执行的方法 在单线程环境下实现多SQL的“并行”执行,本质是通过 **异步非阻塞** 或 **数据库自身特性** 来模拟并行效果。以下是具体方法: --- #### 1. **使用JDBC批量操作** 通过JDBC的批量处理功能,将多个SQL语句打包一次性提交给数据库,减少网络往返和事务开销。虽然数据库可能仍按顺序执行,但整体效率显著提升。 **示例代码**: ```java Connection conn = dataSource.getConnection(); conn.setAutoCommit(false); Statement stmt = conn.createStatement(); stmt.addBatch("INSERT INTO table1 VALUES (...)"); stmt.addBatch("UPDATE table2 SET ..."); stmt.addBatch("DELETE FROM table3 WHERE ..."); int[] results = stmt.executeBatch(); conn.commit(); ``` --- #### 2. **利用数据库存储过程** 在数据库中编写存储过程,通过数据库引擎的并行执行能力(如Oracle的并行查询)实现多SQL并行。例如: ```sql -- Oracle示例 CREATE PROCEDURE parallel_queries AS BEGIN -- 启用并行执行 ALTER SESSION FORCE PARALLEL DML; -- 并行执行多个DML INSERT INTO table1 ...; UPDATE table2 ...; END; ``` 在Java中调用该存储过程: ```java CallableStatement cstmt = conn.prepareCall("{call parallel_queries()}"); cstmt.execute(); ``` --- #### 3. **异步非阻塞驱动(如R2DBC)** 使用响应式编程模型(如Spring R2DBC),在单线程事件循环中异步发送多个SQL请求,通过回调处理结果。**注意**:底层可能使用线程池,但对用户代码透明。 **示例**: ```java DatabaseClient client = DatabaseClient.create(connectionFactory); Flux<Object> flux = Flux.merge( client.sql("SELECT * FROM table1").fetch().all(), client.sql("SELECT * FROM table2").fetch().all() ); flux.subscribe(result -> System.out.println("Received: " + result)); ``` --- #### 4. **数据库连接池优化** 通过配置连接池(如HikariCP)的`maximumPoolSize`,允许多个SQL共享连接资源,结合数据库的并发处理能力提升效率: ```java HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost/db"); config.setMaximumPoolSize(10); // 增加连接数 HikariDataSource ds = new HikariDataSource(config); ``` --- ### 关键区别与选择建议 | 方法 | 是否真正并行 | 依赖多线程 | 适用场景 | |---------------------|--------------------|------------|-----------------------------| | JDBC批量操作 | 否(顺序执行) | 否 | 批量插入/更新 | | 存储过程 | 是(数据库支持时) | 否 | 复杂业务逻辑 | | 异步驱动(R2DBC) | 是(非阻塞IO) | 隐式使用 | 高并发、低延迟 | | 连接池优化 | 否 | 否 | 高频率简单查询 | --- ### 注意事项 1. **数据库支持**:存储过程并行需要数据库引擎支持(如Oracle、PostgreSQL)。 2. **异步驱动限制**:R2DBC目前主要支持非阻塞的查询,事务管理需额外处理。 3. **性能权衡**:单线程“并行”本质是优化执行顺序,无法突破物理并发上限[^3][^5]。 ---
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值