orm을 맞이하는 우리의 자세

Post on 12-Apr-2017

1.698 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ORM 을 맞이하는 우리의 자세

정병태

랑겔한스 : 정병태

- Web Developer

- OKKY.KR Contributor

- https://github.com/1angerhans - http://okky.kr/user/info/26138 - btjung@ebrain.kr

‘나는 SQL 이 싫어요.’

ORMObject Relational Mapping

– Wikipedia 인용

“Object-relational mapping (ORM, O/RM, and O/R mapping) in computer science is a programming technique for converting data between

incompatible type systems in object-oriented programming languages.”

– Wikipedia 인용

“객체 관계 매핑(Object-relational mapping; ORM)은 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다.”

Object-relational impedance mismatch

- Data type differences - Structural and integrity differences - Manipulative difference - Transactional differences

https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch

문제의 해결 Without ORM

현실의 문제 #1

Vo, DTO 그리고 Table들

D.D.DDomain Driven Design

Domain Entity 설계

CREATE TABLE TBL_MSG ( F_GRP_ID INT(6) NOT NULL PRIMARY KEY , PTN_ID INT(6) , PRIORITY INT(6) , JOB_CODE INT(6) , FLAG_PRO INT(6) , CHAINNUM INT(6) , MASSNUM INT(6) , USERID VARCHAR(20) , CPCODE VARCHAR(20) , QTCODE VARCHAR(20) , MSGSEPER CHAR(1) , MSG_CNT INT(6) , CNTPSEC INT(6) ,

흔한 Legacy Table

Minimization

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

AUTH_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

TEL VARCHAR(12) ,

CELL VARCHAR(12) ,

OFFICE_TEL VARCHAR(12) ,

EMAIL VARCHAR(200) ,

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200) ,

COMPANY_NAME VARCHAR(20) ,

QUARTER_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

MILEAGE INT(12) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

User

Contact

Company

Domains

Auth

Mileage

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

public class User { Long seq; String userid; String userpass; String username; Date regDate;

Company company; Address address; Contact contact; Mileage mileage;

List<Auth> authorities;

// Getter & Setter }

public class Company { … }

public class Address { … }

public class Contact { … }

public class Mileage { … }

public class Auth { … }

현실의 문제 #2

DBA

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

DBA 들이 나를 향해 이렇게 외친다.

public class MSG {

int grpnum; int chainnum; String userid; String usernm; String cpcode; String qtcode; String title; String sndTitle; String cComment; String dstaddr; String callback; String msgTemplet; String reservData;

흔한 Legacy Model

Mybatis Association

<select id="selectOne" resultMap=“userMap">

select u.seq, u.userid, u.pass, u.name, u.tel, u.cel, u.email, u.company_name, u.zipcode, u.address_01, u.address_02 …. from tbl_user u where u.seq = #{seq}

</select>

Mybatis

Mybatis Association<resultMap id="userMap" type=“User">

<id jdbcType="INTEGER" property="seq" column="seq"/> <result jdbcType="VARCHAR" property="userid" column="userid"/> <result jdbcType="VARCHAR" property="pass" column="pass"/>

<association property="company" javaType="Company" > <result jdbcType="VARCHAR" property=“company_name" column="cpname"/> </association>

<association property="contact" javaType="Contact" > <result jdbcType="VARCHAR" property=“company_name" column="cpname"/> </association>

<association property="address" javaType="Address" > <result jdbcType="VARCHAR" property=“zopcode" column=“zopcode"/> <result jdbcType="VARCHAR" property=“address_01” column=“address_01"/> <result jdbcType="VARCHAR" property=“address_01” column="address_01"/> </association>

<collection property="authorities" select="selectUserAuthList" fetchType="lazy" column="{seq=seq}" />

</resultMap>

– 미상

“인간의 욕심은 끝이 없고, 같은 실수를 반복한다.”

With ORM

Hibernate

@Entity@Table( name = “TBL_USER" )public class User { Integer seq; String userid; String userpass; String username; Date regDate;

Company company; Address address; Contact contact; Mileage mileage;

List<Auth> authorities;

// Getter & Setter

@Id@GeneratedValue(generator="increment")@GenericGenerator(name="increment", strategy = “increment”)@Column(name = “SEQ”)

Long getSeq() { return seq;

}

}

@Entity@Table( name = “TBL_COMPANY" )public class Company { … }

@Entity@Table( name = “TBL_ADDRESS" )public class Address { … }

@Entity@Table( name = “TBL_CONTACT" )public class Contact { … }

@Entity@Table( name = “TBL_MILEAGE" )public class Mileage { … }

@Entity@Table( name = “TBL_AUTH" )public class Auth { … }

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

DBA 들이 나를 향해 이렇게 외친다.

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

AUTH_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

TEL VARCHAR(12) ,

CELL VARCHAR(12) ,

OFFICE_TEL VARCHAR(12) ,

EMAIL VARCHAR(200) ,

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200) ,

COMPANY_NAME VARCHAR(20) ,

QUARTER_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

MILEAGE INT(12) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

User

Contact

Company

Domains

Auth

Mileage

@Entity@Table( name = “TBL_USER" )public class User {

@Id@GeneratedValue(generator="increment")@GenericGenerator(name="increment", strategy = “increment”)@Column(name = “SEQ”)

Integer seq;

@Column(name = “USERID”) String userid;

@Embedded

Company company;

@Embedded

Address address;

@Embedded

Contact contact;

@OneToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY) Mileage mileage;

@OneToMany( cascade = CascadeType.ALL, fetch = FetchType.LAZY) List<Auth> authorities;

}

@Embeddable

public class Company { … }

@Embeddable

public class Address { … }

@Embeddable

public class Contact { … }

@Embeddable

public class Mileage { … }

@Embeddable

public class Auth { … }

Criteria

Criteria

Criteria criteria = session.createCriteria(User.class);

criteria.add(Restrictions.eq("seq", seq))

.setProjection(

Projections.projectionList()

.add(Projections.property(“zipcode"))

.add(Projections.property(“address_01"))

.add(Projections.property(“address_02")))

.setResultTransformer(

Transformers.aliasToBean(Address.class));

Address address = criteria.uniqueResult();

HQL

HQL

Address address = session.createQuery(“select u.zipcode,

u.address_01, u.address_02 from User u where seq = :seq”, )

.setParameter("seq", seq)

.setResultTransformer(

Transformers.aliasToBean(Address.class))

.uniqueResult();

ORM 에 대한 단상

• Legacy DB 도 충분히 도입 가능하다.

• ORM을 염두한 디자인을 적용할 경우 생산성이 급격히 좋아진다.

• Criteria는 학습이 쉽지 않다.

• HQL을 쓸 때면 뭔가 손해보는 기분.. (방언 처리 라고는 하지만..)

• 퍼포먼스는 사실상 문제 없다.

• SQL Layer가 빠져야돼.

ORM 은 우리가 가지고 있는 문제를 해결한

‘결과’가 아닌

더욱 나은 방향으로 가기 위한 ‘과정’ 입니다.

– 저

No SQL

SQL이 필요 없다고 RDBMS가 필요 없는건 아닐껍니다.

공유의 시간

top related