Spring

Spring Framework - CRUD Using Hibernate ORM

728x90

참조한 강의 : 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(11NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45DEFAULT NULL,
  `last_name` varchar(45DEFAULT NULL,
  `email` varchar(45DEFAULT 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

 

Generate Tables from Entity classes in Hibernate

In this document I will guide you to create tables from the entity classes, on any database (Oracle, MySQL, SQL Server, ..). The tables created will have full of constraints as designated by the Entity classes. Take note of that Hibernate is created to wor

o7planning.org

(개인적인 생각으론 sql 파일 만들어서 자바에서 이 파일을 읽은 뒤, 테이블 생성하느니 차라리 그냥 DB 서버에 직접 가서 SQL 문 쳐주는게 나은것 같다)

 

 

 

* 참고2)

DB 테이블에서 자바로 Entity Class 를 생성하는게 가능한가?

: 가능하다, 아래의 링크에 가면 자세히 설명되어 있다.

o7planning.org/10125/use-hibernate-tools-to-generate-entity-classes-from-tables

 

Use Hibernate Tools to generate Entity classes from Tables

The first we must be make sure you have make sure that installed "Hibernate Tools" on Eclipse. "Hibernate Tools" is one tool in the tools of JBoss -. "JBoss Tools". The database used to illustrate in this tutorial is "simplehr". You can refer to: In this t

o7planning.org

 

 

* 참고3)

Hibernate ORM 을 사용해서 DB 와 작업을 수행할때, 이클립스 콘솔창을 보면, 결과물들이 ? 형식으로 뭔가 많이 생략되어 있음을 볼 수 있다.

이를 생략된 부분없이 자세한 로그를 보고 싶으면 다음의 과정을 거치면 된다.

 

1) 먼저 아래의 사이트에 가서 log4j 를 받아야한다

logging.apache.org/log4j/1.2/download.html

 

Apache log4j 1.2 - Download Apache log4j 1.2

Log4j 2 is nominated for the JAX Innovation Awards! Do you like its performance, garbage-free logging, and easy and flexible configuration? Log4j 2 needs your love. Vote for Log4j 2! End of Life On August 5, 2015 the Logging Services Project Management Com

logging.apache.org

압축을 풀고 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

 

Transactions with Spring and JPA | Baeldung

How to best set up Transactions in Spring - the configuration, Transaction Propagation and which layer should have Transactional Semantics.

www.baeldung.com

 

 

 

여기까지 Hibernate ORM 을 통해서 아주 기본적인 CRUD 를 하는 방법에 대해서 알아봤다.

다음은 Hibernate 를 통해서 관계 매핑하는 방법에 대해 알아본다.

728x90

'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