JdbcTemplate 批量插入,HikariCP数据库连接池

JdbcTemplate 批量插入

在使用Spring框架的JdbcTemplate进行数据库操作时,批量插入是一种常见的需求,尤其是在需要高效地插入大量数据时。JdbcTemplate提供了多种方法来支持批量插入,下面我将介绍几种常用的实现方式:

1. 使用batchUpdate方法

batchUpdateJdbcTemplate提供的一个用于执行批量更新操作的方法,它也可以用于批量插入。这种方法适用于插入结构相同的多条数据。

import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

public void batchInsert(List<MyObject> objects) {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

    String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)";

    jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
            MyObject object = objects.get(i);
            ps.setString(1, object.getColumn1());
            ps.setString(2, object.getColumn2());
        }

        @Override
        public int getBatchSize() {
            return objects.size();
        }
    });
}

2. 使用NamedParameterJdbcTemplate进行批量插入

当你的插入语句中有很多参数,并且希望通过名称而不是索引来指定它们时,可以使用NamedParameterJdbcTemplate。这样可以使代码更加清晰易读。

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;

public void batchInsertUsingNamedParameterJdbcTemplate(List<MyObject> objects) {
    NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);

    String sql = "INSERT INTO my_table (column1, column2) VALUES (:column1, :column2)";

    SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(objects.toArray());
    namedParameterJdbcTemplate.batchUpdate(sql, batch);
}

3. 使用SimpleJdbcInsert进行批量插入

SimpleJdbcInsert是一个简化插入操作的工具类,它可以自动处理表名和列名的映射。对于批量插入,可以与SqlParameterSourceUtils一起使用来简化操作。

import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;

public void batchInsertUsingSimpleJdbcInsert(List<MyObject> objects) {
    SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(dataSource)
            .withTableName("my_table")
            .usingColumns("column1", "column2");

    SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(objects.toArray());
    simpleJdbcInsert.executeBatch(batch);
}

注意事项

1. 数据库连接池配置

假设你正在使用HikariCP作为数据库连接池,为了支持大量的并发插入操作,你需要合理配置数据库连接池的参数,比如maximumPoolSize(最大池大小)、idleTimeout(空闲超时时间)等。

在Spring框架中,配置Datasource是连接数据库的基础。Spring提供了多种方式来配置Datasource,包括在XML文件中配置、使用Java配置类,以及利用SpringBoot的自动配置功能。这里,我将介绍如何通过SpringBoot的application.properties文件以及使用Java配置类来配置Datasource。

使用SpringBoot的application.properties

当你使用SpringBoot时,配置Datasource非常简单。SpringBoot的自动配置功能能够根据classpath中的库和application.properties文件中的配置自动设置Datasource。以下是一个MySQL
数据库的配置示例:

# 数据库基本配置
spring.datasource.url=jdbc:mysql://localhost:3306/yourDatabase?useSSL=false&serverTimezone=UTC
spring.datasource.username=user
spring.datasource.password=password

# 指定HikariCP作为连接池 (Spring Boot 2.x 默认使用 HikariCP)
spring.datasource.type=com.zaxxer.hikari.HikariDataSource

# HikariCP 连接池配置
spring.datasource.hikari.maximum-pool-size=20 # 默认值: 10
spring.datasource.hikari.minimum-idle=10 # 默认值: 和maximumPoolSize相同
spring.datasource.hikari.idle-timeout=300000 # 默认值: 600000(10分钟)
spring.datasource.hikari.connection-timeout=30000 # 默认值: 30000(30秒)
spring.datasource.hikari.max-lifetime=1800000 # 默认值: 1800000(30分钟),0表示无限寿命
spring.datasource.hikari.pool-name=HikariCP # 默认是自动生成的
spring.datasource.hikari.auto-commit=true # 默认值: true

# 数据库驱动类(根据实际数据库类型更改)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 连接测试查询 (Hikari会自动检测是否需要这个查询,对于某些数据库不是必须的)
# 如果数据库驱动支持JDBC4的Connection.isValid()方法,HikariCP会使用它来验证,而不需要指定这个
# HikariCP优先使用Connection.isValid()方法来检测连接的有效性
# MySQL JDBC驱动(Connector/J 5.1及以上版本)支持JDBC 4规范
# 此项可以帮助提升应用的稳定性和用户体验
spring.datasource.hikari.connection-test-query=SELECT 1

