Hibernate Named Query 예제 – @NamedQuery

Hibernate Named Query 예제 튜토리얼에 오신 것을 환영합니다. 우리는 Hibernate에서 HQL과 Native SQL Query를 사용하는 방법을 보았습니다. 많은 쿼리가 있다면, 모든 쿼리가 프로젝트 전체에 흩어져 있어 코드가 혼잡해질 수 있습니다. 그래서 Hibernate에서는 중앙 위치에 정의할 수 있는 Named Query를 제공합니다. 우리는 HQL과 Native SQL 모두를 위해 named query를 생성할 수 있습니다.

Hibernate Named Query

Hibernate Named Query는 Hibernate 매핑 파일을 통해 정의하거나 JPA 주석 @NamedQuery@NamedNativeQuery를 사용하여 정의할 수 있습니다. 오늘은 두 가지 방법 모두와 간단한 응용 프로그램에서 하이버네이트 네임드 쿼리를 사용하는 방법을 살펴보겠습니다. 데이터베이스 설정 SQL 스크립트는 HQL 예제와 같은 데이터베이스 테이블을 사용하므로 해당 게시물을 확인할 수 있습니다. 하이버네이트 네임드 쿼리 예제 프로젝트에서는 하이버네이트 매핑에 주석을 사용할 것입니다. 그러나 매핑 파일과 엔티티 빈 클래스 모두에서 일부 네임드 쿼리를 생성할 것입니다. 최종 프로젝트 구조는 아래 이미지와 같으며, 주로 하이버네이트 네임드 쿼리와 관련된 구성 요소에 초점을 맞출 것입니다.

하이버네이트 구성 XML

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE hibernate-configuration SYSTEM "https://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.password">pankaj123</property>
		<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
		<property name="hibernate.connection.username">pankaj</property>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

		<property name="hibernate.current_session_context_class">thread</property>
		<property name="hibernate.show_sql">true</property>

		<mapping class="com.journaldev.hibernate.model.Employee" />
		<mapping class="com.journaldev.hibernate.model.Address" />
		<mapping resource="named-queries.hbm.xml" />
	</session-factory>
</hibernate-configuration>

Hibernate Named Query XML

우리는 HQL(named queries)과 Native SQL(named queries)만 포함하는 하이버네이트 매핑 파일을 가지고 있습니다. named-queries.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
	
<hibernate-mapping>
	<query name="HQL_GET_ALL_EMPLOYEE">from Employee</query>

	<query name="HQL_GET_EMPLOYEE_BY_ID">
		<![CDATA[from Employee where emp_id = :id]]>
	</query>

	<query name="HQL_GET_EMPLOYEE_BY_SALARY">
		<![CDATA[from Employee where emp_salary > :salary]]>
	</query>
	
	<sql-query name="SQL_GET_ALL_EMPLOYEE">
		<![CDATA[select emp_id, emp_name, emp_salary from Employee]]>
	</sql-query>
	
	<sql-query name="SQL_GET_ALL_EMP_ADDRESS">
		<![CDATA[select {e.*}, {a.*} from Employee e join Address a ON e.emp_id=a.emp_id]]>
		<return alias="e" class="com.journaldev.hibernate.model.Employee" />
		<return-join alias="a" property="e.address"></return-join>
	</sql-query>
</hibernate-mapping>

query 요소는 HQL(named queries)에 사용되며, sql-query 요소는 네이티브 SQL(named queries)에 사용됩니다. return 요소는 결과 집합이 매핑될 엔티티를 선언하는 데 사용됩니다. return-join은 여러 테이블을 조인할 때 사용됩니다. 하이버네이트 named query를 선언할 때는 CDATA를 사용하여 데이터로 처리되도록 해야 합니다. 그렇지 않으면 <와 > 기호가 매핑 XML 파일을 망칠 수 있습니다.

Hibernate Named Query @NamedQuery 어노테이션

두 개의 모델 클래스 – EmployeeAddress가 있습니다. Address 클래스에서 아래와 같이 named query를 정의했습니다.

package com.journaldev.hibernate.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name = "ADDRESS")
@NamedQueries({ @NamedQuery(name = "@HQL_GET_ALL_ADDRESS", 
			query = "from Address") })
@NamedNativeQueries({ @NamedNativeQuery(name = "@SQL_GET_ALL_ADDRESS", 
			query = "select emp_id, address_line1, city, zipcode from Address") })
public class Address {

	@Id
	@Column(name = "emp_id", unique = true, nullable = false)
	@GeneratedValue(generator = "gen")
	@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
	private long id;

