본문 바로가기
배움 로그/backend

sqlite3 에러 해결하기(sqlite3.OperationError, sqlite3.ProgrammingError)

by eple 2023. 1. 25.
728x90
반응형

 

 

In memory DB로 서버가 아니라
응용 프로그램에 임베디드 되어 사용하는
가벼운 데이터베이스 -
SQLite 

SQLite는 쓰기 작업 시
데이터베이스를 잠그므로
여러 동시 쓰기 작업이 실행되는 앱에서는
성능 문제가 발생할 수 있어
업무 자동화를 위한
혼자만의 작업이라던가... 미니시스템으로
SQL을 배우거나 할 때 사용해 보기 좋다.

파이썬(3.11.0)에는 sqlite3라는
패키지 이름으로 기포함되어 있다. 

아래는 조금씩 활용하다가
마주친 에러를 해결방법을 공유! 

 

    Task  -  XML 파일 파싱 후,  정규화(Normalization)하기 

import xml.etree.ElementTree as ET
import sqlite3

conn = sqlite3.connect('trackdb.sqlite')
cur = conn.cursor()

# Make some fresh tables using executescript()
cur.executescript('''
DROP TABLE IF EXISTS Artist;
DROP TABLE IF EXISTS Album;
DROP TABLE IF EXISTS Track;
DROP TABLE IF EXISTS Genre;

CREATE TABLE Artist (
    id  INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    name    TEXT UNIQUE
);

CREATE TABLE Genre (
    id  INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    name    TEXT UNIQUE
);

CREATE TABLE Album (
    id  INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
    artist_id  INTEGER,
    title   TEXT UNIQUE
);

CREATE TABLE Track (
    id  INTEGER NOT NULL PRIMARY KEY 
        AUTOINCREMENT UNIQUE,
    title TEXT  UNIQUE,
    album_id  INTEGER,
    len INTEGER, rating INTEGER, count INTEGER, genre_id INTEGER 
);
''')

fname = 'Library.xml'

def lookup(d, key):
    found = False
    for child in d:
        if found : return child.text
        if child.tag == 'key' and child.text == key :
            found = True
    return None

stuff = ET.parse(fname)
all = stuff.findall('dict/dict/dict')
print('Dict count:', len(all))
for entry in all:
    if ( lookup(entry, 'Track ID') is None ) : continue

    name = lookup(entry, 'Name')
    artist = lookup(entry, 'Artist')
    album = lookup(entry, 'Album')
    count = lookup(entry, 'Play Count')
    rating = lookup(entry, 'Rating')
    length = lookup(entry, 'Total Time')
    genre = lookup(entry, 'Genre')

    if name is None or artist is None or album is None : 
        continue
    
    print(name, artist, album, count, rating, length, genre)

    cur.execute('''INSERT OR IGNORE INTO Artist (name) 
        VALUES ( ? )''', ( artist, ) )
    cur.execute('SELECT id FROM Artist WHERE name = ? ', (artist, ))
    artist_id = cur.fetchone()[0]

    cur.execute('''INSERT OR IGNORE INTO Album (title, artist_id) 
        VALUES ( ?, ? )''', ( album, artist_id ) )
    cur.execute('SELECT id FROM Album WHERE title = ? ', (album, ))
    album_id = cur.fetchone()[0]

    cur.execute('''INSERT OR IGNORE INTO Genre (name) 
        VALUES ( ? )''', ( genre, ) )
    cur.execute('SELECT id FROM Genre WHERE name = ? ', (genre, ))
    genre_id = cur.fetchone()[0]

    cur.execute('''INSERT OR REPLACE INTO Track
        (title, album_id, len, rating, count, genre_id) 
        VALUES ( ?, ?, ?, ?, ?, ?)''', 
        ( name, album_id, length, rating, count, genre_id) )

    conn.commit()

conn.close()

 

    sqlite3.OperationError : database is locked

  • genre 키 값에 따른 데이터를 DB에 저장해오려다 마주친 Error

sqlite3.OperationError

conn = sqlite3.connect('trackdb.sqlite')
cur = conn.cursor()

....

conn.close()
  • 위와 같이 DB와 Connection을 열었다면 재차 다시 돌리기 위해서는 Connection을 닫아줘야한다. 그럼 해결
  • 그런데도 해결이 안된다면 python에서 물고 있는 Connection을 끊을 수 있도록 Python을 재시작한다. 

 

    sqlite3.ProgrammingError : Cannot operate on a closed database

  • 반대로 conn.close()가 남발되서 생긴 Error다. 
conn.close()

sqlite3.ProgrammingError
sqlite3.ProgrammingError

  • 잘못된 들여쓰기로 DB를 Close 하고 DB에 데이터를 넣으려해서 표시된 에러
  • 항상 Indentation(들여쓰기)를 주의하자 

 

 

'배움 로그 > backend' 카테고리의 다른 글

[DB/Oracle] 두 테이블 JOIN하기 - ① JOIN  (0) 2022.05.17

댓글