pymysql.connect(host="localhost", # 데이터베이스 주소
port=3306, # 데이터베이스 서비스 포트 (MySQL 기본 포트: 3306)
user="springboot", # 데이터베이스 접속 계정
passwd="p@ssw0rd", # 데이터베이스 사용자 패스워드
db="sampledb" # 사용할 데이터베이스/스키마
autocommit=True|False # INSERT, UPDATE, DELETE 구문 실행 결과를
자동으로 반영할지의 여부 설정
cursorclass=pymysql.cursors.DictCursor # SELECT 결과를 컬럼 명과 값으로
구성된 dict 타입으로 반환
)
(1, '홍길동', 23, 'hong@test.com')
with pymysql.connect(host="localhost", port=3306,
user="springboot", passwd="p@ssw0rd", db="sampledb") as conn:
{'member_id': 1, 'member_name': '홍길동', 'member_age': 23, 'member_email': 'hong@test.com'}
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
📢 여기서 잠깐! commit이란?
만들고 수정하는 작업 후 연결시켜주는 행위
import pymysql
from faker import Faker
try:
with pymysql.connect(host="localhost", port=3306, user="springboot", passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
fake = Faker('ko-KR')
for i in range(10):
query = f"insert into members (member_name, member_age, member_email) values ('{fake.name()}', {fake.pyint(10, 30)}, '{fake.email()}')"
print(query)
curr.execute(query)
conn.commit() # 10개의 insert 구문의 실행 결과를 DB에 반영
except pymysql.MySQLError as e:
print(e)
📢 여기서 잠깐! autocommit이란?
변경을 자동으로 반환
import pymysql
from faker import Faker
try:
with pymysql.connect(host="localhost", port=3306, user="springboot", passwd="p@ssw0rd",
db="sampledb", cursorclass=pymysql.cursors.DictCursor, autocommit=True) as conn:
~~~~~~~^~~~~~~~~
curr = conn.cursor() 트랜잭션 관리가 필요한 경우 False(기본값)으로 설정
commit() 또는 rollback()을 처리
fake = Faker('ko-KR')
for i in range(10):
query = f"insert into members (member_name, member_age, member_email)
values ('{fake.name()}', {fake.pyint(10, 30)}, '{fake.email()}')"
print(query)
curr.execute(query)
# conn.commit() ⇐ commit() 함수를 호출하지 않아도 변경사항이 DB에 반영되는 것을 확인할 수 있음
except pymysql.MySQLError as e:
print(e)
커서로부터 하나의 행(레코드) 반환
import pymysql
from faker import Faker
try:
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
fake = Faker('ko-KR')
for i in range(10):
query = f"insert into members (member_name, member_age,member_email)
values ('{fake.name()}', {fake.pyint(10, 30)}, '{fake.email()}')"
print(query)
curr.execute(query)
conn.commit()
query = "select * from members"
curr.execute(query)
# 조회 결과를 하나씩 가져오기
while True:
result = curr.fetchone()
if result == None: break
print(result)
except pymysql.MySQLError as e:
print(e)
커서로부터 모든 행(레코드) 반환
import pymysql
from faker import Faker
try:
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
fake = Faker('ko-KR')
for i in range(10):
query = f"insert into members (member_name, member_age, member_email) values ('{fake.name()}', {fake.pyint(10, 30)}, '{fake.email()}')"
print(query)
curr.execute(query)
conn.commit()
query = "select * from members"
curr.execute(query)
# 모든 조회 결과를 반환
results = curr.fetchall()
for result in results:
print(result)
except pymysql.MySQLError as e:
print(e)
커서로부터 n개의 행(레코드)을 반환
import pymysql
from faker import Faker
try:
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
fake = Faker('ko-KR')
for i in range(10):
query = f"insert into members (member_name, member_age, member_email)
values ('{fake.name()}', {fake.pyint(10, 30)}, '{fake.email()}')"
print(query)
curr.execute(query)
conn.commit()
query = "select * from members"
curr.execute(query)
# 조회 결과의 일부를 반환
results = curr.fetchmany(10) → 조회 결과의 첫 부분부터 10개를 가져와 반환
for result in results:
print(result)
print("*" * 10)
results = curr.fetchmany(10) → 그 다음(11번째)부터 10개를 가져와서 반환
for result in results:
print(result)
except pymysql.MySQLError as e:
print(e)
import pymysql
try:
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
name = input("검색할 이름을 입력하세요 : ")
query = f"select * from members where member_name = '{name}'"
curr.execute(query)
results = curr.fetchall()
for result in results:
print(f"ID : {result['member_id']}")
print(f"이름 : {result['member_name']}")
print(f"나이 : {result['member_age']}")
print(f"이메일 : {result['member_email']}")
→ 컬럼의 이름으로 값을 추출하는 것이 가능
DictCursor를 사용하지 않는 경우 result[0]과 같이
튜플 데이터의 인덱스를 사용해야 함
except pymysql.MySQLError as e:
print(e)
import pymysql
try:
with pymysql.connect(host="localhost", port=3306, user="springboot",
passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
name = input("검색할 이름을 입력하세요 : ")
query = f"select * from members where member_name like '%{name}%'"
count = curr.execute(query) → SELECT 구문인 경우 조회 결과 개수를 반환
INSERT, UPDATE, DELETE 구문인 경우
등록, 수정, 삭제된 행의 개수를 반환
print(f"총 {count}건을 조회했습니다.")
results = curr.fetchall()
print(f"총 {len(results)}건을 조회했습니다.")
for result in results:
print(f"ID : {result['member_id']}")
print(f"이름 : {result['member_name']}")
print(f"나이 : {result['member_age']}")
print(f"이메일 : {result['member_email']}")
except pymysql.MySQLError as e:
print(e)
검색할 이름을 입력하세요 : a' or 'a' = 'a' or 'a
총 71건을 조회했습니다.
query = f"select * from members where member_name like '%{name}%'"
# 입력값이 결합된 쿼리의 형태
select * from members where member_name like '%a' or 'a' = 'a' or 'a%'
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
항상 참이 되는 조건
쿼리를 조작할 수 있는 문자(' or = 등)를 포함한 입력
~~~~~~~~~~~
원래 의도와 다르게 외부 입력값에 의해 쿼리의 구조와 의미가 변경되어서 실행 → SQL 인젝션
~~~~~~~~~ ~~~~
이름에 특정 글자가 포함된 회원을 조회 모든 회원 데이터를 조회하는 것으로 변경
import pymysql
try:
with pymysql.connect(host="localhost", port=3306, user="springboot", passwd="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as conn:
curr = conn.cursor()
name = input("검색할 이름을 입력하세요 : ")
# 쿼리문의 구조 정의
query = "select * from members where member_name like %s"
# execute() 함수의 두번째 인자에 쿼리 실행에 필요한 값을
튜플 또는 딕셔너리를 통해 전달
count = curr.execute(query, ('%'+name+'%',))
# execute() 함수가 값을 안전한 형태로 변경해서 쿼리를 생성, 실행
print(f"총 {count}건을 조회했습니다.")
results = curr.fetchall()
print(f"총 {len(results)}건을 조회했습니다.")
for result in results:
print(f"ID : {result['member_id']}")
print(f"이름 : {result['member_name']}")
print(f"나이 : {result['member_age']}")
print(f"이메일 : {result['member_email']}")
except pymysql.MySQLError as e:
print(e)
검색할 이름을 입력하세요 : a' or 'a' = 'a' or 'a
총 0건을 조회했습니다.
해당 입력을 통해서 생성되는 쿼리는
→ ' ' 홑따움표가 이스케이프 처리되서 문자 그 자체로 해석
select * from members where member_name like 'a\' or \'a\' = \'a\' or \'a'
| |
+---------------------------+
%s = 문자열 데이터
https://docs.python.org/ko/3/library/re.html
문자열 데이터에 특정 패턴을 이용해 검색, 추출, 치환하는 기능
문자열을 처리하는 모든 곳에서 사용하는 일종의 형식 언어
정규표현식을 줄여 '정규식' 이라고 하기도 함
특별한 의미를 가진 문자
. ^ $ * + ? { } [ ] \ | ( )
문자 클래스
‘[’ 와 ‘]’ 사이의 문자들과 매치’라는 의미
[ ] 사이에는 어떤 문자도 들어가기 가능
[] 안의 두 문자 사이에 하이픈(-)을 사용하면 두 문자 사이의 범위를 의미
Ex.
정규표현식 [abc]
이 표현식의 의미는 ‘a, b, c 중 한 개의 문자와 매치’라는 뜻
정규표현식 [0-5]
이 표현식의 의미는 [012345]와 동일
[0123456789] # 대괄호 → 나열된 데이터 중 하나
[0-9] # 대괄호 내의 - → 가질 수 있는 값의 범위
\d
[^0-9] # 0부터 9까지를 제외한 문자
[abcdefghijklmnopqrstuvwxyz]
[a-z]
[ABCDEFGHIJKLMNOPQRSTUVWXYZ]
[A-Z]
[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]
[a-zA-Z]
📢 여기서 잠깐! 문자 클래스 안에 ^ 메타 문자를 사용한다면?
이는 반대(not)라는 의미
[^0-9] 라는 정규 표현식이 있다면 이는 숫자가 아닌 문자만 매치
[0-9a-fA-F]
^ # circumflex, carrot, hat, cap
$
[ㄱ-힣]
? * + {m} {m,n} 등으로 표현
\d? # 숫자 0회 또는 1회
\d* # 숫자 0회 이상
\d+ # 숫자 1회 이상
\d{m} # 숫자 m개
\d{m, n} # 숫자 m개 ~ n개
줄바꿈 문자인 \n을 제외한 모든 문자와 매치
단, re.DOTALL
옵션을 주면 .(dot) 문자와 \n 문자도 매치 가능
a.b
→ "a + 모든 문자 + b"
→ 즉, a와 b라는 문자 사이에 어떤 문자가 들어가도 모두 매치된다는 뜻
반복을 의미하는 메타 문자
ca*t
→ * 앞에 있는 a가 아예 안 나오거나 여러 번 반복될 수 있다는 뜻
→ ct(a가 0번 반복), cat(a가 0번 이상 반복), caaat(a가 0번 이상 반복)
등의 문자열은 모두 매치 가능
최소 1번 이상의 반복을 나타내는 문자
*와 차이점이라면 *은 반복 횟수 0번부터라면 +은 반복 횟수 1번부터 포함
ca+t
→ "c + a가 1번 이상 반복 + t"
→ cat(a가 1번 이상 반복), caaat(a가 3번 이상 반복) 등과는 매치가 가능하지만
ct(a가 0번 반복)와는 매치 X
{} 메타 문자를 사용하면 반복 횟수를 고정시켜줌
? 메타 문자는 문자가 아예 없거나 1번 있는 것
→ ? 메타 문자가 의미하는 것은 {0, 1}
{m, n} 정규식
→ 반복 횟수가 m부터 n까지인 문자와 매치
→ m 또는 n 생략 가능
ab?c
→ "a + b가 있어도 되고 없어도 됨 + c"
파이썬은 정규 표현식의 지원을 위해 re(regular expression)
모듈을 제공
re 모듈은 파이썬을 설치할 때 자동으로 설치되는 표준 라이브러리
💡 re 모듈의 사용 방법
패턴이란 정규식을 컴파일한 결과>> import re >> p = re.compile('ab*') # re.compile을 사용하여 정규 표현식(예제에선 ab*)을 컴파일 # re.compile의 리턴값을 객체 p(컴파일 된 패턴 객체) 에 할당해 그 이후의 작업 수행
컴파일 된 패턴 객체를 사용하여 문자열 검색 수행
총 4가지 메서드 제공
💡 Method와 목적
match()
→ 문자열이 정규식과 매치되는지 조사
search()
→ 문자열 전체를 검색해 매치되는지 조사
findall()
→ 매치되는 문자열(substring)을 리스트로 반환
finditer()
→ 매치되는 문자열을 반복 가능한 객체로 반환
※ match, search
→ 매치될 때는 match 객체 리턴, 매치되지 않을 때는 None 리턴
※ match 객체
→ 정규식의 검색 결과로 리턴된 객체를 의미
import re
p = re.compile('[a-z]+')
문자열의 처음부터 정규식과 맞는지 조사
result = p.match('python')
print(result) # <re.Match object; span=(0, 6), match='python'>
result = p.match('3 python')
print(result) # None
result = p.match('life is too short')
print(result) # <re.Match object; span=(0, 4), match='life'>
컴파일 된 객체 p로 search 메서드 수행
result = p.search('python')
print(result) # <re.Match object; span=(0, 6), match='python'>
result = p.search('3 python')
print(result) # <re.Match object; span=(2, 8), match='python'>
result = p.search('life is too short')
print(result) # <re.Match object; span=(2, 8), match='python'>
💡 match 메서드와 search 메서드
문자열의 처음부터 검색할지의 여부에 따라 다르게 사용
패턴([a-z]+)과 매치되는 모든 값을 찾아 리스트로 리턴
results = p.findall('life is too short')
print(results) # ['life', 'is', 'too', 'short']
results = p.findall('3 python')
print(results) # ['python']
findall과 동일하지만 그 결과로 반복 가능한 객체(iterator object) 리턴
또한 반복 가능한 객체가 포함하는 각각의 요소는 match 객체
results = p.finditer('life is too short')
print(results) # <callable_iterator object at 0x000002232E003310>
for result in results: print(result)
# <re.Match object; span=(0, 4), match='life'>
# <re.Match object; span=(5, 7), match='is'>
# <re.Match object; span=(8, 11), match='too'>
# <re.Match object; span=(12, 17), match='short'>
results = p.finditer('3 python')
print(results) # <callable_iterator object at 0x000002232E0024A0>
for result in results: print(result)
# <re.Match object; span=(2, 8), match='python'>
p.match, p.search 또는 p.finditer 메서드에 의해 리턴된 매치 객체(Match Object)를 의미
💡 Method와 목적
group
→ 매치된 문자열을 리턴
start
→ 매치된 문자열의 시작 위치 리턴
end
→ 매치된 문자열의 끝 위치 리턴
span
→ 매치된 문자열의 (시작, 끝)에 해당하는 튜플 리턴
import re
p = re.compile('[a-z]+')
result = p.search('3 python')
type(result)
print("매치된 문자열 : " + result.group()) # python
print("매치된 문자열의 시작 위치(인덱스) : " + str(result.start())) # 2
print("매치된 문자열의 끝 위치(인덱스) : " + str(result.end())) # 8
print("매치된 문자열의 (시작, 끝) 튜플 : " + str(result.span())) # (2, 8)
💡 search 메서드
문자열의 처음부터 검색하는 게 아니라 문자열 전체를 검색하기 때문에 3 이후의 python 문자열과 매치되어 start 값은 2가 나옴
.
메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙 존재
만약 \n 문자도 포함하여 매치하고 싶다면 re.DOTALL
또는 re.S
옵션을 사용해 정규식을 컴파일하면 됨
💡
re.DOTALL
옵션
여러 줄로 이루어진 문자열에서 줄바꿈 문자에 상관없이 검색할 때 많이 사용
import re
p = re.compile('a.b')
result = p.match('a\nb') # \n은 매치되지 않기에 결과값으로 None 출력
print(result) # None
p = re.compile('a.b', re.DOTALL)
result = p.match('a\nb')
print(result) # <re.Match object; span=(0, 3), match='a\nb'>
re.IGNORECASE
또는 re.I
옵션은 대소문자 구별 없이 매치를 수행할 때 사용하는 옵션
💡 [a-z]+ 정규식
소문자만을 의미
→ 그러나re.I
옵션으로 대소문자 구별 없이 매치
import re
p = re.compile('[a-z]+')
result = p.match('python')
print(result) # <re.Match object; span=(0, 6), match='python'>
result = p.match('Python')
print(result) # None
result = p.match('PYTHON')
print(result) # None
p = re.compile('[a-z]+', re.IGNORECASE)
result = p.match('python')
print(result) # <re.Match object; span=(0, 6), match='python'>
result = p.match('Python')
print(result) # <re.Match object; span=(0, 6), match='Python'>
result = p.match('PYTHON')
print(result) # <re.Match object; span=(0, 6), match='PYTHON'>
^
는 문자열의 처음, $
는 문자열의 마지막을 의미
re.MULTILINE
또는 re.M
옵션은 이러한 메타 문자인 ^
, $
와 연관된 옵션
Ex.
정규식이 ^python
이라면 문자열의 처음이 python으로 시작해야 매치
정규식이 python$
이라면 문자열의 마지막이 python으로 끝나야 매치
import re
p = re.compile(r'^python\s\w+')
result = p.findall('''python one\nlife...\npython
two\nyour nedd python\npython threee
life is too short
python two
your nedd python
python three''')
print(result) # ['python one']
python이라는 문자열로 시작하고 그 뒤에 화이트 스페이스, 그 뒤에 단어가 와야 한다는 의미
이는 ^
메타 문자에 의해 python이라는 문자열을 사용한 첫 번째 줄만 매치된 것
💡
^
메타 문자
문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우에 사용할 수 있는 옵션이 바로re.MULTILINE
또는re.M
# r"^python\s\w+" 또는 "^python\\s\\w+" 형식으로 표기
p = re.compile(r"^python\s\w+", re.MULTILINE)
# raw string \를 이용해서 이스케이프
result = p.findall('''python one
life is too short
python two
your nedd python
python three''') # ['python one', 'python two', 'python three']
print(result)
^
메타 문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 가지게 됨
즉, re.MULTILINE
옵션은 ^
, $
메타 문자를 문자열의 각 줄마다 적용해 주는 것
CLI 기반의 CRUD 프로그램 작성
==========================
메뉴
--------------------------
Q : 종료 ⇒ 프로그램을 종료
I : 등록 ⇒ 등록 화면으로 이동
S : 검색 ⇒ 검색 화면으로 이동
==========================
메뉴를 선택하세요 >>>
==========================
회원 등록
--------------------------
이름 : 홍길동
나이 : 23
이메일 : hong@test.com
==========================
Y : 등록 / N : 취소 ⇒ Y → members 테이블에 입력한 내용을 저장 → 등록했습니다. 출력 후 메뉴 화면으로 이동
N → 메뉴 화면으로 이동
==========================
회원 검색
--------------------------
이름 : 길동
==========================
Y : 검색 / N : 취소 ⇒ Y → members 테이블에 like 검색 → 검색 결과 화면으로 이동
N → 메뉴 화면으로 이동
==========================
회원 검색 결과 (OO건)
--------------------------
1 : 홍길동 ⇐ 검색 결과를 회원아이디 : 회원이름 형식으로 나열
2 : 고길동 검색 결과가 없는 경우 "일치하는 결과 없음" 출력
3 : 신길동
==========================
번호 : 상세 조회 / N : 취소 ⇒ 번호(회원 아이디) → 회원 상세 조회 화면으로 이동
N → 메뉴 화면으로 이동
==========================
회원 상세 조회
--------------------------
아이디 : 1
이름 : 홍길동
나이 : 23
이메일 : hong@test.com
==========================
U : 수정 D : 삭제 / Y : 메뉴로 이동
⇒ D → 해당 회원 삭제 후 "삭제했습니다" 메시지를 출력하고 메뉴 화면으로 이동
U → 수정 화면으로 이동
N → 메뉴 화면으로 이동
==========================
회원 수정
--------------------------
아이디 : 1 ⇐ 회원 정보를 보여주고,
이름 : 홍길동
나이 : 23
이메일 : hong@test.com
==========================
나이 : 43
이메일 : gildong@test.com
수정할까요? (Y : 수정 / N : 메뉴로 이동)
Y → 나이와 이메일을 입력 받아서 수정 후 "수정했습니다." 메시지를 출력하고
메뉴 화면으로 이동
N → 메뉴 화면으로 이동
결과
import pymysql
import re
def print_double_line():
print("======================================")
def print_single_line():
print("--------------------------------------")
def show_menu_page():
print_title("메뉴")
print("I: 회원 정보를 등록합니다.")
print("S: 회원을 LIKE 검색합니다.")
print("Q: 프로그램을 종료합니다.")
print_tail()
def print_title(title):
print()
print_double_line()
print(title)
print_single_line()
def print_tail():
print_double_line()
def check_input(message, valid_inputs, line_yn=False):
if line_yn: print("--------------------------------------")
while True:
i = input(message + " >>> ").upper()
if i in valid_inputs:
return i
else:
print("잘못된 입력입니다. 확인 후 다시 입력해 주세요.")
def main():
while True:
show_menu_page()
menu = check_input("메뉴를 선택하세요. (I: 등록 / S: 검색 / Q: 종료)", "ISQ")
if menu == "Q":
print("프로그램을 종료합니다.")
break
elif menu == "I":
do_insert()
elif menu == "S":
do_search()
def do_insert():
print_title("회원 등록")
name = input("이름 : ")
age = int(input("나이 : "))
email = input("이메일 : ")
# 형식 검증 후 메시지 출력
yn = check_input("등록하시겠습니까? (Y: 등록 / N: 취소)", "YN", True)
if yn == "N":
print("회원 등록을 취소합니다.")
return
query = "insert into members (member_name, member_age, member_email) value (%s, %s, %s)"
with pymysql.connect(host="localhost", port=3306, user="springboot", password="p@ssw0rd", db="sampledb", autocommit=True) as connection:
cursor = connection.cursor()
count = cursor.execute(query, (name, age, email))
if count == 1:
print("회원 정보를 정상적으로 등록했습니다.")
else:
print("회원 정보를 등록하는데 실패했습니다.")
def do_search():
print_title("회원 검색")
name = input("이름 : ")
yn = check_input("검색하시겠습니까? (Y: 검색 / N: 취소)", ("Y", "N"), True)
if yn == "N":
print("회원 검색을 취소합니다.")
return
with pymysql.connect(host="localhost", port=3306, user="springboot", password="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as connection:
query = "select * from members where member_name like %s"
cursor = connection.cursor()
count = cursor.execute(query, ("%"+name+"%",))
members = cursor.fetchall()
print_title(f"검색 결과 (총 {count}건)")
if count == 0:
print("일치하는 결과가 없습니다. ")
else:
ids = []
for member in members:
ids.append(str(member['member_id']))
print(f"{member['member_id']} : {member['member_name']}")
do_detail(ids)
def do_detail(ids: list):
ids.append('N')
mid = check_input("상세 정보를 조회하시겠습니까? (회원번호: 상세조회 / N: 취소)", ids, True)
if mid == "N":
print("상세 조회를 취소합니다.")
return
with pymysql.connect(host="localhost", port=3306, user="springboot", password="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as connection:
query = "select * from members where member_id like %s"
cursor = connection.cursor()
cursor.execute(query, (mid,))
member = cursor.fetchone()
print_title("회원 상세 조회")
print(f"ID: {member['member_id']}")
print(f"이름: {member['member_name']}")
print(f"나이: {member['member_age']}")
print(f"이메일: {member['member_email']}")
udn = check_input("회원 정보를 수정 또는 삭제하시겠습니까? (U: 수정 / D: 삭제 / N: 메인 화면으로 이동)", ("U", "D", "N"), True)
if udn == "U":
do_update(member['member_id'])
elif udn == "D":
do_delete(member['member_id'])
elif udn == "N":
return
def do_delete(id):
yn = check_input("회원 정보를 삭제하시겠습니까? (Y: 삭제 / N: 취소)", "YN")
if yn == "N":
print("회원 정보 삭제를 취소합니다.")
return
with pymysql.connect(host="localhost", port=3306, user="springboot", password="p@ssw0rd", db="sampledb", autocommit=True) as connection:
query = "delete from members where member_id = %s"
cursor = connection.cursor()
count = cursor.execute(query, (id,))
if count == 1:
print("회원 정보를 정상적으로 삭제했습니다.")
else:
print("회원 정보를 삭제하는데 실패했습니다.")
def do_update(id):
with pymysql.connect(host="localhost", port=3306, user="springboot", password="p@ssw0rd", db="sampledb", cursorclass=pymysql.cursors.DictCursor) as connection:
query = "select * from members where member_id like %s"
cursor = connection.cursor()
cursor.execute(query, (id,))
member = cursor.fetchone()
print_title("회원 정보 수정")
print(f"ID: {member['member_id']}")
print(f"이름: {member['member_name']}")
print(f"나이: {member['member_age']}")
print(f"이메일: {member['member_email']}")
print_tail()
age = int(input("변경할 나이 : "))
email = input("변경할 이메일 : ")
# TODO 형식 검증 후 메시지 출력
yn = check_input("회원 정보를 수정하시겠습니까? (Y: 수정 / N: 취소)", ("Y", "N"), True)
if yn == "N":
print("회원 정보 수정을 취소합니다.")
else:
query = "update members set member_age = %s, member_email = %s where member_id = %s"
cursor = connection.cursor()
count = cursor.execute(query, (age, email, id))
if count == 1:
print("회원 정보를 정상적으로 수정했습니다.")
connection.commit()
else:
print("회원 정보를 수정하는데 실패했습니다.")
connection.rollback()
if __name__ == "__main__":
main()