From 76da7d9cd1fbe7bc3642a5c7646bf371eaabd0c1 Mon Sep 17 00:00:00 2001 From: thug0bin Date: Fri, 27 Feb 2026 15:43:52 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20SQLite=20=EB=A9=80=ED=8B=B0=EC=8A=A4?= =?UTF-8?q?=EB=A0=88=EB=93=9C=20I/O=20=EC=97=90=EB=9F=AC=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 요청마다 새 SQLite 연결 생성 (new_connection=True) - 사용 후 명시적 close - 간헐적 'I/O operation on closed file' 에러 방지 --- backend/app.py | 12 +++++++-- backend/db/dbsetup.py | 57 ++++++++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/backend/app.py b/backend/app.py index 49fb4f4..f78fdc6 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3029,9 +3029,10 @@ def api_member_history(phone): transaction_ids = [] # 적립된 거래번호 수집 - # 1. 마일리지 내역 조회 (SQLite) + # 1. 마일리지 내역 조회 (SQLite) - 새 연결 사용 (멀티스레드 안전) + sqlite_conn = None try: - sqlite_conn = db_manager.get_sqlite_connection() + sqlite_conn = db_manager.get_sqlite_connection(new_connection=True) cursor = sqlite_conn.cursor() # 사용자 정보 조회 @@ -3108,6 +3109,13 @@ def api_member_history(phone): except Exception as e: logging.warning(f"마일리지 조회 실패: {e}") + finally: + # SQLite 연결 닫기 + if sqlite_conn: + try: + sqlite_conn.close() + except: + pass # 2. 전화번호로 POS 고객코드 조회 (MSSQL) cuscode = None diff --git a/backend/db/dbsetup.py b/backend/db/dbsetup.py index c209703..2a3e12e 100644 --- a/backend/db/dbsetup.py +++ b/backend/db/dbsetup.py @@ -185,18 +185,23 @@ class DatabaseManager: # 새 세션 생성 return self.get_session(database) - def get_sqlite_connection(self): + def get_sqlite_connection(self, new_connection=False): """ - SQLite mileage.db 연결 반환 (싱글톤 패턴) - 최초 호출 시 스키마 자동 초기화 + SQLite mileage.db 연결 반환 + + Args: + new_connection: True면 항상 새 연결 생성 (멀티스레드 안전) Returns: sqlite3.Connection: SQLite 연결 객체 """ - # 연결 유효성 체크 강화 + # 새 연결 요청 시 항상 새로 생성 + if new_connection: + return self._create_sqlite_connection() + + # 기존 싱글톤 방식 (하위 호환) if self.sqlite_conn is not None: try: - # 연결 상태 확인 cursor = self.sqlite_conn.cursor() cursor.execute("SELECT 1") cursor.fetchone() @@ -210,28 +215,30 @@ class DatabaseManager: self.sqlite_conn = None if self.sqlite_conn is None: - # 파일 존재 여부 확인 - is_new_db = not self.sqlite_db_path.exists() - - # 연결 생성 - self.sqlite_conn = sqlite3.connect( - str(self.sqlite_db_path), - check_same_thread=False, # 멀티스레드 허용 - timeout=10.0 # 10초 대기 - ) - - # Row Factory 설정 (dict 형태로 결과 반환) - self.sqlite_conn.row_factory = sqlite3.Row - - # 신규 DB면 스키마 초기화 - if is_new_db: - self.init_sqlite_schema() - print(f"[DB Manager] SQLite 신규 DB 생성 완료: {self.sqlite_db_path}") - else: - print(f"[DB Manager] SQLite 기존 DB 연결: {self.sqlite_db_path}") - self._migrate_sqlite() + self.sqlite_conn = self._create_sqlite_connection() return self.sqlite_conn + + def _create_sqlite_connection(self): + """새 SQLite 연결 생성""" + is_new_db = not self.sqlite_db_path.exists() + + conn = sqlite3.connect( + str(self.sqlite_db_path), + check_same_thread=False, + timeout=10.0 + ) + conn.row_factory = sqlite3.Row + + if is_new_db: + # 스키마 초기화 (임시로 self.sqlite_conn 설정) + old_conn = self.sqlite_conn + self.sqlite_conn = conn + self.init_sqlite_schema() + self.sqlite_conn = old_conn + print(f"[DB Manager] SQLite 신규 DB 생성 완료: {self.sqlite_db_path}") + + return conn def init_sqlite_schema(self): """