《Hibernate快速开始》Query /HQL and JPQL (上)
Hibernate查询语言(HQL)和Java持久性查询语言(JPQL)都是与SQL类似的面向对象模型的查询语言。JPQL是受HQL影响很大的子集。所有的JPQL查询都是有效的HQL查询,但反过来并不正确。
HQL和JPQL都是非类型安全的方式来执行查询操作。Criteria 查询提供了一种查询类型安全的方法。有关更多信息,请参阅标准。
查询API
domain 模型示例
为了更好地理解更多的HQL和JPQL示例,现在是时候熟悉本章中所有示例功能中使用的domain模型实体。
@NamedQueries({//将多个命名查询附加到相同的实体类需要将它们包装在@NamedQueries注释中
@NamedQuery(定义了一个名称为“get_person_by_name”的查询
name = "get_person_by_name",
//查询语句
query = "select p from Person p where name = :name"
)
,
@NamedQuery(
name = "get_read_only_person_by_name",
query = "select p from Person p where name = :name",
hints = {
@QueryHint(//@QueryHint 批注指定供应商特定的 JPA 查询扩展,提高查询性能,利用Hibernate的 JPA 持续性提供程序实现中的特定特性
name = "org.hibernate.readOnly",
value = "true"
)
}
)
})
@NamedStoredProcedureQueries(//使用@NamedStoredProcedureQueries注解来调用存储过程
@NamedStoredProcedureQuery(//使用@NamedStoredProcedureQuery注解并绑定到一个JPA表
name = "sp_person_phones",//JPA中的存储过程的名字
procedureName = "sp_person_phones",//存储过程的名字
parameters = {
@StoredProcedureParameter(//使用注解@StoredProcedureParameter来定义存储过程使用的IN/OUT参数
name = "personId",
type = Long.class,
mode = ParameterMode.IN
),
@StoredProcedureParameter(
name = "personPhones",
type = Class.class,
mode = ParameterMode.REF_CURSOR
)
}
)
)
@Entity//@Entity注解定义一个实体
public class Person {
@Id//@Id声明此字段为主键@GeneratedValue//为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键),@GeneratedValue提供了主键的生成策略
private String name;private String nickName;private String address;@Temporal(TemporalType.TIMESTAMP )//@Temporal注解Date格式的字段,获得”HH:MM:SS”日期格式[引申]TemporalType.TIME也会得到形如’HH:MM:SS’ 格式的日期,TemporalType.DATE 会得到形如’yyyy-MM-dd’ 格式的日期
private Date createdOn;@OneToMany(mappedBy = “person”, cascade = CascadeType.ALL)//@OneToMany用来配置一对多关联映射 在JPA中,在@OneToMany里加入mappedBy属性可以避免生成一张中间表。cascade:设置级联操作类型,CascadeType.ALL包含所有持久化方法
@OrderColumn(name = “order_id”)//@OrderColumn注解根据指定的列进行排序
private List phones = new ArrayList<>();
@ElementCollection//JPA通过@ElementCollection注解集合映射,可以自动检测元素类型
@MapKeyEnumerated(EnumType.STRING)//指定基本类型为枚举类型的映射键的枚举类型,MapKeyEnumerated注释可以应用于一个元素集合或类型的关系
private Map<AddressType, String> addresses = new HashMap<>();
@Version//JPA通过在实体类中使用@Version注解来发现数据库记录的并发操作,如果数据被修改,JPA会将这个字段自增,如果还有别的实体也在操作,它会抛出一个尝试提交的事务异常
private int version;
//Getters and setters are omitted for brevity
}
public enum AddressType {
HOME,
OFFICE
}
@Entity
public class Partner {
@Id
@GeneratedValue
private Long id;
private String name;
@Version
private int version;
//Getters and setters are omitted for brevity
}
@Entity
public class Phone {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)//@ManyToOne用来配置多对一关联映射,表示在多的那一方通过延迟加载的方式加载对象(默认是非延迟加载)
private Person person;
@Column(name = “phone_number”)//@Column注解来标识实体类中属性与数据表中字段的对应关系
private String number;
@Enumerated(EnumType.STRING)
@Column(name = “phone_type”)
private PhoneType type;
@OneToMany(mappedBy = “phone”, cascade = CascadeType.ALL, orphanRemoval = true)// orphanRemoval 设置级联删除 , true代表自动删除
private List calls = new ArrayList<>( );
@OneToMany(mappedBy = “phone”)
@MapKey(name = “timestamp”)//@MapKey指定了映射,持久化timestamp或者timestamp的值
@MapKeyTemporal(TemporalType.TIMESTAMP )//@MapKeyTemporal应用于java.util.map类型的元素集合或关系
private Map<Date, Call> callHistory = new HashMap<>();
@ElementCollection
private List repairTimestamps = new ArrayList<>( );
//Getters and setters are omitted for brevity
}
public enum PhoneType {
LAND_LINE,
MOBILE;
}
@Entity
@Table(name = “phone_call”)@Table用于指明数据库的表名,若不指定则以实体类名称作为表名
public class Call {
@Id
@GeneratedValue
private Long id;
@ManyToOne
private Phone phone;
@Column(name = “call_timestamp”)
private Date timestamp;
private int duration;
//Getters and setters are omitted for brevity
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)//@Inheritance定义继承的策略,有SINGLE_TABLE、TABLE_PER_CLASS 和 JOINED 三种,JOINED 是将父类、子类分别存放在不同的表中,并且建立相应的外键,以确定相互之间的关系
public class Payment {
@Id
@GeneratedValue
private Long id;
private BigDecimal amount;
private boolean completed;
@ManyToOne
private Person person;
//Getters and setters are omitted for brevity
}
@Entity
public class CreditCardPayment extends Payment {
}
@Entity
public class WireTransferPayment extends Payment {
}
JPA查询API
在JPA中,查询是由javax.persistence.Query
或javax.persistence.TypedQuery
从EntityManager中获得的
。创建一个内联Query
或TypedQuery
,你需要使用该EntityManager#createQuery
方法。对于命名查询,该EntityManager#createNamedQuery
方法是必需的。
Query
或TypedQuery
引用
Query query = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name"
);
TypedQuery typedQuery = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name", Person.class
);
Query
或TypedQuery
引用
@NamedQuery(
name = "get_person_by_name",
query = "select p from Person p where name = :name"
)
Query query = entityManager.createNamedQuery( "get_person_by_name" );
TypedQuery typedQuery = entityManager.createNamedQuery(“get_person_by_name”, Person.class);@NamedQuery注解
,它提供了配置各种查询功能的方法,如刷新方法,缓存能力,超时间隔。
@NamedQueries({
@NamedQuery(
name = "get_phone_by_number",
query = "select p " +
"from Phone p " +
"where p.number = :number",
timeout = 1,
readOnly = true
)
})
Phone phone = entityManager
.createNamedQuery( "get_phone_by_number", Phone.class )
.setParameter( "number", "123-456-7890" )
.getSingleResult();
Query
然后接口可用于控制查询的执行。例如,我们可能想要指定执行超时或控制缓存。
Query
使用
Query query = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
// timeout - in milliseconds
.setHint( "javax.persistence.query.timeout", 2000 )
// flush only at commit time
.setFlushMode( FlushModeType.COMMIT );
Query
Javadocs。许多控制查询执行的设置都被定义为提示。JPA定义了一些标准提示(例如示例中的超时),但大多数提示都是基于提供者特定的环境的。依赖提供者特定的提示在一定程度上限制了你的应用程序的可移植性。
javax.persistence.query.timeout
定义查询超时,以毫秒为单位。
javax.persistence.fetchgraph
定义一个fetchgraph EntityGraph。显式指定的属性AttributeNodes被视为FetchType.EAGER(通过联合提取或随后的选择)。有关详细信息,请参阅提取中的EntityGraph讨论。
javax.persistence.loadgraph定义一个负载图EntityGraph。显式指定为AttributeNodes的属性被视为FetchType.EAGER(通过联合提取或随后的选择)。未指定的属性视为FetchType.LAZY或FetchType.EAGER取决于元数据中属性的定义。有关详细信息,请参阅Fetching中的EntityGraph讨论。org.hibernate.cacheMode
定义CacheMode去使用
org.hibernate.query.Query#setCacheMode
org.hibernate.cacheable
定义查询是否可缓存。是真是假
org.hibernate.query.Query#setCacheable
org.hibernate.cacheRegion
对于可缓存的查询,定义要使用的特定缓存区域
org.hibernate.query.Query#setCacheRegion
org.hibernate.comment
定义应用于生成的SQL的注释
org.hibernate.query.Query#setComment
org.hibernate.fetchSize
定义要使用的JDBC提取大小
org.hibernate.query.Query#setFetchSize
org.hibernate.flushMode
定义特有的FlushMode为Hibernate来使用
请参阅org.hibernate.query.Query#setFlushMode.如果可能,请使用javax.persistence.Query#setFlushMode代替。org.hibernate.readOnly
定义由此查询加载的实体和集合应被标记为只读
看到org.hibernate.query.Query#setReadOnly
在可以执行查询之前需要发生的最后一件事是绑定任何已定义参数的值。JPA定义了一组简化的参数绑定方法。从本质上讲,它支持设置参数值(通过名称/位置)和一个专门的形式为Calendar/ Date类型另外接受一个TemporalType。
Query query = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" );
// For generic temporal field types (e.g. `java.util.Date`, `java.util.Calendar`)// we also need to provide the associated `TemporalType`
Query query = entityManager.createQuery(
“select p ” +
“from Person p ” +
“where p.createdOn > :timestamp” )
.setParameter( “timestamp”, timestamp, TemporalType.DATE );
?1
,- 来声明的?2
。序号从1开始。就像命名参数一样,位置参数也可以在查询中多次出现。Query query = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like ?1" )
.setParameter( 1, "J%" );
一个好的做法是不要以混合形式出现在给定的查询中。
在执行方面,JPA Query
提供了两种不同的方法来检索结果集。
Query#getResultList()
– 执行选择查询并返回结果列表。Query#getSingleResult()
– 执行选择查询并返回单个结果。如果有多个结果,则抛出异常。
getResultList()返回
结果集List persons = entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" )
.getResultList();
Person person = (Person) entityManager.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" )
.getSingleResult();
Hibernate Query API
在Hibernate中,HQL查询表示为org.hibernate.query.Query
从一个Session获得。如果一个HQL被命名为query,Session#getNamedQuery
将被使用; 否则Session#createQuery
需要。
Query
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name"
);
org.hibernate.query.Query query = session.getNamedQuery( "get_person_by_name" );
不仅大量的JPQL语法受到HQL语法的启发,而且许多JPA API也深受Hibernate的启发。这两份Query语法约定
非常相似。
Query接口可以用来控制查询的执行。例如,我们可能想要特定的控制执行超时或控制缓存。
例子12.基本查询用法 – Hibernate
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
// timeout - in seconds
.setTimeout( 2 )
// write to L2 caches, but do not read from them
.setCacheMode( CacheMode.REFRESH )
// assuming query cache was enabled for the SessionFactory
.setCacheable( true )
// add a comment to the generated SQL if enabled via the hibernate.use_sql_comments configuration property
.setComment( "+ INDEX(p idx_person_name)" );
有关完整的详细信息,请参阅查询 Javadocs。
这里的查询提示是数据库查询提示。根据,它们将根据Dialect#getQueryHintString
直接被添加到生成的SQL中。
Hibernate 还允许一个应用程序通过org.hibernate.transform.ResultTransformer的约定hook进进程来建立查询结果。请参阅其Javadocs以及Hibernate提供的实现。
在我们执行查询之前需要发生的最后一件事是绑定查询中定义的任何参数的值。Query为此定义了许多重载的方法。最通用的形式是取值和Hibernate类型一样。
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%", StringType.INSTANCE );
Hibernate通常可以推断出给定查询中上下文的参数的预期类型。在前面的例子中,因为我们在LIKE
与String类型的属性进行比较时使用的参数,Hibernate会自动推断出类型; 所以上述语法可以简化。
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" );
还有用于绑定常用类型的简写形式,如字符串,布尔值,整数等。
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name " +
" and p.createdOn > :timestamp" )
.setParameter( "name", "J%" )
.setParameter( "timestamp", timestamp, TemporalType.TIMESTAMP);
HQL风格的位置参数遵循JDBC位置参数语法。他们宣布使用?
没有以下序数。除了将相同的值绑定到每个参数之外,没有办法将两个这样的位置参数关联为“相同”。
org.hibernate.query.Query query = session.createQuery(
"select p " +
"from Person p " +
"where p.name like ? " )
.setParameter( 0, "J%" );
在执行方面,Hibernate提供了4种不同的方法。以下是2个最常用
Query#list – 执行选择查询并返回结果列表。
Query#uniqueResult – 执行选择查询并返回单个结果。如果有多个结果,则抛出异常。
例子17.休眠list()结果
List persons = session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" )
.list();
也可以从Query中提取单个结果。
uniqueResult()
Person person = (Person) session.createQuery(
"select p " +
"from Person p " +
"where p.name like :name" )
.setParameter( "name", "J%" )
.uniqueResult();
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 《Hibernate快速开始》Query /HQL and JPQL (上)
暂无评论