참조한 강의 : Spring & Hibernate For Beginners (www.udemy.com/course/spring-hibernate-tutorial/)
이번에는, Hibernate ORM 을 이용해서 간단하게 CRUD (Create, Read, Update, Delete) 를 하는 방법에 대해 알아본다.
먼저 사용할 DB (여기선 MySQL) 에 Student 테이블을 만들어준다
- SQL
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) DEFAULT NULL,
`last_name` varchar(45) DEFAULT NULL,
`email` varchar(45) DEFAULT NULL,
`date_of_birth` DATETIME,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
|
cs |
1) C : Create
먼저 Entity Class 인 Student.java 를 다음과 같이 만든다
- Student.java
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;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.luv2code.hibernate.demo.DateUtils;
@Entity
@Table(name="student")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="email")
private String email;
@Column(name="date_of_birth")
@Temporal(TemporalType.DATE)
private Date dateOfBirth;
public Student() {}
public Student(String firstName, String lastName, String email, Date dateOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.dateOfBirth = dateOfBirth;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
@Override
public String toString() {
return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "dateOfBirth" + DateUtils.formatDate(dateOfBirth) + "]";
}
}
|
cs |
참고) Hibernate ORM 에서 Date 타입을 다룰때
: Date 타입을 다루기 위해서는, 별도의 타입 변환 객체가 있어야한다.
- DateUtils.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
private static SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
public static Date parseDate(String dateStr) throws ParseException {
Date theDate = formatter.parse(dateStr);
return theDate;
}
public static String formatDate(Date theDate) {
String result = null;
if (theDate != null) result = formatter.format(theDate);
return result;
}
}
|
cs |
위와 같이 SimpleDateFormat 객체로, 날짜 타입을 지정해주고,
파싱하는 함수, 포맷하는 함수를 각각 만들어줘야한다.
이제, Student 테이블에 행을 추가해주기 위해서 Create 객체를 만들어주자
- CreateStudentDemo.java
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
public class CreateStudentDemo {
public static void main(String[] args) {
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
Session session = factory.getCurrentSession();
try {
// create a student object
System.out.println("Creating new student");
String theDateOfBirthStr = "31/12/1998";
Date theDateOfBirth = DateUtils.parseDate(theDateOfBirthStr);
Student theStudent = new Student("Dalphi", "allen", "papa@gmail.com", theDateOfBirth);
// start a transaction
session.beginTransaction();
// save the student object
session.save(theStudent);
// commit transaction
session.getTransaction().commit();
System.out.println("Well Done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
factory.close();
}
}
}
|
cs |
Create 할때 순서는 이렇게 진행된다
1. SessionFactory 객체를 만든다
2. 추가할 객체 인스턴스를 만든다
3. Session 객체를 SessionFactory 에서 얻어온다.
4. Session 객체에서 트랜잭션을 할 준비를 한다.
5. create 의 경우 save 함수를 이용해서 세션에 해당 객체를 저장한다
6. 트랜잭션을 커밋한다.
2) R : Read
DB 로 부터 Hibernate ORM 을 통해 데이터를 읽어오는 작업을 해보자
읽어오는 방법은 두가지가 있다
첫번째로, 기본키(PK) 를 이용해서 특정한 행을 읽어온다.
두번째로 HQL(Hibernate Query Language)
먼저 기본키를 통해서 읽어오는 코드이다.
- ReadStudentDemo.java
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
public class ReadStudentDemo {
public static void main(String[] args) {
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
Session session = factory.getCurrentSession();
try {
// create a student object
System.out.println("Creating new student");
String dateOfBirthStr = "06/10/2002";
Date dateOfBirth = DateUtils.parseDate(dateOfBirthStr);
Student theStudent = new Student("thomas", "rivest", "bellmanford@algo.com", dateOfBirth);
// start a transaction
session.beginTransaction();
// save the student object
session.save(theStudent);
// commit transaction
session.getTransaction().commit();
// find out the student's primary key
System.out.println("Saved Student, The student's id : " + theStudent.getId());
// now get a new session and start transaction
session = factory.getCurrentSession(); // 항상 새로운 트랜잭션 사용시 새로운 세션을 꼭 만들어야함.
session.beginTransaction();
// retrieve student based on primary key
System.out.println("\n Getting student id : " + theStudent.getId());
Student myStudent = session.get(Student.class, theStudent.getId());
System.out.println("\n Get Complete : " + myStudent);
// commit the transaction
session.getTransaction().commit();
System.out.println("Well Done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
factory.close();
}
}
}
|
cs |
위 코드를 보면 알겠지만, DB 에 저장할 값을 만들고 그 값을 읽어오는 예제이다.
기본키로부터 데이터를 얻어오려면 session.get() 을 써야함을 알 수 있다.
(나머지 부분은 Create 와 똑같음)
다음은 HQL 로 읽어오는 방법을 알아보자
이번에는 단순히 한명만 읽어오는게 아니라, 여러가지 조건을 넣어서 다채롭게 읽어오는 방법을 알아보자
- QueryStudentDemo.java
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
//import com.luv2code.hibernate.demo.entity.Subject;
public class QueryStudentDemo {
public static void main(String[] args) {
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
Session session = factory.getCurrentSession();
try {
// create a student object
System.out.println("Creating new student");
// start a transaction
session.beginTransaction();
// query all students
List<Student> theStudents = session.createQuery("from Student").getResultList();
displayStudents(theStudents);
// query specific student
theStudents = session.createQuery("from Student s where s.lastName='sung'").getResultList();
System.out.println("");
displayStudents(theStudents);
// query student : lastName = sung OR firstName = lexa
theStudents = session.createQuery("from Student s where s.lastName='sung' OR firstName='lexa'").getResultList();
System.out.println();
displayStudents(theStudents);
theStudents = session.createQuery("from Student s where s.email LIKE '%algo.com'").getResultList();
System.out.println();
displayStudents(theStudents);
// commit transaction
session.getTransaction().commit();
System.out.println("Well Done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
factory.close();
}
}
private static void displayStudents(List<Student> theStudents) {
// display all students
for (Student tempStudent : theStudents) {
System.out.println(tempStudent);
}
}
}
|
cs |
위 코드에서 첫번째로 조회하는 28번줄은
1
|
List<Student> theStudents = session.createQuery("from Student").getResultList();
|
cs |
SQL 에서
SELECT * FROM student 와 동일하다.
- (참고) 테이블에 지정된 이름은 student 인데 왜 Student 를 사용했는가?
: HQL 을 사용할때, 테이블 이름과 칼럼명은, DB 에 저장된 네이밍을 따르는게 아니라,
Entity Class 에 정의해둔 클래스명, 필드명을 따라감
그래서 student 가 아니라, Student 를 사용했고, 이름 부분도 last_name 이 아니라, lastName 으로 되어 있음.
위 코드에서 두번째로 조회하는 33번줄은
1
|
theStudents = session.createQuery("from Student s where s.lastName='sung'").getResultList();
|
cs |
SQL 에서
SELECT * FROM student WHERE last_name='sung' 과 같다
위에서 s 는 Alias 를 의미한다.
나머지 두개도 SQL 문법만 약간 다른것이므로 생략함.
3) U : Update
: 다음은 DB 의 데이터를 수정하는 Update 를 해본다.
- UpdateStudentDemo.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
//import com.luv2code.hibernate.demo.entity.Subject;
public class UpdateStudentDemo {
public static void main(String[] args) {
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
try {
int studentId = 1;
Session session = factory.getCurrentSession();
// start a transaction
session.beginTransaction();
// update row using primary key
Student tempStudent = session.get(Student.class, studentId);
System.out.println("Get tempStudent : " + tempStudent);
System.out.println("Updating tempStudent's firstName");
tempStudent.setFirstName("Spring"); // JVM 에서만 데이터를 바꾼것
// commit transaction
session.getTransaction().commit(); // 여기까지와야 DB 에 데이터값을 바꾸는것
// update row using HQL
session = factory.getCurrentSession();
session.beginTransaction();
System.out.println("Updates the email of a student whose firstName is lee");
session.createQuery("update Student set email='update@gmail.com' where firstName='lee'").executeUpdate();
session.getTransaction().commit();
System.out.println("Well Done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
factory.close();
}
}
}
|
cs |
Update 도 Read 와 마찬가지로, 기본키로 수정할 데이터를 찾아내던가 아니면, HQL 을 쓰면된다.
다만 기본키로 수정할때, setter method 를 통해서 수정해야된다는 것 정도만 다르다.
나머진 Read 와 똑같음
4) D : Delete
: 이번엔 특정 데이터를 DB 에서 지우는 것을 해본다.
Delete 도 Read 와 Update 처럼 직접 기본키를 지정해줘서 삭제하던가 아니면 HQL 을 쓰면된다.
- DeleteStudentDemo.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
//import com.luv2code.hibernate.demo.entity.Subject;
public class DeleteStudentDemo {
public static void main(String[] args) {
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
try {
int studentId = 1;
Session session = factory.getCurrentSession();
// start a transaction
session.beginTransaction();
// delete row using primary key
Student tempStudent = session.get(Student.class, studentId);
System.out.println("Get tempStudent : " + tempStudent);
System.out.println("Deleting tempStudent's firstName");
session.delete(tempStudent);
// commit transaction
session.getTransaction().commit();
session.beginTransaction();
System.out.println("Delete student who has id that equals 3");
session.createQuery("delete from Student where id=3").executeUpdate();
session.getTransaction().commit();
System.out.println("Well Done!");
} catch (Exception e) {
e.printStackTrace();
} finally {
factory.close();
}
}
}
|
cs |
* 참고)
SQL 로 테이블 생성하는것 말고, Hibernate ORM 으로 DB 테이블 생성이 가능한가?
: Hibernate 만으로는 불가능하다.
대신에, sql 파일을 자바에서 읽어들여서 테이블을 만드는 방법은 가능하다.
o7planning.org/11223/generate-tables-from-entity-classes-in-hibernate
(개인적인 생각으론 sql 파일 만들어서 자바에서 이 파일을 읽은 뒤, 테이블 생성하느니 차라리 그냥 DB 서버에 직접 가서 SQL 문 쳐주는게 나은것 같다)
* 참고2)
DB 테이블에서 자바로 Entity Class 를 생성하는게 가능한가?
: 가능하다, 아래의 링크에 가면 자세히 설명되어 있다.
o7planning.org/10125/use-hibernate-tools-to-generate-entity-classes-from-tables
* 참고3)
Hibernate ORM 을 사용해서 DB 와 작업을 수행할때, 이클립스 콘솔창을 보면, 결과물들이 ? 형식으로 뭔가 많이 생략되어 있음을 볼 수 있다.
이를 생략된 부분없이 자세한 로그를 보고 싶으면 다음의 과정을 거치면 된다.
1) 먼저 아래의 사이트에 가서 log4j 를 받아야한다
logging.apache.org/log4j/1.2/download.html
압축을 풀고 log4j-1.2.17 JAR 파일이 존재하는데, 이 파일을 사용하는 이클립스 프로젝트의 lib 폴더에 넣어주고, 프로젝트 속성에 가서 classpath 를 추가해줘야한다.
2) log4j.properties 파일을 만들어준다
- log4j.properties
# Root logger option
log4j.rootLogger=DEBUG, stdout
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.logger.org.hibernate=TRACE
|
cs |
여기서 중요한 것은
첫번째 log4j.properties 파일이 프로젝트의 src 폴더에 있어야 한다는것
두번째 log4j.logger.org.hibernate=TRACE 코드 부분의 의미가 hibernate 가 수행하는 low-level 부분과 로그 창에서 숨겨진 ? 로된 부분을 보여준다는것 이다.
* 참고4)
위의 예제에서는 트랜잭션의 시작과 끝을 프로그래머가 직접 명시를 해줬는데, 이렇게 일일이 명시하지 않아도 @Transactional 이라는 어노테이션을 쓰면 처리가 가능해진다.
(아래 사이트에 자세한 사용법이 나와있다)
www.baeldung.com/transaction-configuration-with-jpa-and-spring
여기까지 Hibernate ORM 을 통해서 아주 기본적인 CRUD 를 하는 방법에 대해서 알아봤다.
다음은 Hibernate 를 통해서 관계 매핑하는 방법에 대해 알아본다.
'Spring' 카테고리의 다른 글
Spring Framework - Eager, Lazy Loading (0) | 2021.02.11 |
---|---|
Spring Framework - Persistence Context (0) | 2021.02.06 |
Spring Framework - Hibernate ORM (0) | 2021.02.02 |
Spring Framework - Validation (0) | 2021.02.01 |
Spring Framework - Spring MVC Form Tag (0) | 2021.01.28 |