Flask와 MySQL을 사용한다고했다!! Django의 경우 django가 제공하는 기능으로 django와 mysql을 연결할 수 있었는데 기본 flask의 경우 그런 자동기능이 없어 직접 설정해 주어야 한다!
이 상황에서 우리가 선택한 것은 PyMySql로 쉽게 말해서 Flask와 MySQL의 중간다리 역활을 수행하 주는 것이다.
pip install pymysql
으로 설치해 준다. 위의 명령어에서 볼수 있듯이 이 모듈은 python에서 제공하는 모듈이다
따라서 Flask 내에서 사용할때에는
import pymysql
로 적용하면 된다!
DB에 관한 정보는 지난번 Django를 이용한 프로젝트때처럼 my_settings
라는 file을 만들어 .gitignore
에 등록해 보안상의 정보가 githup에 업로륻 되지 않도록 관리해야 한다.
이번에는 DB 연결에 관한 정보가 담긴 파일을 두개로 나눠서 관리하고자 한다.
my_settings.py 와 같은 역활이다.
그 안에는 내가 연동할 DB의 이름, 내 MySQL의 접속 비밀번호, 포트번호 등 여러 비밀번호들이 입력되어 있다.
설치한 pymysql
을 이용해 Mysql을 연결해주는 내용이 담긴 파일이다.
import pymysql
from config import DATABASE
def connect_db():
db = pymysql.connect(
host = DATABASE['host'],
port = DATABASE['port'],
user = DATABASE['user'],
password = DATABASE['password'],
database = DATABASE['database'],
charset = DATABASE['charset'],
autocommit = False,
read_timeout = 20
)
return db
autocommit ?
이후 내용에서 나오겠지만 INSERT / UPDATE / DELETE의 결과를 DB에 적용하기 위해선commit
을 해주어야 한다.
이때 autocommit설정이 되어있으면 굳이 commit한다고 언급하지 않아도 되지만 중간에 어떤 실수가 있을지 모르니 이건 OFF로 해두도록 한다.
연결된 db에 대한 설정을 처음 적용하는 곳이다. 먼저 import를 해준다.
from db_connector import connect_db
앞으로 로직을 타고가면서 DB연결에 대한 정보도 같이 넘겨주어야 한다. 이를 위해서 새로 connection
이라는 변수에 연결에 대한 정보를 저장한다.
먼저 연결정보를 저장하기 전 connection
이라는 변수를 초기화 해준다
아무것도 없음이 확실하더라도 초기화를 진행해 주도록 하자
connection = None
이후 try / execpt / finally 문을 통해 connection에 대한 정보를 설정해준다.
try:
connection = connect_db()
...생략...
except:
if connection:
connection.rollback()
finally:
if connection:
connection.close()
생성한 변수 connection
에 db_connector에서 작성한 함수 connec_db()를 설정해 준다. 이제 내가 설정한 DB와 이 로직은 연결된다.
예상치 못한 에러상황으로 인해 db에 연결되어 수행되었던 것들이 취소되어야 할때가 있다. 예를들어 새로운 instance를 생성하는 도중에 에러가 발생했을때!? 중단 했지만 이미 몇가지 Instance들이 잘못 생성되었다면 곤란할 것이다.
이럴때 수행해 주는것이 rollback이다. 이는 pymysql에서 제공하는 함수이다!
try와 execpt 상황에 상관없이 항상 수행되는 구문이다.
따라서 로직의 마지막 결과 connection이 None이 아니라면 (초기화 상태가 아니라면) 연결을 닫아준다.
view에서 설정된 connection은 로직이 진행되는 동안 계속해서 전달되어야 한다. 따라서 내 프로젝트 상 view => service => dao => service => view 순으로 진행되므로 이 흐름을 따라 connection도 함께 넘겨주어야 한다.
딱히 복잡한 것은 없고 모든 parameter에 connection을 추가하면 된다.!
# view에서 받는 service의 정보
mypage_service = MyPageService()
view_result = mypage_service.mypage_order(connection, 이하생략)
# service의 class와 parameter
class MyPageService:
def mypage_order(self, connection, 이하생략):
# service에서 받는 dao의 정보
mypage_dao = MyPageDao()
service_result = mypage_dao.mypage_order_dao(connection, 이하생략)
# dao의 class와 parameter
class MyPageDao:
def mypage_order_dao(self, connection, 이하생략)
pymysql이 연결되는 db와 상호작용 하기 위해서 cursor라는 객체가 필요하다!
cursor ?
말 그대로 클릭 이다. cursor 메소드에 포함되어 있는 여러 기능을 사용해 DB와 상호작용 한다.
또한 RDMS를 사용하는때에 Dictionary 형태가 가장 적합하다! 때문에 결과를 dictionary형태로 변환해 주도록 DictCursor
를 사용한다.
DictCursor ?
pymysql의 cursor객체는 default값으로cursor()
가 지정되어 있다. 이는 Array based cursor로 row의 결과값을 배열로 / pymysql에서는 tuple형태로 반환한다.
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
connection
에 python의 cursor메소드를 사용해 DictCursor로 지정해 주고 것을 앞으로 별칭 cursor
라고 함을 선언한다.cursor를 사용해 SQL을 실행한다! 이를 위해서 execute를 사용한다.
예를들어 입력된 유저의 회원가입 정보를 user_info
라는 값에 저장시켜놓고 이에 대한 정보를 해당 정보가 담길 table의 CREATE 기능을 지정한 변수 user_query
에 적용한다고 하면 다음과 같이 입력해야 한다.
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
user_query = """
INSERT INTO
이하 생략
"""
cursor.execute(user_info, user_query)
위의 execute로 실행한 SQL의 결과를 fetch를 통해 받아온다.
git 다룰때 많이쓰던 commit...!!! 반갑지만 뜻이 전혀 다르다는거 당연한 소리;;
여기서 commit은 INSERT / UPDATE / DELETE된 DB의 값을 진짜로 DB에 적용하기 위해 사용하는 기능이다.
위의 기능에 대해 반환되는 결과는 특별히 없다 (있는 경우도 있겠지만 일반적으론??) 때문에 위의 fetch
를 사용하지 않아도 된다. (쓸 곳이 없으니!)
대신 변동된 DB의 내용을 실제 DB에 적용하기 위해선 아래의 코드를 입력해 주어야 한다.
# view.py
cursor.commit()
이걸 작성하게 된 계기는 아무리 DB의 내용을 UPDATE 해도 반영이 안되서 왜..안되지...? 하던차에 구글링을 통해 commmit()을 해주지 않음을 알았던 탓이다. 기록!!
REFERENCE
execuemany에 대한 것 (pymysql 참고한 분의 블로그 글을 토대로 계속 공부할 것)