Hibernate Interceptor - Try-Catch T-SQL

时间:2014-05-13 14:31:41

标签: java sql-server hibernate tsql

我要求在插入中忽略来自SQL Server的主键冲突。虽然有几种方法可以完成这项任务,但其中许多方法具有性能影响或不可行。我需要批量插入表中,并且有可能存在重复。

为了完成这项任务,我编写了一个拦截onPrepareStatement的Hibernate拦截器,并在一个t-SQL TRY CATCH结构中包装了Hibernate生成的SQL。 TRY CATCH查找主键违规并使其静音。下面是我的拦截器代码。

private static final String FORMAT_TRY_CATCH = "BEGIN TRY %s END TRY\r\n" + "BEGIN CATCH\r\n" + "\r\n"
    + "DECLARE @ErrorMessage NVARCHAR(4000),\r\n" + "  @ErrorNumber INT,\r\n" + "  @ErrorSeverity INT,\r\n" + "  @ErrorState INT,\r\n"
    + "  @ErrorLine INT,\r\n" + "  @ErrorProcedure NVARCHAR(200) ;\r\n" + "\r\n"
    + "SELECT  @ErrorNumber = ERROR_NUMBER(), @ErrorSeverity = ERROR_SEVERITY(),\r\n"
    + "        @ErrorState = ERROR_STATE(), @ErrorLine = ERROR_LINE(),\r\n"
    + "        @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-') ;\r\n" + "\r\n"
    + "SELECT  @ErrorMessage = N'Error %%d, Level %%d, State %%d, Procedure %%s, Line %%d, ' +\r\n"
    + "        'Message: ' + ERROR_MESSAGE() ;\r\n" + "     IF @ErrorNumber <> 2627\r\n" + "        BEGIN\r\n"
    + "RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, -- parameter: original error number.\r\n"
    + "  @ErrorSeverity, -- parameter: original error severity.\r\n" + "  @ErrorState, -- parameter: original error state.\r\n"
    + "  @ErrorProcedure, -- parameter: original error procedure name.\r\n"
    + "  @ErrorLine-- parameter: original error line number.\r\n" + "        ) ;\r\n" + "       END\r\n" + "END CATCH;";

@Override
public String onPrepareStatement(String sql) {
    if (sql.toLowerCase().startsWith("insert")) {
        return String.format(FORMAT_TRY_CATCH, sql);
    }
    return sql;
}

拦截器的工作原理除外,当存在主键约束违规时,该语句返回0个受影响的行。如果受影响的行数与预期的行数不匹配,Hibernate会有一个抛出异常的检查。我可以通过执行返回一个受影响的行的虚拟t-SQL语句来解决此问题。

DECLARE @dummy TABLE (col1 int)
INSERT INTO @dummy values (1)

当存在主键约束违规时,此伪逻辑将降低性能。是否有更好的虚拟脚本,或更好的方法来捕获主键约束违规?

注意:出于性能原因,在每次插入之前执行选择是不可接受的。我无法重新创建SQL的主键以打开IGNORE_DUP_KEY。

0 个答案:

没有答案