	@Column(name = "address_line1")
	private String addressLine1;

	@Column(name = "zipcode")
	private String zipcode;

	@Column(name = "city")
	private String city;

	@OneToOne
	@PrimaryKeyJoinColumn
	private Employee employee;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getAddressLine1() {
		return addressLine1;
	}

	public void setAddressLine1(String addressLine1) {
		this.addressLine1 = addressLine1;
	}

	public String getZipcode() {
		return zipcode;
	}

	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	@Override
	public String toString() {
		return "AddressLine1= " + addressLine1 + ", City=" + city
				+ ", Zipcode=" + zipcode;
	}
}

Hibernate Named Query 테스트 프로그램

package com.journaldev.hibernate.main;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.hibernate.model.Address;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;

public class HibernateNamedQueryExample {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {

		위에서 정의한 모든 하이버네이트 이름이 지정된 쿼리를 사용하는 테스트 프로그램을 작성해 봅시다.
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.getCurrentSession();
		Transaction tx = session.beginTransaction();

		// 준비 작업
		Query query = session.getNamedQuery("HQL_GET_ALL_EMPLOYEE");
		List empList = query.list();
		for (Employee emp : empList) {
			System.out.println("List of Employees::" + emp.getId() + ","
					+ emp.getAddress().getCity());
		}

		query = session.getNamedQuery("HQL_GET_EMPLOYEE_BY_ID");
		query.setInteger("id", 2);
		Employee emp = (Employee) query.uniqueResult();
		System.out.println("Employee Name=" + emp.getName() + ", City="
				+ emp.getAddress().getCity());

		query = session.getNamedQuery("HQL_GET_EMPLOYEE_BY_SALARY");
		query.setInteger("salary", 200);
		empList = query.list();
		for (Employee emp1 : empList) {
			System.out.println("List of Employees::" + emp1.getId() + ","
					+ emp1.getSalary());
		}

