0

0

深入理解Hibernate 3.6 Criteria API根别名行为及限制

碧海醫心

碧海醫心

发布时间:2025-10-10 12:27:24

|

836人浏览过

|

来源于php中文网

原创

深入理解Hibernate 3.6 Criteria API根别名行为及限制

本文深入探讨了Hibernate 3.6版本中,使用Criteria API尝试为根实体设置自定义表别名时,为何默认的this_别名仍会生效的问题。通过分析Hibernate内部的CriteriaQueryTranslator机制,揭示了自定义别名被内部逻辑覆盖的根本原因,并提供了在面对此限制时的应对策略和建议。

Hibernate Criteria API根别名问题描述

在使用hibernate criteria api进行查询时,开发者通常可以通过getsession().createcriteria(entityclass.class, "alias")来为查询的根实体指定一个表别名。然而,在hibernate 3.6.10.final版本中,即使显式设置了别名,生成的sql语句中的根实体别名仍然是默认的this_,而非用户期望的自定义别名。

例如,当尝试将Vehicle实体的根别名设置为temp时:

Criteria cr = getSession().createCriteria(Vehicle.class, "temp");
// ... 其他Criteria配置

期望生成的SQL可能是:

select temp.vehicle_id as y0_, temp.vin as y1_, temp.initial_registration as y2_ from vehicle temp where temp.vin=?

但实际生成的SQL却是:

select this_.vehicle_id as y0_, this_.vin as y1_, this_.initial_registration as y2_ from vehicle this_ where this_.vin=?

这表明用户设置的"temp"别名并未生效。

示例代码

以下是一个简化的Hibernate Criteria查询示例,用于说明上述问题:

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.hibernate.criterion.ProjectionList;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

// 假设这是一个通用的DAO方法
public abstract class BaseDao {

    protected Session getSession() {
        // 实际应用中应从SessionFactory获取当前Session
        throw new UnsupportedOperationException("Method not implemented: getSession()");
    }

    protected void begin() {
        // 事务开始
    }

    protected void commit() {
        // 事务提交
    }

    public List findByProjectionCriteria() {
        // 尝试设置根别名为 "temp"
        Criteria cr = getSession().createCriteria(Vehicle.class, "temp");
        cr.setResultTransformer(Transformers.aliasToBean(Vehicle.class));

        ProjectionList projectionList = Projections.projectionList();
        projectionList.add(Projections.property("vehicleId"), "vehicleId");
        projectionList.add(Projections.property("vin"), "vin");
        projectionList.add(Projections.property("initialRegistration"), "initialRegistration");
        cr.setProjection(projectionList);

        cr.add(Restrictions.eq("vin", "WVW29343249702776"));

        begin();

        List list = null;
        try {
            list = cr.list();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (list == null)
            list = new ArrayList<>();

        commit();
        return list;
    }
}

// 实体定义
@Entity
@Table(name = "vehicle")
public class Vehicle {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "vehicle_id", unique = true, nullable = false)
    private int vehicleId;

    @Column(nullable = false, length = 17)
    private String vin;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "initial_registration")
    private Date initialRegistration;

    // Getter和Setter方法 (为简洁省略,但实际应存在)
    public int getVehicleId() { return vehicleId; }
    public void setVehicleId(int vehicleId) { this.vehicleId = vehicleId; }
    public String getVin() { return vin; }
    public void setVin(String vin) { this.vin = vin; }
    public Date getInitialRegistration() { return initialRegistration; }
    public void setInitialRegistration(Date initialRegistration) { this.initialRegistration = initialRegistration; }
}

Hibernate内部机制解析:根别名被覆盖的原因

要理解为何自定义根别名无效,需要深入探究Hibernate 3.6内部处理Criteria查询的机制。问题根源在于CriteriaQueryTranslator类的构造函数及其调用的createCriteriaSQLAliasMap()方法。

当执行cr.list()方法时,Hibernate会创建一个CriteriaLoader对象,该对象进而会实例化CriteriaQueryTranslator。在CriteriaQueryTranslator的构造过程中,createCriteriaSQLAliasMap()方法负责设置SQL别名。其核心逻辑如下(简化自Hibernate 3.6源码):

private void createCriteriaSQLAliasMap() {
    int i = 0;
    // 遍历所有Criteria实例(包括根Criteria和关联Criteria)
    Iterator criteriaIterator = criteriaEntityNames.entrySet().iterator();
    while ( criteriaIterator.hasNext() ) {
        Map.Entry me = ( Map.Entry ) criteriaIterator.next();
        Criteria crit = ( Criteria ) me.getKey(); // 当前Criteria实例
        String alias = crit.getAlias(); // 获取用户为当前Criteria设置的别名
        if ( alias == null ) {
            alias = ( String ) me.getValue(); // 如果没有显式别名,则使用实体名
        }
        // 为当前Criteria生成一个SQL别名并放入map
        criteriaSQLAliasMap.put( crit, StringHelper.generateAlias( alias, i++ ) );
    }
    // 关键步骤:在循环结束后,再次为根Criteria设置SQL别名
    // rootSQLAlias 通常默认为 "this_"
    criteriaSQLAliasMap.put( rootCriteria, rootSQLAlias );
}

