【问题标题】:How can I set XACT_ABORT using JPA/Hibernate?如何使用 JPA/Hibernate 设置 XACT_ABORT?
【发布时间】:2013-03-19 03:48:00
【问题描述】:

我正在使用映射到 MS SQLServer 中的视图的休眠实体。该视图包含从链接服务器上的表中选择的数据。我能够使用 JPQL 成功查询此视图。但是,当我尝试使用 entityManager.merge(myEntity) 更新视图时,出现以下错误:

com.microsoft.sqlserver.jdbc.SQLServerException:无法为链接服务器“DBNAME”的 OLE DB 提供程序“MSDAORA”启动嵌套事务。因为 XACT_ABORT 选项设置为 OFF,所以需要嵌套事务。 在 com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216) 在 com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515) 在 com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:404) 在 com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:350) 在 com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696) 在 com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715) 在 com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:180) 在 com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:155) 在 com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:314)...

我需要将 XACT_ABORT 设置为 ON,以便 SQLServer 在发生错误时可以回滚整个事务。我能够使用本机查询来解决这个问题,但这并不理想。

    String queryString = """set xact_abort on; update table_name set column1 = :column1, column2 = :column2 where id = :id"""
    Query query = entityManager.createNativeQuery(queryString)
    query.setParameter("column1", column1)
    query.setParameter("column2", column2)
    query.setParameter("id", id)
    query.executeUpdate()

有什么方法可以配置 hibernate/JPA/JPAVendorAdaptor 为每个合并/持久执行“设置 xact_abort on”,这样我就不必使用本机查询了吗?

这是我的休眠配置:

@Resource
DataSource dataSource

@Bean
JpaVendorAdapter vendorAdapter(){
    return new HibernateJpaVendorAdapter(database:Database.SQL_SERVER)
}

@Bean
AbstractEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(dataSource:dataSource, jpaVendorAdapter:vendorAdapter())
    em.setPackagesToScan("com.mycompany.entity")
    return em
}

@Bean
PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory:entityManagerFactory().getObject())
}

【问题讨论】:

    标签: sql-server hibernate jpa groovy


    【解决方案1】:

    我最终使用休眠拦截器为每个插入和更新语句附加“set xact_abort on”。

    这是我的拦截器:

    class XactAbortInterceptor extends EmptyInterceptor{
       String onPrepareStatement(String sql) {
          if(sql.startsWith("insert") || sql.startsWith("update"))
             sql = "set xact_abort on; " + sql
          return sql
       }
    }
    

    这里是我注册拦截器的地方:

    @Bean
    AbstractEntityManagerFactoryBean entityManagerFactory(){
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(dataSource:dataSource, jpaVendorAdapter:vendorAdapter())
        em.setPackagesToScan("com.mycompany.entity")
        em.setJpaPropertyMap(["hibernate.ejb.interceptor": XactAbortInterceptor.class.name])
        return em
    }
    

    现在所有对 entityManager.merge(myObject) 或 entityManager.persist(myObject) 的调用都会将 xact_abort 设置为 on。

    希望这可以帮助遇到同样问题的其他人!

    【讨论】:

      【解决方案2】:

      我必须在 persitence.xml 文件中注册拦截器类 XactAbortInterceptor

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-02
        • 1970-01-01
        • 1970-01-01
        • 2011-01-07
        • 2016-07-10
        • 1970-01-01
        • 2013-12-23
        相关资源
        最近更新 更多