		query = session.getNamedQuery("@HQL_GET_ALL_ADDRESS");
		List
addressList = query.list(); for (Address addr : addressList) { System.out.println("List of Address::" + addr.getId() + "::" + addr.getZipcode() + "::" + addr.getEmployee().getName()); } //HQL 이름이 지정된 쿼리 예제 query = session.getNamedQuery("@SQL_GET_ALL_ADDRESS"); List addressObjArray = query.list(); for(Object[] row : addressObjArray){ for(Object obj : row){ System.out.print(obj + "::"); } System.out.println("\n"); } query = session.getNamedQuery("SQL_GET_ALL_EMP_ADDRESS"); addressObjArray = query.list(); for(Object[] row : addressObjArray){ Employee e = (Employee) row[0]; System.out.println("Employee Info::"+e); Address a = (Address) row[1]; System.out.println("Address Info::"+a); } //Native SQL 이름이 지정된 쿼리 예제 tx.commit(); // 테스트 데이터 저장을 위한 롤백 sessionFactory.close(); } }

// 하이버네이트 리소스 닫기

Hibernate: select employee0_.emp_id as emp_id1_1_, employee0_.emp_name as emp_name2_1_, employee0_.emp_salary as emp_sala3_1_ from EMPLOYEE employee0_
Hibernate: select address0_.emp_id as emp_id1_0_0_, address0_.address_line1 as address_2_0_0_, address0_.city as city3_0_0_, address0_.zipcode as zipcode4_0_0_, employee1_.emp_id as emp_id1_1_1_, employee1_.emp_name as emp_name2_1_1_, employee1_.emp_salary as emp_sala3_1_1_ from ADDRESS address0_ left outer join EMPLOYEE employee1_ on address0_.emp_id=employee1_.emp_id where address0_.emp_id=?
Hibernate: select address0_.emp_id as emp_id1_0_0_, address0_.address_line1 as address_2_0_0_, address0_.city as city3_0_0_, address0_.zipcode as zipcode4_0_0_, employee1_.emp_id as emp_id1_1_1_, employee1_.emp_name as emp_name2_1_1_, employee1_.emp_salary as emp_sala3_1_1_ from ADDRESS address0_ left outer join EMPLOYEE employee1_ on address0_.emp_id=employee1_.emp_id where address0_.emp_id=?
Hibernate: select address0_.emp_id as emp_id1_0_0_, address0_.address_line1 as address_2_0_0_, address0_.city as city3_0_0_, address0_.zipcode as zipcode4_0_0_, employee1_.emp_id as emp_id1_1_1_, employee1_.emp_name as emp_name2_1_1_, employee1_.emp_salary as emp_sala3_1_1_ from ADDRESS address0_ left outer join EMPLOYEE employee1_ on address0_.emp_id=employee1_.emp_id where address0_.emp_id=?
Hibernate: select address0_.emp_id as emp_id1_0_0_, address0_.address_line1 as address_2_0_0_, address0_.city as city3_0_0_, address0_.zipcode as zipcode4_0_0_, employee1_.emp_id as emp_id1_1_1_, employee1_.emp_name as emp_name2_1_1_, employee1_.emp_salary as emp_sala3_1_1_ from ADDRESS address0_ left outer join EMPLOYEE employee1_ on address0_.emp_id=employee1_.emp_id where address0_.emp_id=?
List of Employees::1,San Jose
List of Employees::2,Santa Clara
List of Employees::3,Bangalore
List of Employees::4,New Delhi
Hibernate: select employee0_.emp_id as emp_id1_1_, employee0_.emp_name as emp_name2_1_, employee0_.emp_salary as emp_sala3_1_ from EMPLOYEE employee0_ where emp_id=?
Employee Name=David, City=Santa Clara
Hibernate: select employee0_.emp_id as emp_id1_1_, employee0_.emp_name as emp_name2_1_, employee0_.emp_salary as emp_sala3_1_ from EMPLOYEE employee0_ where emp_salary>?
List of Employees::3,300.0
List of Employees::4,400.0
Hibernate: select address0_.emp_id as emp_id1_0_, address0_.address_line1 as address_2_0_, address0_.city as city3_0_, address0_.zipcode as zipcode4_0_ from ADDRESS address0_
List of Address::1::95129::Pankaj
List of Address::2::95051::David
List of Address::3::560100::Lisa
List of Address::4::100100::Jack
Hibernate: select emp_id, address_line1, city, zipcode from Address
1::Albany Dr::San Jose::95129::

2::Arques Ave::Santa Clara::95051::

3::BTM 1st Stage::Bangalore::560100::

4::City Centre::New Delhi::100100::

Hibernate: select e.emp_id as emp_id1_1_0_, e.emp_name as emp_name2_1_0_, e.emp_salary as emp_sala3_1_0_, a.emp_id as emp_id1_0_1_, a.address_line1 as address_2_0_1_, a.city as city3_0_1_, a.zipcode as zipcode4_0_1_ from Employee e join Address a ON e.emp_id=a.emp_id
Employee Info::Id= 1, Name= Pankaj, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}
Address Info::AddressLine1= Albany Dr, City=San Jose, Zipcode=95129
Employee Info::Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}
Address Info::AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051
Employee Info::Id= 3, Name= Lisa, Salary= 300.0, {Address= AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100}
Address Info::AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100
Employee Info::Id= 4, Name= Jack, Salary= 400.0, {Address= AddressLine1= City Centre, City=New Delhi, Zipcode=100100}
Address Info::AddressLine1= City Centre, City=New Delhi, Zipcode=100100

위의 프로그램을 테스트 데이터와 함께 실행하면 다음 출력이 생성됩니다.Hibernate 이름이 지정된 쿼리 중요 사항

Hibernate 이름이 지정된 쿼리에 대한 몇 가지 중요한 사항은 다음과 같습니다.

  1. Hibernate 이름이 지정된 쿼리는 코드 전체에 흩어지지 않고 중앙 위치에 쿼리를 그룹화하는 데 도움이 됩니다.
  2. Hibernate 이름이 지정된 쿼리 구문은 하이버네이트 세션 팩토리가 생성될 때 확인되므로, 이름이 지정된 쿼리에 오류가 있는 경우 응용 프로그램이 빠르게 실패합니다.
  3. Hibernate 이름이 지정된 쿼리는 전역적으로 사용할 수 있으므로, 한 번 정의하면 응용 프로그램 전체에서 사용할 수 있습니다.
  4. 이름이 지정된 쿼리의 주요 단점 중 하나는 디버깅하기 어렵다는 것입니다. 즉, 정의된 위치를 찾아야 합니다.

Hibernate 이름이 지정된 쿼리 예제에 대한 내용은 여기까지입니다. 아래 링크에서 샘플 프로젝트를 다운로드할 수 있습니다.

Hibernate 이름이 지정된 쿼리 프로젝트 다운로드

Source:
https://www.digitalocean.com/community/tutorials/hibernate-named-query-example-namedquery