我正在将 Spring Boot 应用程序 (spring-boot-starter-parent) 从 2.6.1 升级到 3.4.1。 该升级的一部分与 hibernate 5 到 6 的升级有关,特别是 hibernate core 6.6.4.Final 与 postgresql 的升级。在这种情况下,在一个测试用例中会出现以下异常,从而阻止升级。
...
org.hibernate.loader.NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [id_number] during auto-discovery of a native-sql query
at org.hibernate.query.results.ResultSetMappingImpl.resolve(ResultSetMappingImpl.java:289)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.resolveJdbcValuesSource(JdbcSelectExecutorStandardImpl.java:340)
at
...
此异常与此本机 HQL 查询相关,即以下查询:
...
@Override
public List<ParentNodeChieldTreeDTOInterface> findAllSubNodesRecursively(NodeInterface node) {
try {
Session session = getSessionFactory().openSession();
session.beginTransaction();
String sql_query =
" WITH RECURSIVE tree AS "
+ "("
+ " SELECT id, id_number, node_type_id, cast (array[] as BIGINT[]) AS ancestors"
+ " FROM node"
+ " UNION ALL"
+ " SELECT node.id, node.id_number, node.node_type_id, tree.ancestors || node.parent_id_number"
+ " FROM node, tree"
+ " WHERE node.parent_id_number = tree.id_number"
+ ") "
+ "SELECT DISTINCT ON (id_number) tree.id_number, * FROM tree WHERE (:Argument1 = ANY(tree.ancestors) )"
+ " ORDER BY tree.id_number"
;
@SuppressWarnings("unchecked")
Query<Object[]> query = session.createNativeQuery(sql_query)
.addScalar("id", byte[].class)
.addScalar("id_number", Long.class)
.addScalar("node_type_id", Integer.class)
.addScalar("ancestors", LongArrayType.INSTANCE)
;
Long nodeIdHex = node.getIdNumber();
query.setParameter("Argument1", nodeIdHex, Long.class);
List<Object[]> objectCollection = (List<Object[]>) query.list();
List<ParentNodeChieldTreeDTOInterface> parentNodeChieldTreeDTOList = new ArrayList<ParentNodeChieldTreeDTOInterface>();
if (objectCollection.iterator().hasNext()) {
for (Object[] objects : objectCollection) {
byte[] nodeUUIDArray = (byte[]) objects[0];
long nodeIdNumber = (long) objects[1];
int nodeTypeIdNumber = (int) objects[2];
Object parentNodes = objects[3];
long[] parents = (long[]) parentNodes;
ParentNodeChieldTreeDTOInterface dtoObject = new ParentNodeChieldTreeDTO(
nodeUUIDArray,
nodeIdNumber,
nodeTypeIdNumber,
parents
);
if(logger.isDebugEnabled()) {
ByteBuffer buffer = ByteBuffer.wrap(nodeUUIDArray);
UUID nodeUUID = ByteBufferOperations.byteBufferToUUID(buffer);
logger.debug("Cheild Node UUID : " + nodeUUID.toString() );
logger.debug("Parent Nodes : " + parents);
logger.debug("Cheild Node : " + nodeUUIDArray);
}
parentNodeChieldTreeDTOList.add(dtoObject);
}
}
session.getTransaction().commit();
session.close();
return parentNodeChieldTreeDTOList;
} catch (Exception e) {
logger.error("Exception", e);
throw e;
}
}
...
我必须提到,完全相同的本机 SQL 查询代码在 spring-boot-starter-parent 2.6.1 即 hibernate 5 中没有抛出异常。
现在异常表明sql别名[id_number]是重复的,从逻辑角度来看确实是这样,因为这里我们正在执行递归操作或者正确地说是对同一个表进行迭代操作。即,实际上以下列“node.id_number”和“id_number”基本上是 select 语句中的同一列,它们基本上是同一件事。但这就是递归查询的重点。 即,这是表的各个部分在 postgres 中的样子
...
# \d node;
Table "public.node"
Column | Type | Collation | Nullable | Default
------------------+--------------------------+-----------+----------+-----------------------------------------
...
node_type_id | integer | | not null |
id_number | bigint | | not null | nextval('node_id_number_seq'::regclass)
parent_id_number | bigint | | |
id | bytea | | not null |
parent_id | bytea | | |
...
那么在 Hibernate 6 中如何处理此类问题。即虽然“node.id_number”和“id_number”是同一个表/事物,但我的理解是在这种情况下别名确实不同。如何在 Hibernate 6 中实现此功能。 经过一段时间的搜索后,我在 SO 上发现了一个类似的问题,但那个问题不涉及同一张表上的递归。
有用的资源: