Persistence Framework

MisCaminos·2021년 2월 12일
0

DBMS

목록 보기
5/6

프로그램의 data를 DB에 저장하는 작업을 효율적으로 진행 할 수 있도록 도움을 주는 tool중 하나가 persistence framework이다.

Persistence framework은 database와 application program사이를 연결하는 다소 반복적인 작업들을 자동으로 수행해주는 middleware 역할을 한다. 여러 framework이 존재하는데, 특히 relational DB와 프로그램을 연동할 때 많이 사용되어서 Object-relational mapping(ORM) tool로 활용된다.

ORM tool역할을 하는 persistence framework으로는 Hibernate, MyBatis SQL Maps, Apache Cayenne, Entity Framework, Slick, Java Ultra-Lite Persistence, 등이 있다. 이 framework들은 application program내 객체의 정보들이 DB에 지속적으로 존재할수있도록(i.e. persist할 수 있도록) DB구조에 맞게 mapping하는 역할을 수행한다. 이 mapping 작업을 수행하기 위해 xml파일 또는 metadata annotation이 활용된다.

오늘은 주요 ORM tool중 하나인 Hibernate와 수업시간에 사용해본 MyBatis에 대해 소개하려한다.

Hibernate

가장 많이 사용되는 open source persistence framework로 Hibernate가 있다. Hibernate은 object-oriented domain model과 relational database를 연결하기위해 mapping framework을 제공한다. 주로 Java classes를 database table로, Java data types를 SQL data type으로 mapping한다. Java 프로그램 개발자가 직접 database에서 얻은 result set을 handling하고 Java object로 convert하는 단계를 건너뛸 수 있도록 지원한다.

Hibernate은 direct, persistent database accesses를 high-level object handling function으로 교체하는 방식을 사용하여서 object-relational impedance mismatch 문제들을 처리할 수 있다고한다. 이 mismatch 문제는 object-oriented langauge로 작성된 application program을 RDBMS와 연동시키기위해서 object(또는 class) definition을 relational schema로 정의된 database table과 match시키려할때 발생할 수 있는 기술적 또는 conceptual mismatch 문제이다. (SQL과 같이 low-level data access 언어에서 Java와 같은 high-level language에서 object를 handling하는 기능을 구현 할 수 있도록 하는것같은데... Hibernate에서 object-relational mismatch issue들을 어떻게 완화할 수 있도록 지원하는지 더 찾아봐야겠다.)

Hibernate에서 mapping은 configuration 역할을 하는 xml file또는 Java annotation을 사용하여 구현할 수 있다. classes간의 one-to-many, many-to-many relationship을 생성할 수 있고, reflexive association을 관리해서 하나의 object가 다른 class type의 instances들과 one-to-many relationship을 가지게 할 수 있다. 그래서 아래와 같은 시나리오를 구현할 수 있다:

-property & column을 mapping할때에 default SQL type을 override할 수 있다.
-Java Enums를 columns로 mapping할 수 있다.
-하나의 property를 여러 column들과 mapping할 수 있다.

Hibernate에서는 HQL(Hibernate Query Language) 라는 SQL을 기반으로 만든 쿼리 언어를 사용해서 Hibernate의 data object에 SQL과 비슷한 쿼리문장을 명령할 수 있다.(HQL은 SQL의 object-oriented verion이라고 생각하면된다.) Criteria Queries는 HQL의 object-oriented alternative로 제공되고 이것을 사용해서 object를 modify하거나 object에 restriction을 걸을 수 있다.

Entity는 Hibernate에서 독립적인 object와 같은 역할을 하고, component는 entity의 subordinate으로 관련된 entity의 범위내에서만 manipulate될 수 있다.

Hibernate API는 open source이기때문에 org.hibernate에서 무료로 다운받아서 사용할 수 있다. Hibernate의 configuraion file은 Oracle 또는 MySQL과 같은 RDBMS와의 JDBC connection을 처리한다. session factory를 setup하여 session object를 받아와서 database와의 connection을 생성한다.

그리고 Entity 클래스를 만들어서 database table과의 mapping을 지정한다. 아래 예시에서 작성한것과 같이 annotation을 사용해서 mapping해준다.

예시)

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="employee") 
//entity로 지정하려는 table 이름 "employee"를 명시한다

public class Employee{

 //table안에 column이름과 object property를 match시켜준다
 
 //@Id는 table의 primary key를 뜻한다
 //@GeneratedValue(strategy=GenerationType.IDENTITY)는 id에 어떤 값이 
 //지정되어야하는지를 명시한다. 자동으로 1씩 increment하는것으로 지정.
 @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;
 
 //Hibernate에서 persistence의 requirement로 no-argument constructor가 포함되어야한다
 public Employee(){}
 
 public Employee(String firstName, String lastName, String email) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.email = email;
 }
 
 //그리고 각 변수의 getter(), setter(), overridden toString()을 추가로 정의한다

}

(example with contents modified from Amrut of Medium)

Database에 새로운 record를 입력하기위해서는 다음과 같이 3가지 step을 진행한다.

  1. session factory를 생성한다. Hibernate configuration file과 entity class를 아래 코드와 같이 명시한다.
SessionFactory sessionFactory = new Configuration().configure(“hibernate.cfg.xml”).addAnnotatedClass(Employee.class).buildSessionFactory();
  1. current session을 받아온다.
Session session = sessionFactory.getCurrentSession();
  1. Employee object를 생성하고 database에 저장한다.
//create the Employee object
Employee employee = new Employee("Paul", "Walker","paul.walker@gmail.com");
//start a transaction
session.beginTransaction();
//Save the Employee object to the database
session.save(employee);
//commit the transaction
session.getTransaction().commit();

Database에서 read, update, delete과 같은 작업을 하기위해서는 위와 동일하게 session factory를 생성하고 current session에서 beginTransaction() 메소드를 호출해서 database의 data를 access할수있는 연결을 형성한다.

data를 read 하기위해서는, 다음과 같이 코드를 구현한다.

//Read the employee
//specify PRIMARY KEY of the employee
Employee readEmployee = session.get(Employee.class, employee.getId());

//commit the transaction
session.getTransaction().commit();

HQL(Hibernate Query Language)를 사용해서 data를 update할수 있다.

//update email for all employees
int rowsUpdated = session.createQuery(“update Employee set email=’hiberate@gmail.com’”).executeUpdate();

System.out.println(“Rows updated : “ + rowsUpdated); //update된 row수 출력
session.getTransaction().commit();

아래 syntax와 같이 createQuery()안에 HQL문장을 넣으면된다.

session.createQuery(“<your HQL update query>”).executeUpdate()

MyBatis

MyBatis도 Hibernate와 동일하게 Java 프로그램과 RDBMS를 연결시켜주는 middleware 역할을 한다. xml파일을 사용 할수도 있고, annotation을 통해 더 간단하게 코드를 작성할수도 있다. MyBatis API를 사용하여 지정한 configuration 방식을 적용하면 이 tool이 자동으로 Java object의 properties와 DB table을 연결시켜서 원하는 SQL 질의를 결과를 얻을 수 있다.

먼저 MyBatis를 사용하려면 mybatis-x.x.x.jar 파일이 개발하려는 프로그램의 classpath에 포함되어야한다. (MyBatis는 open source이기때문에 MyBatis 팀에서 운영하는 gitihub repository에서 jar파일을 무료로 다운받을 수 있다. Releases · mybatis/mybatis-3 (github.com)) 다운받은 MyBatis jar파일을 Java Project의 library에 추가한다.

