建立實體類
在介紹Hibernate查詢語言之前,首先我們來建立一下資料庫。這裡直接使用了MySQL自帶的樣例資料庫world。如果你沒有安裝MySQL那麼需要安裝一下,并且在安裝的時候選擇安裝樣例資料庫。
安裝完成之後,應該能在MySQL中看到一個名為world的資料庫,其中有三個表,country、city以及countrylanguage表。然後我們來建立這三個表對應的實體類。需要注意,由于這一次是針對已經存在的資料庫,是以在
hibernate.cfg.xml
中
<property name="hbm2ddl.auto">update</property>
這一行應當設定為update,避免Hibernate重新建立表覆寫掉原有的資料。
這三個表有點長,是以會影響到閱讀。由于countrylanguage表存在兩個主鍵,而且Hibernate要求複合主鍵的實體類必須實作Serializable接口,是以這裡也實作了這個接口。
@Entity
public class City {
private int id;
private Country country;
private String district;
private String name;
private Integer population;
@Id
@Column(name = "ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "CountryCode", foreignKey = @ForeignKey(name = "countryLanguage_ibfk_1"))
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
@Basic
@Column(name = "District")
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
@Basic
@Column(name = "Name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
@Column(name = "Population")
public Integer getPopulation() {
return population;
}
public void setPopulation(Integer population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
City city = (City) o;
return id == city.id &&
Objects.equals(country, city.country) &&
Objects.equals(district, city.district) &&
Objects.equals(name, city.name) &&
Objects.equals(population, city.population);
}
@Override
public String toString() {
return "City{" +
"id=" + id +
", country=" + country.getName() +
", district='" + district + '\'' +
", name='" + name + '\'' +
", population=" + population +
'}';
}
@Override
public int hashCode() {
return Objects.hash(id, country, district, name, population);
}
}
@Entity
public class Country {
private String code;
private String name;
private String continent;
private String region;
private double surfaceArea;
private Short indepYear;
private int population;
private Double lifeExpectancy;
private Double gnp;
private Double gnpOld;
private String localName;
private String governmentForm;
private String headOfState;
private Integer capital;
private String code2;
@Id
@Column(name = "Code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Basic
@Column(name = "Name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
@Column(name = "Continent")
public String getContinent() {
return continent;
}
public void setContinent(String continent) {
this.continent = continent;
}
@Basic
@Column(name = "Region")
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
@Basic
@Column(name = "SurfaceArea")
public double getSurfaceArea() {
return surfaceArea;
}
public void setSurfaceArea(double surfaceArea) {
this.surfaceArea = surfaceArea;
}
@Basic
@Column(name = "IndepYear")
public Short getIndepYear() {
return indepYear;
}
public void setIndepYear(Short indepYear) {
this.indepYear = indepYear;
}
@Basic
@Column(name = "Population")
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Basic
@Column(name = "LifeExpectancy")
public Double getLifeExpectancy() {
return lifeExpectancy;
}
public void setLifeExpectancy(Double lifeExpectancy) {
this.lifeExpectancy = lifeExpectancy;
}
@Basic
@Column(name = "GNP")
public Double getGnp() {
return gnp;
}
public void setGnp(Double gnp) {
this.gnp = gnp;
}
@Basic
@Column(name = "GNPOld")
public Double getGnpOld() {
return gnpOld;
}
public void setGnpOld(Double gnpOld) {
this.gnpOld = gnpOld;
}
@Basic
@Column(name = "LocalName")
public String getLocalName() {
return localName;
}
public void setLocalName(String localName) {
this.localName = localName;
}
@Basic
@Column(name = "GovernmentForm")
public String getGovernmentForm() {
return governmentForm;
}
public void setGovernmentForm(String governmentForm) {
this.governmentForm = governmentForm;
}
@Basic
@Column(name = "HeadOfState")
public String getHeadOfState() {
return headOfState;
}
public void setHeadOfState(String headOfState) {
this.headOfState = headOfState;
}
@Basic
@Column(name = "Capital")
public Integer getCapital() {
return capital;
}
public void setCapital(Integer capital) {
this.capital = capital;
}
@Basic
@Column(name = "Code2")
public String getCode2() {
return code2;
}
public void setCode2(String code2) {
this.code2 = code2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return Double.compare(country.surfaceArea, surfaceArea) == 0 &&
population == country.population &&
Objects.equals(code, country.code) &&
Objects.equals(name, country.name) &&
Objects.equals(continent, country.continent) &&
Objects.equals(region, country.region) &&
Objects.equals(indepYear, country.indepYear) &&
Objects.equals(lifeExpectancy, country.lifeExpectancy) &&
Objects.equals(gnp, country.gnp) &&
Objects.equals(gnpOld, country.gnpOld) &&
Objects.equals(localName, country.localName) &&
Objects.equals(governmentForm, country.governmentForm) &&
Objects.equals(headOfState, country.headOfState) &&
Objects.equals(capital, country.capital) &&
Objects.equals(code2, country.code2);
}
@Override
public int hashCode() {
return Objects.hash(code, name, continent, region, surfaceArea, indepYear, population, lifeExpectancy, gnp, gnpOld, localName, governmentForm, headOfState, capital, code2);
}
@Override
public String toString() {
return "Country{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
", continent='" + continent + '\'' +
", region='" + region + '\'' +
", surfaceArea=" + surfaceArea +
", indepYear=" + indepYear +
", population=" + population +
", lifeExpectancy=" + lifeExpectancy +
", gnp=" + gnp +
", gnpOld=" + gnpOld +
", localName='" + localName + '\'' +
", governmentForm='" + governmentForm + '\'' +
", headOfState='" + headOfState + '\'' +
", capital=" + capital +
", code2='" + code2 + '\'' +
'}';
}
}
@Entity
public class Countrylanguage implements Serializable {
private String language;
private Country country;
private String isOfficial;
private Double percentage;
@Id
@Column(name = "Language")
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
@Id
@ManyToOne
@JoinColumn(name = "CountryCode", foreignKey = @ForeignKey(name = "countryLanguage_ibfk_1"))
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
@Basic
@Column(name = "IsOfficial")
public String getIsOfficial() {
return isOfficial;
}
public void setIsOfficial(String isOfficial) {
this.isOfficial = isOfficial;
}
@Basic
@Column(name = "Percentage")
public Double getPercentage() {
return percentage;
}
public void setPercentage(Double percentage) {
this.percentage = percentage;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Countrylanguage that = (Countrylanguage) o;
return Objects.equals(language, that.language) &&
Objects.equals(country, that.country) &&
Objects.equals(isOfficial, that.isOfficial) &&
Objects.equals(percentage, that.percentage);
}
@Override
public String toString() {
return "Countrylanguage{" +
"language='" + language + '\'' +
", country=" + country.getName() +
", isOfficial='" + isOfficial + '\'' +
", percentage=" + percentage +
'}';
}
@Override
public int hashCode() {
return Objects.hash(language, country, isOfficial, percentage);
}
}
HQL
HQL是Hibernate的資料庫查詢語言,看名字可以知道這種查詢語言和SQL類似。其實呢,這種查詢語言,其實就是SQL中把表名和列名換成了實體類名和屬性名。而且如果使用IDEA這樣的智能內建開發環境,還會貼心的把SQL和HQL等查詢語言高亮顯示,特别友善。
首先我們需要建立一個Session,然後使用session.createQuery方法建立一個Query對象,然後調用query.list方法擷取查詢結果。這是一個簡單的例子,示範了一下HQL的基本用法。如果需要更詳細的用法還是查閱相關資料更好。
@Test
public void test() {
try (Session session = factory.openSession()) {
//查詢所有國家
List<Country> countries = session.createQuery("from Country", Country.class).list();
//查詢c開頭的所有國家
List<Country> countriesStartWithC = session.createQuery("from Country c where c.name like 'c%'", Country.class).list();
//countries.forEach(country -> logger.info(country.toString()));
countriesStartWithC.forEach(country -> logger.info(country.toString()));
//查詢中國的國家代碼
List<String> countryCodes = session.createQuery("select c.code from Country c where c.name='China'", String.class).list();
countryCodes.forEach(c -> logger.info(c));
//查詢中國的所有城市
List<City> cities = session.createQuery("from City c where c.country.name='China'", City.class).list();
cities.forEach(c -> logger.info(c.toString()));
}
}
Criteria
Criteria是Hibernate提供的另外一種查詢語言。Criteria有兩個版本,
org.hibernate.Criteria
屬于舊版本的,雖然還沒有标記為過時,Hibernate官方已經不推薦我們使用這種了。相應的,我們應該使用
javax.persistence.criteria.CriteriaBuilder
接口來建立和使用查詢。
首先需要調用getCriteriaBuilder方法生成一個CriteriaBuilder。然後使用Builder的createQuery方法建立一個查詢。Root對象代表查詢的根,也就是要查詢的表,然後可以使用查詢對象提供的各種方法來查詢我們要的資料。詳細的使用方法還是需要查閱文檔。
@Test
public void testCriteria() {
try (Session session = factory.openSession()) {
//查詢人口最少的20個城市
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<City> query = builder.createQuery(City.class);
Root<City> root = query.from(City.class);
query.select(root);
query.orderBy(builder.asc(root.get("population")));
List<City> cities = session.createQuery(query).setMaxResults(20).list();
cities.forEach(city -> logger.info(city.toString()));
}
}
Native SQL
除了使用上面所說的查詢語言之外,還可以直接使用SQL查詢資料。調用Session.createNativeQuery即可建立一個SQL查詢。需要注意傳回的結果是一個List<Object[]>。我們需要對結果進行轉換才能正确使用。
@Test
public void testSQL() {
try (Session session = factory.openSession()) {
//東亞所有國家和地區
NativeQuery query = session.createNativeQuery("select code,name,population from country where Region='Eastern Asia'");
List<Object[]> countries = query.getResultList();
for (Object[] country : countries) {
String code = (String) country[0];
String name = (String) country[1];
int population = (int) country[2];
logger.info("Code:{} Name:{} Population:{}", code, name, population);
}
}
}
以上就是Hibernate提供的幾種查詢方式。我這裡隻做了一點簡單介紹,詳細的使用方法還是需要檢視更詳細的資料。不過這些方法基本大同小異,隻要熟悉SQL資料庫的查詢語言,學會這幾種查詢方法也很簡單。