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

SQL Server开启NOCOUNT ON时Spring Data JPA操作报错的解决方案咨询

解决方案

问题根源在于SQL Server全局开启NOCOUNT ON后,会抑制SQL语句执行时返回受影响行数的信息,而Hibernate依赖这个行数确认写操作成功状态及乐观锁校验,因此触发Unexpected row count: -1和StaleObjectStateException错误。你之前的自定义Dialect仅处理了序列查询场景,未覆盖所有需要返回行数的操作,所以无效。以下是三种无需关闭全局NOCOUNT或使用原生查询的解决方法:

方案1:完善自定义Dialect,覆盖全量写操作SQL生成

修改CustomSQLServerDialect,覆盖插入、更新、删除、自增主键查询等方法,在生成的SQL前添加SET NOCOUNT OFF;:

package com.ata2.art22;

import org.hibernate.dialect.SQLServer2012Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes;

public class CustomSQLServerDialect extends SQLServer2012Dialect {
    
    public CustomSQLServerDialect() {
        super();
        registerFunction("concat", new StandardSQLFunction("concat", StandardBasicTypes.STRING));
    }

    @Override
    public String getIdentityInsertString() {
        return "SET NOCOUNT OFF;\n" + super.getIdentityInsertString();
    }

    @Override
    public String getIdentitySelectString(String table, String column, int type) {
        return "SET NOCOUNT OFF;\n" + super.getIdentitySelectString(table, column, type);
    }

    @Override
    public String getUpdateString() {
        return "SET NOCOUNT OFF;\n" + super.getUpdateString();
    }

    @Override
    public String getDeleteString() {
        return "SET NOCOUNT OFF;\n" + super.getDeleteString();
    }

    @Override
    public String getSequenceNextValString(String sequenceName) {
        return "SET NOCOUNT OFF;\n" + super.getSequenceNextValString(sequenceName);
    }
}

此方法让Hibernate在生成所有需要返回行数的SQL时自动添加SET NOCOUNT OFF,确保能获取正确的受影响行数。

方案2:使用SessionEventListener初始化会话时关闭NOCOUNT

创建会话监听器,在每个Hibernate会话打开时执行SET NOCOUNT OFF:

package com.ata2.art22;

import org.hibernate.Session;
import org.hibernate.event.spi.SessionEvent;
import org.hibernate.event.spi.SessionEventListener;
import java.sql.Statement;

public class NocountOffSessionListener implements SessionEventListener {
    @Override
    public void sessionOpened(SessionEvent event) {
        Session session = event.getSession();
        session.doWork(connection -> {
            try (Statement stmt = connection.createStatement()) {
                stmt.execute("SET NOCOUNT OFF");
            }
        });
    }
}

在Spring配置文件中添加监听器配置:

spring.jpa.properties.hibernate.session_event_listener=com.ata2.art22.NocountOffSessionListener

会话启动后,所有操作都会在NOCOUNT OFF环境下执行,无需修改单条SQL。

方案3:自定义ConnectionProvider,获取连接时关闭NOCOUNT

实现自定义连接提供者,每次获取数据库连接时执行SET NOCOUNT OFF:

package com.ata2.art22;

import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
import org.springframework.beans.factory.annotation.Autowired;

public class CustomConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
    private DataSource dataSource;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    protected DataSource selectAnyDataSource() {
        return dataSource;
    }

    @Override
    protected DataSource selectDataSource(String tenantIdentifier) {
        return dataSource;
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException {
        Connection connection = super.getConnection(tenantIdentifier);
        try (Statement stmt = connection.createStatement()) {
            stmt.execute("SET NOCOUNT OFF");
        }
        return connection;
    }

    @Override
    public Connection getConnection() throws SQLException {
        Connection connection = super.getConnection();
        try (Statement stmt = connection.createStatement()) {
            stmt.execute("SET NOCOUNT OFF");
        }
        return connection;
    }
}

在配置文件中指定自定义连接提供者:

spring.jpa.properties.hibernate.connection.provider_class=com.ata2.art22.CustomConnectionProvider

此方法确保所有Hibernate获取的连接默认关闭NOCOUNT,对全量操作生效。

内容的提问来源于stack exchange,提问作者infD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:00:14