Java project의 src(source code) folder에는 각 vo의 dao 메소드를 선언한 Mapper interface, SqlSession 객체를 생성해서 Mapper 클래스의 dao기능을 사용하고 외부로 기능을 제공하는 Service클래스, mapping에서 사용되는 matching의 기준을 지정하는 xml mapping files, 그리고 SqlSessionFactory 객체를 생성하는 클래스와 이 클래스에서 resource로 활용할 configuration xml 파일이 추가된다.

여기에서 xml mapping file이 Java 객체와 DB table을 matching할 수 있도록 기준을 define하는것이 주요 포인트이다. 먼저 mapper의 namespace를 Mapper interface로 지정해서 어떤 vo의 dao기능이 선언된 interface의 메소드를 구현하는데에 이 mapper xml이 활용될지를 지정한다.

그리고 resultMap 태그를 지정해준다. JDBC를 사용했을때에 PreparedStatement 객체를 통해 Java에서 SQL 질의를 작성하고 Resultset에 DB table정보를 담아온것과 비슷하게 xml에서는 resultMap을 사용한다. resultMap의 type에는 vo 객체 클래스의 full name을 지정하고 id에는 resultMap을 가리킬 이름을 지어준다. 그리고 resultMap내에서 result의 property에는 객체의 변수를, column에는 matching할 DB table의 column명을 지정해준다. Data access 작업결과를 자동으로 vo로 변환하기위해 필요한 정보가 define된것이다.

그리고 data access 작업의 기준을 지정해준다. 태그를 사용하여 SQL 질의 문장을 넣는다. 각 태그의 id를 mapper interface에서 선언한 method이름과 동일하게 지정해서 dao 메소드가 Java코드로 직접 구현되지않아도 resultMap에서 정의한 property와 column의 기준에 따라서 SQL질의 문장의 결과물을 얻을 수 있다.

이후 Service 클래스에서 Sqlsession을 통해 Mapper 클래스의 객체를 얻고, 이 Mapper 객체를 통해 Mapper interface에서 선언한 method를 호출하여 SQL 질의의 결과를 반환받는다. 외부에서는 Service class에서 정의한 메소드를 호출해서 원하는 DB작업을 할 수 있는 것이다.

각 vo 객체와 DB를 연결시켜주는 Mapper역할의 xml파일을 제외하고 @insert, select, update, delete와 같이 Mapper 클래스에서 annotation을 넣어서 코드를 더 단순화하는 방법도 있다. 기존 xml을 사용하는 방식에서는 configuration xml파일에 mapper xml 경로를 mapper resource로 포함해야했지만, annotation 방식에서는 mapper가 포함되지 않는다. mapper xml파일을 사용하지않아도 직접 annotation을 사용하여 Mapper interface에서 어떤 SQL 질의를 진행할 것이고, 어떤 SQL 문장을 DBMS와 소통 할 것인지를 지정하기때문이다. 그래서 interface에서 원래 선언되었던 각 dao 메소드의 이름, 매개변수, 반환타입 외에도 mapper xml에 포함되었던 SQL 질의 종류와 (insert, select, update, or delete) SQL 문장이 모두 interface에서 정의되는 것이다.

이 방식에서 주의할 점은 기존 mapper xml파일에서 정의한 resultMap을 건너뛰기때문에 DB table의 column이름과 Java 프로그램의 vo 객체의 변수이름이 동일해야하고 객체의 생성자의 매개변수의 순서가 column순서와 동일해야한다. 알아서 순서대로 동일한 이름을 matching 시켜주기때문이다.

References:
1. Persistence Framework from Wikipedia
2. What is Persistence Framework from Rose India
3. What is ORM and Why You Should Use it? by Mario Hoyo from Medium
4. Hibernate from Wikipedia
5. Reference Documentation from MyBatis.org
6. CRUD with Java, Hibernate and MySQL - Part3 by Amrut from Medium
7. Hibernate and MyBatis coexist from Programmer Sought

profile
Learning to code and analyze data

0개의 댓글