从上述代码可以看出,createCriteriaSQLAliasMap()方法首先会遍历所有Criteria实例(包括根Criteria),并尝试根据crit.getAlias()或实体名生成一个SQL别名,将其存入criteriaSQLAliasMap。这意味着,即使我们通过createCriteria(Vehicle.class, "temp")设置了"temp",它可能在这个循环中被处理。

然而,关键在于循环结束后的一行:criteriaSQLAliasMap.put( rootCriteria, rootSQLAlias );。这一行会强制将rootCriteria的SQL别名设置为rootSQLAlias。在Hibernate 3.6中,rootSQLAlias的默认值通常就是"this_"。由于rootCriteria作为Map的键是唯一的,这个操作会覆盖之前在循环中可能为根Criteria设置的任何自定义别名。

因此,无论开发者在createCriteria()方法中为根实体指定了什么别名,最终都会被Hibernate内部的默认rootSQLAlias(即this_)所覆盖。

Rationale
Rationale

Rationale 是一款可帮助企业主、经理和个人做出艰难的决定的AI工具

下载

解决方案与建议

鉴于Hibernate 3.6的这一内部行为,直接通过Criteria API改变根实体的默认this_别名是不可行的。在面对此限制时,可以考虑以下策略:

  1. 接受默认别名: 对于大多数简单的查询,this_作为根实体的别名并不会影响查询的正确性或可读性。如果对别名没有强烈的自定义需求,接受默认行为是最直接的方式。

  2. 升级Hibernate版本: 较新的Hibernate版本可能已经改进了Criteria API对根别名的处理逻辑。如果项目条件允许,升级Hibernate是一个长期的解决方案,可能会解决此类内部行为问题并带来其他性能和功能上的改进。

  3. 使用HQL或JPQL: 如果对SQL别名有严格的控制要求,或者需要更复杂的查询逻辑,可以考虑使用Hibernate Query Language (HQL) 或 Java Persistence Query Language (JPQL)。HQL/JPQL提供了更灵活的语法来定义查询,包括自定义别名:

    // HQL示例
    String hql = "select v.vehicleId as vehicleId, v.vin as vin, v.initialRegistration as initialRegistration " +
                 "from Vehicle v where v.vin = :vin";
    List vehicles = getSession().createQuery(hql, Vehicle.class)
                                         .setParameter("vin", "WVW29343249702776")
                                         .list();

    在HQL中,您可以自由选择任何合法的标识符作为实体别名。

  4. 使用原生SQL: 对于极度复杂的查询或需要数据库特定功能的场景,原生SQL是最终的解决方案。原生SQL提供了对SQL语句的完全控制,包括所有别名的定义。

    // 原生SQL示例
    String sql = "select temp.vehicle_id as vehicleId, temp.vin as vin, temp.initial_registration as initialRegistration " +
                 "from vehicle temp where temp.vin = :vin";
    List results = getSession().createNativeQuery(sql)
                                         .setParameter("vin", "WVW29343249702776")
                                         .list();
    // 需要手动将Object[]映射到Vehicle对象

总结

Hibernate 3.6 Criteria API在处理根实体别名时存在一个内部限制,即用户通过createCriteria(Class, alias)设置的自定义别名会被CriteriaQueryTranslator强制覆盖为默认的this_。这是由于Hibernate内部在构建SQL别名映射时,会最后一步将根Criteria的别名设置为rootSQLAlias。

理解这一机制有助于开发者在遇到类似问题时,明确其行为而非误认为是API使用不当。对于需要严格控制SQL别名的场景,建议转向使用HQL、JPQL或原生SQL,或者考虑升级到更现代的Hibernate版本以获取潜在的改进和更灵活的功能。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

799

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

722

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

727

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

394

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

445

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

428

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16860

2023.08.03

JavaScript 性能优化与前端调优
JavaScript 性能优化与前端调优

本专题系统讲解 JavaScript 性能优化的核心技术,涵盖页面加载优化、异步编程、内存管理、事件代理、代码分割、懒加载、浏览器缓存机制等。通过多个实际项目示例,帮助开发者掌握 如何通过前端调优提升网站性能,减少加载时间,提高用户体验与页面响应速度。

3

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.1万人学习

C# 教程
C# 教程

共94课时 | 5.6万人学习

Java 教程
Java 教程

共578课时 | 39.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号