프로그래밍n학습자료(2018~)/Hibernate

[Hibernate] 7. Hibernate(하이버네이트) HQL

단세포소년 2018. 3. 8. 16:59
반응형

HQL 사용하기

HQL SQL과는 거의 비슷하다. 다른 점이라면 테이블명이나 컬럼명을 쓰는 것이 아니라 맵핑 클래스명과 멤버변수명을 쓰는 것이다.

 

그리고 테이블과 맵핑된 클래스명을 쓸때는 Alias 써야한다.

 

HQL 쓰면 SQL 맵핑되고 결과가 다시 맵핑 클래스로 맵핑되는 형태이다. HQL 결과는 클래스로 맵핑된다.

 

예제 데이터

간단한 예제를 위해 foreigne key Constraint(제약조건) 무시, 정규화 무시.

 

학생, 과목, 과목별점수 테이블로 이루어진 예제이다. 예제를 바탕으로 몇가지 HQL 예제를 확인할 것이다.

 

스키마 데이터(mysql):

DROP TABLE IF EXISTS `Course`;

 

CREATE TABLE `Course` (

  `ID` int(11) NOT NULL,

  `COURSE_NAME` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`ID`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

LOCK TABLES `Course` WRITE;

 

INSERT INTO `Course` VALUES (1,'Science'),(2,'Math'),(3,'English'),(4,'Music');

 

UNLOCK TABLES;

DROP TABLE IF EXISTS `Score`;

 

CREATE TABLE `Score` (

  `STUDENT_ID` int(11) NOT NULL,

  `COURSE_ID` int(11) NOT NULL,

  `Score` int(11) DEFAULT NULL,

  PRIMARY KEY (`STUDENT_ID`,`COURSE_ID`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

LOCK TABLES `Score` WRITE;

 

INSERT INTO `Score` VALUES (1,1,70),(1,2,50),(1,3,64),(2,1,10),(2,2,32),(2,4,15),(3,3,99);

 

UNLOCK TABLES;

DROP TABLE IF EXISTS `Student`;

 

CREATE TABLE `Student` (

  `ID` int(11) NOT NULL,

  `NAME` varchar(45) DEFAULT NULL,

  `BIRTHDAY` date DEFAULT NULL,

  PRIMARY KEY (`ID`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

LOCK TABLES `Student` WRITE;

 

INSERT INTO `Student` VALUES (1,'Mark','1997-02-02'),(2,'Jane','1990-10-10'),(3,'Jone','1960-11-11');

 

UNLOCK TABLES;

 

Student:

ID

NAME

BIRTHDAY

1

Mark

1997-02-02

2

Jane

1990-10-10

3

Jone

1960-11-11

 

Course:

ID

COURSE_NAME

1

Science

2

Math

3

English

4

Music

 

Score:

STUDENT_ID

COURSE_ID

Score

1

1

70

1

2

50

1

3

64

2

1

10

2

2

32

2

4

15

3

3

99

 

 

 

맵핑 클래스

Student 매핑

package org.onecellboy.db.hibernate.table;

 

import java.util.Date;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="Student")

public class Student {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

        @Column(name="ID",columnDefinition="INT")

        private int id;

        

        @Column(name="NAME",columnDefinition="VARCHAR(45)")

        private String name;

        

        @Column(name="BIRTHDAY",columnDefinition="DATE")

        private Date birthday;

 

        public int getId() {

                return id;

        }

 

        public void setId(int id) {

                this.id = id;

        }

 

        public String getName() {

                return name;

        }

 

        public void setName(String name) {

                this.name = name;

        }

 

        public Date getBirthday() {

                return birthday;

        }

 

        public void setBirthday(Date birthday) {

                this.birthday = birthday;

        }

        

        

}

 

 

Course 맵핑

package org.onecellboy.db.hibernate.table;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="Course")

public class Course {

 

        @Id

        @GeneratedValue(strategy=GenerationType.IDENTITY)

        @Column(name="ID",columnDefinition="INT")

        private int id;

        

        @Column(name="COURSE_NAME",columnDefinition="VARCHAR(45)")

        private String name;

 

        public int getId() {

                return id;

        }

 

        public void setId(int id) {

                this.id = id;

        }

 

        public String getName() {

                return name;

        }

 

        public void setName(String name) {

                this.name = name;

        }

        

        

}

 

 

Score 맵핑

package org.onecellboy.db.hibernate.table;

 

import java.io.Serializable;

 

import javax.persistence.AttributeOverride;

import javax.persistence.AttributeOverrides;

import javax.persistence.Column;

import javax.persistence.Embeddable;

import javax.persistence.EmbeddedId;

import javax.persistence.Entity;

import javax.persistence.Table;

 

import org.onecellboy.db.hibernate.table.Apartment_Embeddable.APT_PK;

 

@Entity

@Table(name="Score")

public class Score {

        @Embeddable

        public static class Score_PK implements Serializable{

                private static final long serialVersionUID = 1L;

                

                protected int student_id;

                protected int course_id;

                

                public Score_PK() {

                        // TODO Auto-generated constructor stub

                }

                public Score_PK(int student_id, int course_id)

                {

                        this.student_id = student_id;

                        this.course_id = course_id;

                }

                

                

                public int getStudent_id() {

                        return student_id;

                }

                public void setStudent_id(int student_id) {

                        this.student_id = student_id;

                }

                public int getCourse_id() {

                        return course_id;

                }

                public void setCourse_id(int course_id) {

                        this.course_id = course_id;

                }

                

                

                @Override

                 public boolean equals(Object o) {

                        return ((o instanceof Score_PK) && student_id == ((Score_PK)o).getStudent_id() && course_id == ((Score_PK) o).getCourse_id());

                    }

                @Override

                 public int hashCode() {

                        return (int)(student_id ^ course_id);

                 }

 

        }

 

        @EmbeddedId

        @AttributeOverrides(value = {

                        @AttributeOverride(name="student_id", column=@Column(name="STUDENT_ID",columnDefinition="INT")),

                        @AttributeOverride(name="course_id", column=@Column(name="COURSE_ID",columnDefinition="INT"))

                  })

        private Score_PK id;

        

        @Column(name="SCORE",columnDefinition="INT")

        private int score;

 

        public Score_PK getId() {

                return id;

        }

 

        public void setId(Score_PK id) {

                this.id = id;

        }

 

        public int getScore() {

                return score;

        }

 

        public void setScore(int score) {

                this.score = score;

        }

        

 

        

}

Score 맵핑 클래스의 경우 복합키를 사용한다.

 

 

 

 

HQL SELECT 예제

HQL 위에서 말한 처럼 실제 테이블명과 컬럼명이 아니라 맵핑 클래스의 클래스명과 멤버변수를 써야한다.

 

HQL 맵핑정보를 보고 SQL 자동 전환되고 결과도 맵핑 클래스로 자동 할당된다.

 

 

기본 Select

query = session.createQuery("FROM Student");

resultList = query.getResultList();

for(Student st : (List<Student>)resultList)

{

        System.out.println("-----------------");

        System.out.println("id="+st.getId());

        System.out.println("name="+st.getName());

        System.out.println("birthday="+st.getBirthday());

 

}

Hibernate: select student0_.ID as ID1_10_, student0_.BIRTHDAY as BIRTHDAY2_10_, student0_.NAME as NAME3_10_ from Student student0_

-----------------

id=1

name=Mark

birthday=1997-02-02 00:00:00.0

-----------------

id=2

name=Jane

birthday=1990-10-10 00:00:00.0

-----------------

id=3

name=Jone

birthday=1960-11-11 00:00:00.0

 

 

 

 

 

 

조건 Select          

 

        query = session.createQuery("FROM Student Where id=:id");

                query.setParameter("id", 1);

                resultList = query.getResultList();

                for(Student st : (List<Student>)resultList)

                {

                        System.out.println("-----------------");

                        System.out.println("id="+st.getId());

                        System.out.println("name="+st.getName());

                        System.out.println("birthday="+st.getBirthday());

                

                }

 

setParameter() 통해 인자를 설정할 있다. 방법이 안전하다. 위의 예제는 ':id' 인자이다.

query.setParameter("id", 1); ':id' 대신 숫자 1 넣는다. 만약 문자열이었다면 "문자열" 설정되었을 것이다.

 

 

 

 

명시적으로 반환 테이블 지정

                query = session.createQuery("SELECT sdt FROM Student sdt");

                resultList = query.getResultList();

                for(Student st : (List<Student>)resultList)

                {

                        System.out.println("-----------------");

                        System.out.println("id="+st.getId());

                        System.out.println("name="+st.getName());

                        System.out.println("birthday="+st.getBirthday());

                

                }

Hibernate: select student0_.ID as ID1_10_, student0_.BIRTHDAY as BIRTHDAY2_10_, student0_.NAME as NAME3_10_ from Student student0_

-----------------

id=1

name=Mark

birthday=1997-02-02 00:00:00.0

-----------------

id=2

name=Jane

birthday=1990-10-10 00:00:00.0

-----------------

id=3

name=Jone

birthday=1960-11-11 00:00:00.0

 

 

 

 

여러 테이블 Join 결과 클래스로 맵핑하기

SELECT 보면 테이블의 alias 값을 넣었다. 이러면 해당 테이블 전체를 말하며 맵핑 클래스로 값이 할당되어 클래스 자체가 반환된다.

                query = session.createQuery("SELECT sdt,sc,cr FROM Student sdt INNER JOIN Score sc ON sdt.id = sc.id.student_id INNER JOIN Course cr ON sc.id.course_id = cr.id ");

                resultList = query.getResultList();

                for(Object[] values : (List<Object[]>)resultList)

                {

                        

                        System.out.println("--------types---------");

                        for(Object o : values)

                        {

                                System.out.println("type = "+o.getClass().getTypeName());

                        }

                }

                for(Object[] values : (List<Object[]>)resultList)

                {

                        Student student = (Student)values[0];

                        Score score = (Score)values[1];

                        Course course = (Course)values[2];

                        System.out.print("name="+student.getName());

                        System.out.print(" course="+course.getName());

                        System.out.print(" score="+score.getScore());

                        System.out.println();

                }

 

Hibernate: select student0_.ID as ID1_10_0_, score1_.COURSE_ID as COURSE_I1_9_1_, score1_.STUDENT_ID as STUDENT_2_9_1_, course2_.ID as ID1_3_2_, student0_.BIRTHDAY as BIRTHDAY2_10_0_, student0_.NAME as NAME3_10_0_, score1_.SCORE as SCORE3_9_1_, course2_.COURSE_NAME as COURSE_N2_3_2_ from Student student0_ inner join Score score1_ on (student0_.ID=score1_.STUDENT_ID) inner join Course course2_ on (score1_.COURSE_ID=course2_.ID)

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------types---------

type = org.onecellboy.db.hibernate.table.Student

type = org.onecellboy.db.hibernate.table.Score

type = org.onecellboy.db.hibernate.table.Course

--------Data---------

name=Mark course=Science score=70

name=Mark course=Math score=50

name=Mark course=English score=64

name=Jane course=Science score=10

name=Jane course=Math score=32

name=Jane course=Music score=15

name=Jone course=English score=99

 

 

 

 

 

 

일반 클래스에 결과값 맵핑하기

 

아래는 일반 클래스인 NotMappingStudent라는 클래스의 생성자에 결과 컬럼들을 인자로 사용하여 생성하는 예제이다.

 

public class NotMappingStudent {

        private int id;

        private String name;

        private Date birthday;

        

        

        public NotMappingStudent(int id, String name, Date birthday)

        {

                this.id=id;

                this.name=name;

                this.birthday=birthday;

        }
(생략...)

 

 

 

클래스명만 쓰면 정확한 클래스를 모르므로 패키지명까지 써야한다.(org.onecellboy.db.hibernate.table.NotMappingStudent)

                query = session.createQuery("SELECT NEW org.onecellboy.db.hibernate.table.NotMappingStudent(sdt.id, sdt.name, sdt.birthday) FROM Student sdt");

                List<NotMappingStudent> notMaps=(List<NotMappingStudent>)query.getResultList();

                

                for(NotMappingStudent notMap : notMaps)

                {

                        System.out.println("-----------------");

                        System.out.println("id="+notMap.getId());

                        System.out.println("name="+notMap.getName());

                        System.out.println("birthday="+notMap.getBirthday());

                

                }

Hibernate: select student0_.ID as col_0_0_, student0_.NAME as col_1_0_, student0_.BIRTHDAY as col_2_0_ from Student student0_

-----------------

id=1

name=Mark

birthday=1997-02-02 00:00:00.0

-----------------

id=2

name=Jane

birthday=1990-10-10 00:00:00.0

-----------------

id=3

name=Jone

birthday=1960-11-11 00:00:00.0

 

 

 

 

 

특정 컬럼만 선택하고 순서주기(Object[] 결과받기)

특정 컬럼만 선택하게 되면 클래스로 반환되는 것이 아니라 컬럼에 맞는 형태의 변수로 변환된다. 예를들어 varchar 값은 String으로 int값은 Integer 변환된다.

                query = session.createQuery("SELECT sdt.id, sdt.name FROM Student sdt ORDER BY sdt.name");

                resultList = query.getResultList();

                for(Object[] values : (List<Object[]>)resultList)

                {

                        

                        System.out.println("--------types---------");

                        for(Object o : values)

                        {

                                System.out.println("type = "+o.getClass().getTypeName());

                        }

                }

                

                for(Object[] values : (List<Object[]>)resultList)

                {

                        

                        System.out.println("-----------------");

                        System.out.println("id="+(Integer)values[0]);

                        System.out.println("name="+(String)values[1]);

                        

                }

Hibernate: select student0_.ID as col_0_0_, student0_.NAME as col_1_0_ from Student student0_

--------types---------

type = java.lang.Integer

type = java.lang.String

--------types---------

type = java.lang.Integer

type = java.lang.String

--------types---------

type = java.lang.Integer

type = java.lang.String

-----------------

id=2

name=Jane

-----------------

id=3

name=Jone

-----------------

id=1

name=Mark

 

 

 

 

패키지명까지 명시적으로 지정

org.onecellboy.db.hibernate.table.Student 이런식으로 패키지명까지 명시적으로 적었다. 맵핑 클래스명이 중복되는 것이 있을   방법이 명확하게 알려준다. 보통은 이름이 중복되게 않게 만드는 것이 좋다.

                query = session.createQuery("SELECT sdt.id, sdt.name FROM org.onecellboy.db.hibernate.table.Student sdt WHERE sdt.id = :id");

                query.setParameter("id", 1);

                resultList = query.getResultList();

                for(Object[] values : (List<Object[]>)resultList)

                {

                        

                        System.out.println("--------types---------");

                        for(Object o : values)

                        {

                                System.out.println("type = "+o.getClass().getTypeName());

                        }

                }

                

                for(Object[] values : (List<Object[]>)resultList)

                {

                        

                        System.out.println("-----------------");

                        System.out.println("id="+(Integer)values[0]);

                        System.out.println("name="+(String)values[1]);

                        

                }

Hibernate: select student0_.ID as col_0_0_, student0_.NAME as col_1_0_ from Student student0_ where student0_.ID=?

--------types---------

type = java.lang.Integer

type = java.lang.String

-----------------

id=1

name=Mark

 

 

 

 

그룹함수 사용하기(결과가 하나일 경우는 getSingleResult() Object 반환)

                query = session.createQuery("SELECT count(sdt.id) FROM Student sdt");

                Object singleResult = query.getSingleResult();

                Long count = (Long)singleResult;

                System.out.println("Student count()="+count);

Hibernate: select count(student0_.ID) as col_0_0_ from Student student0_

Student count()=3

 

 

 

2개의 반환시 getSingleResult() Object[] 반환

                query = session.createQuery("SELECT count(sdt.id), count(sdt.id) FROM Student sdt");

                Object[] result = (Object[])query.getSingleResult();

                Long count1 = (Long)result[0];

                Long count2 = (Long)result[1];

                System.out.println("Student count()="+count1);

                System.out.println("Student count()="+count2);

Hibernate: select count(student0_.ID) as col_0_0_, count(student0_.ID) as col_1_0_ from Student student0_

Student count()=3

Student count()=3

 

 

 

 

 

 

 

 

HQL UPDATE 예제

딱히 설명 없음

        Query query = session.createQuery("UPDATE FROM Student SET name = :name WHERE id = :id ");

        query.setParameter("id", 1);

        query.setParameter("name", "Guest");

        int affectedCount = query.executeUpdate();

        System.out.println("row affected : ="+affectedCount);        

Hibernate: update Student set NAME=? where ID=?

row affected : =1

 

 

 

 

HQL INSERT 예제

HQL 경우는 하나의 ROW 직접 추가하는 방법이 없다.

Hibernate 맵핑 클래스를 통해 INSERT하라고 강제하는 듯하다.

INSERT 경우 다른 테이블 데이터들을 테이블로 대량 INSERT 있게만 했다.

 

INSERT INTO table(a,b) VALUES(1,2)

이런 문법은 통하지 않는다. VALUES 키워드에서 에러를 뿜는다.

 

아래의 이런 문법만 통한다.

INSERT INTO table(a,b) SELECT c,d FROM otherTable

 

 

예를 들어

query = session.createQuery("INSERT INTO Student (id,name,birthday)  Select (a.id)+99,a.name,a.birthday from Student a");

 

affectedCount = query.executeUpdate();

 


반응형