Database ORM
August 2021 (536 Words, 3 Minutes)
영속성
영속성이란 데이터를 생성한 프로그램이 종료되도 데이터가 사라지지 않는 특징을 의미한다. 영속성이 없는 데이터는 메모리에서만 존재하여 프로그램 종료시 증발하게 된다.
메모리 상 데이터를 파일 시스템, RDBMS 등을 활용하여 영구적으로 저장한다. 저장하는 방법은
- JDBC
- Spring JDBC
- Persistence Framework( JPA, Hibernate, Mybatis ) 가 있다.
ORM
ORM( Object Relational Mapping )이란 객체와 관계형 데이터베이스 데이터를 매핑하는 것을 의미한다. 객체 지향의 클래스, RDBMS의 테이블을 사용하여 서로 연결해준다. ORM을 통해 객체 간 관계를 기반으로 SQL를 자동으로 생성하고 일치시킨다. 즉, 객체를 통해 간접적으로 DB 데이터를 다룬다.
장점
- 객체 지향적인 관점에서 SQL 쿼리가 아닌 클래스 메서드로 데이터를 다루어 생산성이 증가한다.
- ORM은 독립적으로 작성되어 객체를 재사용할 수 있고 유지보수가 편리해진다.
- SQL을 자동으로 생성하여 RDMBS의 데이터 구조와 객체 지향 모델 사이의 간격을 좁혀 DB에 종속적이지 않다.
Object–relational impedance mismatch
Object–relational impedance mismatch는 객체 모델과 RDBMS가 같은 데이터를 표현하고 다루는 방법에서 발생하는 차이를 의미하는 패러다임의 불일치이다.
- Granularity : DB의 테이블 수보다 더 많은 클래스를 가진 객체 모델을 만들 수 있다.
- Inheritance : RDBMS는 객체 모델의 주요 패러다임인 상속과 유사한 개념이 없다.
- Identity : RDBMS에서 PK가 동일하면 서로 같은 record로 정의하지만 객체 모델에서는 a==b 와 a.equals(b) 를 다르게 정의한다.
- Associations : 객체 모델에서 참조는 방향이 있고 양방향 관계는 각각의 객체에 연관을 정의해야 한다. 반면, RDBMS에서 FK와 JOIN은 방향성이 없다.
참고
https://gmlwjd9405.github.io/2019/02/01/orm.html
Python ORM - sqlalchemy
Mapping Class
SQLAlchemy
를 이용하여 파이썬에서 ORM을 작성할 수 있다. 공식 문서에서 예시를 참고하였다.
- DB에 연결한다.
from sqlalchemy import create_engine
engine = create_engine('{RDBMS_URL}')
- Mapping을 정의한다. DB 테이블과 매핑하여 CRUD를 위한 클래스를 생성한다. 테이블 생성을 위해서는 클래스와 DB를 연결하는 base 클래스를 사용한다.
from datetime import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (
... self.name, self.fullname, self.nickname)
- Schema를 생성한다.
Base.metadata.create_all(engine) ''' BEGIN... CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR, fullname VARCHAR, nickname VARCHAR, PRIMARY KEY (id) ) [...] () COMMIT '''
- 매핑 클래서의 인스턴스를 생성한다.
>>> ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname') >>> ed_user.name 'ed' >>> ed_user.nickname 'edsnickname' >>> str(ed_user.id) 'None'
Session 활용
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
Objects 추가 및 수정
ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
session.add(ed_user)
이 시점에서 instance가 pending이라고 할 수 있다. Session
은 필요한 순간에 대기 중이던 SQL을flush 를 통해 Ed Jones
를 추가한다.
>>> our_user = session.query(User).filter_by(name='ed').first()
>>> our_user
<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>
Session
은 map을 통해 생성된 객체와 our_user
가 같은 객체임을 식별한다.
>>> ed_user is our_user
True
Reflecting Database Objects
Table
object는 database schema에서 정보를 로드할 수 있다(reflection)
>>> messages = Table('messages', meta, autoload_with=engine)
>>> [c.name] for c in messages.columns]
['message_id', 'message_name', 'date']
messages
table에 database 정보를 반영한다.