You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程Java应用调用Hibernate保存数据时线程阻塞问题排查

多线程调用DAO保存数据时第二个线程停滞问题排查与解决

问题描述

我正在开发一个个人项目,采用多线程调用DAO的save方法进行数据保存。第一个线程执行该方法一切正常,但第二个线程在执行save方法的增强for循环时出现停滞,无法继续执行。不确定需要修改Java代码、Hibernate配置,还是调整MariaDB的设置(注:每次保存的registers列表包含约100条数据,不清楚数据量是否与此问题相关)。

DAO中的save方法

public synchronized void save(List<Registers> registers) throws Exception {
    Session session = null;
    Transaction transaction = null;

    try {
        session = HibernateUtil.getSessionFactory(this.url).openSession();
        transaction = session.beginTransaction();

        for (final Registers register : registers) {
            session.save(register);
        }           

        transaction.commit();
    } catch (final Exception e) {
        if (transaction != null) {
            transaction.rollback();
        }
        throw e;
    } finally {
        if (session != null && session.isOpen()) {
            session.close();
        }
    }
}

Registers实体类

@SuppressWarnings("serial")
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Entity
@Table(name = "TAB_REGISTERS")
public class Registers implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "COD_REG")
    private Long cod;

    // 其余映射变量的@Column注解及构造方法
}

Hibernate配置文件hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="javax.persistence.jdbc.driver">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">false</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.order_updates">true</property>
        <property name="hibernate.enable_lazy_load_no_trans">true</property>
        <property name="hibernate.c3p0.min_size">1</property>
        <property name="hibernate.c3p0.max_size">2</property>
        <property name="hibernate.c3p0.timeout">100</property>
        <property name="hibernate.c3p0.max_statements">1000</property>
        <property name="hibernate.c3p0.idle_test_period">100</property>
    </session-factory>
</hibernate-configuration>

DAO调用代码

public void saveNewRegisters(List<Registers> registers){
    try {
        this.dao.save(registers);
    } catch (final Exception e) {
        logger.error("save()", e);
    }
}

问题排查与解决建议

1. 连接池配置优化

当前c3p0连接池max_size=2的设置仅允许同时存在2个数据库连接,在多线程场景下极易出现连接等待。建议调整参数扩大连接池:

<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.timeout">300</property> <!-- 延长超时时间,避免短时间内连接被回收 -->

2. 移除不必要的synchronized关键字

当前save方法添加的synchronized会强制多线程串行执行,但方法内部每次都会新建独立的Session,无需通过方法同步保证线程安全。移除该关键字后,多线程可并行执行,配合连接池优化提升效率。

3. 优化批量插入逻辑

循环调用session.save()会产生大量单条插入语句,不仅效率低下,还可能引发数据库锁竞争。建议改用批量插入方式:

  • 在Hibernate配置中添加批量插入相关参数:
    <property name="hibernate.jdbc.batch_size">50</property> <!-- 每50条数据批量提交 -->
    <property name="hibernate.order_inserts">true</property> <!-- 按表排序插入,减少锁竞争 -->
    
  • 修改save方法中的插入逻辑:
    // 替换原循环save逻辑
    for (int i = 0; i < registers.size(); i++) {
        session.save(registers.get(i));
        if (i % 50 == 0) { // 每50条刷新一次session,避免内存溢出
            session.flush();
            session.clear();
        }
    }
    

4. 检查SessionFactory的单例实现

确保HibernateUtil.getSessionFactory(this.url)是单例模式,避免每次调用都新建SessionFactory导致连接池资源分散。如果每个SessionFactory实例占用独立连接池,极易出现连接耗尽的情况。

5. 数据库锁排查

使用MariaDB命令查看当前进程状态,确认是否存在锁等待:

SHOW PROCESSLIST;

若发现第二个线程对应的SQL处于锁等待状态,需排查是否有其他事务长时间占用表锁,或调整数据库的锁超时参数。

6. 更换适配MariaDB的驱动与方言

当前配置使用MySQL的驱动和方言,建议替换为MariaDB专用版本提升兼容性:

<property name="javax.persistence.jdbc.driver">org.mariadb.jdbc.Driver</property>
<property name="hibernate.connection.driver_class">org.mariadb.jdbc.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.MariaDBDialect</property>

内容的提问来源于stack exchange,提问作者Luiz Fernando da Silva Santos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 19:11:01