在这个例子中,maximum-pool-size被设置为20,意味着连接池最多可以同时管理20个数据库连接。这样可以在高负载时提供足够的数据库连接,但也需要确保数据库服务器能够处理这么多并发连接。

注意事项

当配置idleTimeout时,需要考虑到maxLiffetime的设置。maxLifetime是一个连接最长生命周期的设置,HikaricP推荐maxLifetime的值应该比idleTimeout精微短一些。这是为了确保连接在被服务器端强制关闭之前,连接池就已经将其回收。
设置过短的idleTimeout可能会导致频繁地创建和销毁数据库连接,这可能会对性能产生负面影响。

在调整这些参数时,建议进行适当的测试,以确保配置的修改能够带来预期的效果,并且不会对应用用性能产生不利影响。
总的来说,是否需要手动配置idleTimeout取决于你对应用性能和资源利用的具体需求。大多数情况下,默认值已经足够好,只有在特定场景下才需要调整。

使用Java配置类
如果你希望通过Java代码来配置Datasource,可以创建一个配置类,并使用@Bean注解来定义Datasource bean。这种方式提供了更高的灵活性,允许你在创建DataSource时执行复杂的逻
辑。
以下是使用HikariCP作为连接池的一个配置示例:

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.url}")
    private String dbUrl

    @Value("${spring.datasource.username}")
    private String dbUsername;

    @Value("${spring.datasource.password}")
    private String dbPassword;

    @Value("${spring.datasource.driver-class-name}")
    private String dbDriverClassName;

    @Bean
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(dbUrl);
        dataSource.setUsername(dbUsername);
        dataSource.setPassword(dbPassword);
        dataSource.setDriverClassName(dbDriverClassName);
        
        //可以根据需要设置其他Hikaricp特有的配置
        return dataSource;
    }
}

在这个配置类中,我们使用@value注解来注入application·properties中定义的配置值,然后创建了一个HikariDatasourrce实例并返回。这个Datasource bean随后可以被Spriing容器管理,供应用中需要进行数据库操作的组件使用
结论
以上就是在SpringBoot项目中配置Datasource的几种常见方法。选择哪种方法取决于你的具体需求和偏好。无论哪种方式,SpringBoot都能够简化数据库连接和操作的过程,让你能够专注于业务逻辑的实现。

2. 分批次插入

考虑到内存限制和数据库压力,当需要插入的数据量非常大时,应该将数据分批次进行插入。例如,如果你有10万条数据需要插入,可以每1000条数据作为一个批次,逐批插入。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

@Service
public class MyService {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public MyService(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Transactional
    public void batchInsertInChunks(List<MyObject> allObjects, int chunkSize) {
        String sql = "INSERT INTO my_table (column1, column2) VALUES (?, ?)";

        for (int i = 0; i < allObjects.size(); i += chunkSize) {
            final List<MyObject> chunk = allObjects.subList(i, Math.min(allObjects.size(), i + chunkSize));

            jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
                @Override
                public void setValues(PreparedStatement ps, int j) throws SQLException {
                    MyObject object = chunk.get(j);
                    ps.setString(1, object.getColumn1());
                    ps.setString(2, object.getColumn2());
                }

                @Override
                public int getBatchSize() {
                    return chunk.size();
                }
            });
        }
    }
}
@RestController
public class MyController {

    private final MyService myService;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
    }

    @PostMapping("/batchInsert")
    public ResponseEntity<?> batchInsert(@RequestBody List<MyObject> allObjects) {
        // 假设chunkSize为1000,这个值可以根据您的实际需要调整
        int chunkSize = 1000;
        myService.batchInsertInChunks(allObjects, chunkSize);
        return ResponseEntity.ok().build();
    }
}

3. 调整批量大小以获得最佳性能

不同数据库对批量操作的最优批量大小(batch size)可能有所不同。过大的批量大小可能导致内存溢出或者长时间的事务锁定,而过小的批量大小则可能导致频繁的数据库交互,影响性能。

实际应用中,你可能需要根据数据库的响应时间、CPU和内存使用率等指标,通过测试来确定一个最佳的批量大小。例如,你可以从1000开始测试,逐步调整,观察性能变化,找到一个最适合你的应用场景的批量大小。

结论

通过上述例子,我们可以看到,在使用JdbcTemplate进行批量插入时,合理配置数据库连接池、分批次插入以及调整批量大小都是非常重要的。这些措施能够帮助我们有效管理资源,提高应用性能,避免潜在的问题。在实际开发中,应该根据具体情况灵活应用这些技巧。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值