Hibernate JPQL SELECT 教程
最后修改于 2020 年 7 月 16 日
Hibernate JPQL SELECT 教程展示了如何在 Hibernate 中执行 JPQL SELECT 语句。我们使用 MySQL 数据库。
Hibernate
Hibernate 是一个用于 Java 编程语言的对象关系映射工具。它提供了一个框架,用于将面向对象的领域模型映射到关系数据库。
JPQL
Java Persistence Query Language (JPQL) 是作为 Java Persistence API (JPA) 规范一部分定义的平台无关的面向对象的查询语言。JPQL 用于针对存储在关系数据库中的实体进行查询。JPQL 的灵感来源于 SQL。
JPQL 是面向对象的。在 JPQL 中,我们处理的是实体和实体集合,而在 SQL 中,我们处理的是列和行。
JPQL SELECT 语句的语法如下:
SELECT {select clause} FROM {from clause} [WHERE {where clause}] [ORDER BY {order by clause}] [GROUP BY {group by clause}] [HAVING {having clause}]
WHERE
、ORDER BY
、GROUP BY
和 HAVING
子句是可选的。
Hibernate JPQL SELECT 示例
下面的应用程序执行了几个 JPQL SELECT 语句。
DROP TABLE IF EXISTS cities; CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100), population INT); INSERT INTO cities(name, population) VALUES('Bratislava', 432000); INSERT INTO cities(name, population) VALUES('Budapest', 1759000); INSERT INTO cities(name, population) VALUES('Prague', 1280000); INSERT INTO cities(name, population) VALUES('Warsaw', 1748000); INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000); INSERT INTO cities(name, population) VALUES('New York', 8550000); INSERT INTO cities(name, population) VALUES('Edinburgh', 464000); INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
这是用于在 MySQL 中创建 cities
表的 SQL。
$ tree . ├── nbactions.xml ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── HibernateJpqlSelect.java │ │ └── model │ │ └── City.java │ └── resources │ ├── log4j2.xml │ └── META-INF │ └── persistence.xml └── test └── java
这是项目结构。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>HibernateJpqlSelect</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.8.Final</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.10.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.5.0</version> <configuration> <mainClass>com.zetcode.HibernateJpqlSelect</mainClass> </configuration> </plugin> </plugins> </build> </project>
这是 Maven 构建文件。mysql-connector-java
是 MySQL 驱动程序,hibernate-core
提供了 Hibernate 的核心功能,而 log4j-slf4j-impl
是 Log4j2 库的一个简单的日志门面。
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d [%t] %-5level %logger - %m%n" /> </Console> </Appenders> <Loggers> <!-- Log everything in Hibernate --> <Logger name="org.hibernate" level="error" additivity="false"> <AppenderRef ref="Console" /> </Logger> <!-- Log SQL statements --> <Logger name="org.hibernate.SQL" level="error" additivity="false"> <AppenderRef ref="Console" /> </Logger> <!-- Log custom packages --> <Logger name="com.zetcode" level="error" additivity="false"> <AppenderRef ref="Console" /> </Logger> <Root level="error"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
log4j2.xml
文件是 Log4j2 的配置文件。
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="my-pu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://:3306/testdb?useSSL=false"/> <property name="javax.persistence.jdbc.user" value="testuser"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.password" value="test623"/> <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> </properties> </persistence-unit> </persistence>
persistence.xml
文件是 JPA 中的标准配置文件。它必须包含在包含实体 Bean 的 JAR 文件内的 META-INF
目录中。persistence.xml
文件必须定义一个在当前作用域的类加载器中唯一的持久化单元(persistence-unit)名称。provider 属性指定了 JPA EntityManager 的底层实现。
我们提供了 MySQL 连接的配置选项。hibernate.dialect
被设置为 MySQL Hibernate 方言。
package com.zetcode.model; import java.util.Objects; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "cities") public class City { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private int population; public City() { } public City(String name, int population) { this.name = name; this.population = population; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } @Override public int hashCode() { int hash = 7; hash = 79 * hash + Objects.hashCode(this.id); hash = 79 * hash + Objects.hashCode(this.name); hash = 79 * hash + this.population; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final City other = (City) obj; if (this.population != other.population) { return false; } if (!Objects.equals(this.name, other.name)) { return false; } return Objects.equals(this.id, other.id); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("City{id=").append(id).append(", name=") .append(name).append(", population=") .append(population).append("}"); return builder.toString(); } }
这是 City
实体。
@Entity @Table(name = "cities") public class City {
@Entity
注解指定该类是一个实体。@Table
注解指定了被注解实体的对应主表。
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
@Id
注解指定了实体的が主键,而 @GeneratedValue
提供了主键值生成策略的指定。
package com.zetcode; import com.zetcode.model.City; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; public class HibernateJpqlSelect { private static final String PERSISTENCE_UNIT_NAME = "my-pu"; public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory( PERSISTENCE_UNIT_NAME); EntityManager entityManager = emf.createEntityManager(); try { entityManager.getTransaction().begin(); String qlQuery = "SELECT c FROM City c"; Query query = entityManager.createQuery(qlQuery); List<City> cities = query.getResultList(); cities.stream().forEach((x) -> System.out.println(x)); String qlQuery2 = "SELECT COUNT(c) FROM City c"; Query query2 = entityManager.createQuery(qlQuery2); Long nOfCities = (Long) query2.getSingleResult(); System.out.printf("There are %d cities%n", nOfCities); String qlQuery3 = "SELECT c.name FROM City c WHERE c.population=1759000"; Query query3 = entityManager.createQuery(qlQuery3); List<String> names = query3.getResultList(); names.stream().forEach((x) -> System.out.println(x)); String qlQuery4 = "SELECT c FROM City c ORDER BY population DESC"; Query query4 = entityManager.createQuery(qlQuery4); List<City> cities2 = query4.getResultList(); cities2.stream().forEach((x) -> System.out.println(x)); String qlQuery5 = "SELECT SUM(c.population) FROM City c"; Query query5 = entityManager.createQuery(qlQuery5); Long popSum = (Long) query5.getSingleResult(); System.out.printf("Sum of city populations %d%n", popSum); entityManager.getTransaction().commit(); } finally { entityManager.close(); emf.close(); } } }
该示例运行了五个 JPQL SELECT 语句。
EntityManagerFactory emf = Persistence.createEntityManagerFactory( PERSISTENCE_UNIT_NAME); EntityManager entityManager = emf.createEntityManager();
从 EntityManagerFactory
创建一个 EntityManager
。它是一个与持久化上下文交互的接口。
String qlQuery = "SELECT c FROM City c"; Query query = entityManager.createQuery(qlQuery); List<City> cities = query.getResultList(); cities.stream().forEach((x) -> System.out.println(x));
SELECT c FROM City c
是一个 JPQL 查询,它返回所有城市。通过 EntityManager
的 createQuery()
创建一个 Query
。从 Query
中,我们使用 getResultList()
获取结果。
String qlQuery2 = "SELECT COUNT(c) FROM City c";
使用 SELECT COUNT(c) FROM City c
,我们获得 City
实体的数量。
String qlQuery3 = "SELECT c.name FROM City c WHERE c.population=1759000";
使用 SELECT c.name FROM City c WHERE c.population=1759000
,我们选择人口等于 1759000
的实体。
String qlQuery4 = "SELECT c FROM City c ORDER BY population DESC";
使用 SELECT c FROM City c ORDER BY population DESC
,我们得到一个按人口降序排列的实体列表。
String qlQuery5 = "SELECT SUM(c.population) FROM City c";
使用 SELECT SUM(c.population) FROM City c
,我们得到所有城市人口的总和。
$ mvn exec:java -q City{id=1, name=Bratislava, population=432000} City{id=2, name=Budapest, population=1759000} City{id=3, name=Prague, population=1280000} City{id=4, name=Warsaw, population=1748000} City{id=5, name=Los Angeles, population=3971000} City{id=6, name=New York, population=8550000} City{id=7, name=Edinburgh, population=464000} City{id=8, name=Berlin, population=3671000} There are 8 cities Budapest City{id=6, name=New York, population=8550000} City{id=5, name=Los Angeles, population=3971000} City{id=8, name=Berlin, population=3671000} City{id=2, name=Budapest, population=1759000} City{id=4, name=Warsaw, population=1748000} City{id=3, name=Prague, population=1280000} City{id=7, name=Edinburgh, population=464000} City{id=1, name=Bratislava, population=432000} Sum of city populations 21875000
在本教程中,我们在 Hibernate 中使用了 JPQL SELECT 语句。