hibernate의 HQL을 알아보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package com.zest.hibernate.chapter10.crud; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.Table; @Entity @Table(name="USER_DETAILS") public class UserDetails { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int userId; private String userName; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } } | cs |
위와 같은 테이블을 생성한다.
먼저 데이터를 insert 한다. 이 부분은 기존에 만들어 놓은 코드를 조금 수정해서 insert를 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @Test public void insertTest() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); for (int i = 0; i < 10; i++) { UserDetails user = new UserDetails(); user.setUserName("user " + i); session.save(user); } session.getTransaction().commit(); // session.close(); } | cs |
user0, user1 ........... 이런 user를 총 10개를 만들었다. 그럼 기존에 사용했던 방식으로 select의 결과물을 가져와보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Test public void getTest() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. // new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); UserDetails user = (UserDetails) session.get(UserDetails.class, 6); System.out.println("name\t"+user.getUserName()); session.getTransaction().commit(); // session.close(); } | cs |
session.get이라는 함수를 통해 파라미터로 어느 테이블(객체), 기본키를 넣어서 값을 가져오는 예제이다.
그럼 hql를 해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @Test public void hsqlTest1() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. // new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); //hibernate 용으로. Query query= session.createQuery("from UserDetails"); List users = query.list(); session.getTransaction().commit(); // session.close(); System.out.println("list size==>"+users.size()); } | cs |
위의 내용은 전체 리스트를 가져오는 예제이다. 이때 중요한 메소드는 createQuery라는 메소드인데 이 뒤는 sql문과 매우 흡사하다. 여기서 중요한 점은 UserDetails는 table명이 아니라 객체 라는 점이다. jpa에서는 jpa ql 이라는 것과 거의 비슷하게 맵핑이 될것이다.
한개더 예제를 해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @Test public void hsqlWhereTest() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. // new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); //hibernate 용으로. Query query= session.createQuery("from UserDetails where userId >5"); List users = query.list(); session.getTransaction().commit(); // session.close(); System.out.println("list size==>"+users.size()); } | cs |
위의 예제는 where절이 추가 되었으며 마찬가지로 UserDetails의 멤버 변수의 값을 5보다 큰 값을 가져오는 예제이다.
이번엔 게시판 또는 그리드에서 많이 쓰는 paging에 대해 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @Test public void hsqlpageingTest2() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. // new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); //hibernate 용으로. Query query= session.createQuery("from UserDetails "); //시작 row를 설정. query.setFirstResult(5); //결과 개수 query.setMaxResults(4); List<UserDetails> users = (List<UserDetails>)query.list(); session.getTransaction().commit(); // session.close(); for(UserDetails u : users){ System.out.println(u.getUserName()); } } | cs |
setFirstResult 메소드와 setMaxResults가 추가 되었다. 이 메소드를 이용해 paging을 쉽게 구현할 것이다.
이번엔 preparedstatement와 비슷한 binding에 대해 알아보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @Test public void hsqlBindingTest2() { // hibernate의 persitst를 위한 클래스 AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(UserDetails.class); // db 접속 정보들을 저장. config.configure("hibernate.cfg.xml"); // db 접속후 여러개의 테이블을 자동으로 제너레이트 해주는 객체. // <property name="hibernate.default_schema">TESTSCHEMA</property> 이구문역시 // 마찬가지임. // new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); String minUserId= "5"; //hibernate 용으로. Query query= session.createQuery("from UserDetails where userId > ?"); query.setInteger(0, Integer.parseInt(minUserId)); List<UserDetails> users = (List<UserDetails>)query.list(); session.getTransaction().commit(); // session.close(); for(UserDetails u : users){ System.out.println(u.getUserName()); } } | cs |
hql에 ? 라는 바인딩 변수가 있다. 이 값을 setInteger로 바인딩 하는 메소드를 추가하고 리스트를 가져오는 예제이다. preparedstatement와 매우 흡사하다.
여기까지 하이버네이트는 끝낸다.
모든 예제는 https://github.com/zest133/hibernateTest.git 에서 있다.
다대다에 대해서 알아보자.
바로 소스 공개...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | package com.zest.hibernate.chapter8.manytomanymapping; import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Delegate { private int delegateId; private String delegateName; private List<Event> events = new ArrayList<Event>(); @Id @GeneratedValue public int getDelegateId() { return delegateId; } public void setDelegateId(int delegateId) { this.delegateId = delegateId; } public String getDelegateName() { return delegateName; } public void setDelegateName(String delegateName) { this.delegateName = delegateName; } // 결과를 담을 테이블명을 정의 . @ManyToMany @JoinTable(name = "JOIN_DELEGATE_EVENT", joinColumns = { @JoinColumn(name = "delegateId") }, inverseJoinColumns = { @JoinColumn(name = "eventId") } ) public List<Event> getEvents() { return events; } public void setEvents(List<Event> events) { this.events = events; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.zest.hibernate.chapter8.manytomanymapping; import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Event { private int eventId; private String eventName; private List<Delegate> delegates = new ArrayList<Delegate>(); @Id @GeneratedValue public int getEventId() { return eventId; } public void setEventId(int eventId) { this.eventId = eventId; } public String getEventName() { return eventName; } public void setEventName(String eventName) { this.eventName = eventName; } @ManyToMany @JoinTable(name = "JOIN_DELEGATE_EVENT", joinColumns = { @JoinColumn(name = "eventId") }, inverseJoinColumns = { @JoinColumn(name = "delegateId") }) public List<Delegate> getDelegates() { return delegates; } public void setDelegates(List<Delegate> delegates) { this.delegates = delegates; } } | cs |
두개의 객체를 선언하였다. 여기도 마찬가지로 새로운 어노테이션이 등장한다.
@ManyToMany 이다. 그리고 JoinColumn이 아닌 JoinTable이다.
@ManyToMany는 두개의 객체 두군데 다 선언을 한다. 그리고 필연적으로 @JoinTable을 사용해야한다. 각 속성을 알아보자. name은 m:n에 대한 데이터를 저장하는 테이블 이며, jonColumns와 inverseJoinColumkns가 존재한다. joinColumns는 join이 되는 컬럼 여기선 상호간의 컬럼 아이디를 써준다.
결과 쿼리를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Delegate (delegateName, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.Event (eventName, eventId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) Hibernate: insert into TESTSCHEMA.JOIN_DELEGATE_EVENT (eventId, delegateId) values (?, ?) | cs |
JOIN_DELEGATE_EVENT 테이블 생성되며 각 각의 정보가 m:n으로 맵핑이 된다.
하이버네이트 모든 코드는 https://github.com/zest133/hibernateTest.git 여기에 저장되어 있다.
이번엔 1:N 관계를 살펴보자.
바로 소스를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.zest.hibernate.chapter7.onetomanymapping; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity public class College { @Id @GeneratedValue private int collegeId; private String collegeName; @OneToMany(targetEntity=Student.class, mappedBy="college" ,cascade= CascadeType.ALL,fetch=FetchType.EAGER) private List<Student> students ; public int getCollegeId() { return collegeId; } public void setCollegeId(int collegeId) { this.collegeId = collegeId; } public String getCollegeName() { return collegeName; } public void setCollegeName(String collegeName) { this.collegeName = collegeName; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.zest.hibernate.chapter7.onetomanymapping; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @Entity public class Student { @Id @GeneratedValue private int studentId; private String studentName; @ManyToOne @JoinColumn(name="college_id") private College college; public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public College getCollege() { return college; } public void setCollege(College college) { this.college = college; } } | cs |
몇가지 새로운 어노테이션이 등장했다. @OneToMany, @ManyToOne
OneToMany가 선언되있는 클래스는 One을 지칭하고 targetEntity는 many가 된다.
mappedBy는 One에 속하는 테이블 명을 써주면 된다.
Student 객체는 ManyToOne을 선언하고 JoinColumn의 컬럼 명을 정의해주면 된다.
그럼 테스트 ㄱㄱ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | package com.zest.hibernate.chapter7.onetomanymapping; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.junit.Test; import com.zest.hibernate.chapter5.inheritancemapping.Module; import com.zest.hibernate.chapter5.inheritancemapping.Project; import com.zest.hibernate.chapter5.inheritancemapping.Task; public class OneToManyTest { @Test public void oneTest(){ AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(College.class); config.addAnnotatedClass(Student.class); config.configure("hibernate.cfg.xml"); new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); College college1 = new College(); college1.setCollegeName("Newyork College"); Student s1 = new Student(); s1.setStudentName("Alex Rod"); Student s2 = new Student(); s2.setStudentName("Linda Berry"); s1.setCollege(college1); s2.setCollege(college1); session.save(college1); session.save(s1); session.save(s2); //session.save(alexdetail); 이건 안함. 카스케이드 라서 session.getTransaction().commit(); } } | cs |
결과는 다음과 같다.
1 2 3 4 | Hibernate: insert into TESTSCHEMA.College (collegeName, collegeId) values (?, ?) Hibernate: insert into TESTSCHEMA.Student (college_id, studentName, studentId) values (?, ?, ?) Hibernate: insert into TESTSCHEMA.Student (college_id, studentName, studentId) values (?, ?, ?) | cs |
예상했던 대로 College_ID는 FK로 셋팅이 된다.