3

我正在使用映射到 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。

我需要将 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()

有什么方法可以配置休眠/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())
}
4

2 回答 2

2

我最终使用休眠拦截器为每个插入和更新语句附加“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。

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

于 2013-04-01T15:21:57.513 回答
0

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

于 2016-07-23T21:54:45.483 回答