我可以将我的sqlite连接和游标放入一个函数吗?

8 投票
2 回答
12730 浏览
提问于 2025-04-16 09:29

我在想,能不能把我的sqlite数据库连接做成一个函数,这样就不用到处复制粘贴大约6行代码来连接和执行查询了。
我想让这个函数更灵活,这样我就可以用同一个函数来处理创建、查询、插入等等操作。

下面是我尝试的代码。'INSERT'和'CREATE TABLE'的查询都能正常工作,但如果我做一个'SELECT'查询,我该怎么在函数外面处理它获取的值呢?
通常我想打印出获取的值,还想对它们做其他处理。

当我像下面这样做时,我遇到了一个错误:

Traceback (most recent call last):
File "C:\Users\steini\Desktop\py\database\test3.py", line 15, in <module>
for row in connection('testdb45.db', "select * from users"):
ProgrammingError: Cannot operate on a closed database.

所以我想,连接需要保持打开状态,这样我才能从游标中获取值,但我又需要关闭它,这样文件才不会一直被锁住。

这是我的测试代码:

import sqlite3

def connection (db, arg, cubby):
    conn = sqlite3.connect(db)
    conn.execute('pragma foreign_keys = on')
    cur = conn.cursor()
    cur.execute(arg)
    for row in cur:
        cubby.append(row)
    conn.commit()
    conn.close()

cubby=[]
connection('testdb.db', "create table users ('user', 'email')", cubby)
connection('testdb.db', "insert into users ('user', 'email') values ('joey', 'foo@bar')", cubby)
for row in connection('testdb45.db', "select * from users", cubby):
    print row

我该怎么才能让这个工作呢?

编辑:我稍微修改了一下代码,让cur的值添加到外部列表中,但效果还是不太好。

2 个回答

0

这个问题出现是因为你的函数在返回之前就关闭了连接。要解决这个问题,可以把函数改成一个生成器,这样它就可以逐步返回结果。下面这个未经测试的代码应该可以工作:

def connection (db, arg):
    conn = sqlite3.connect(db)
    conn.execute('pragma foreign_keys = on')
    cur = conn.cursor()
    cur.execute(arg)
    for row in cur:
        yield row
    conn.commit()
    conn.close()

调用这个函数时,你需要特别注意要处理完所有的行,因为如果不处理完,连接就不会关闭。你也可以考虑实现一些必要的功能,以便使用with语法,这样可能会避免这个问题。

21

我觉得这个问题比看起来要复杂一些。

你看到这个错误是因为你在“连接”函数里关闭了和数据库的连接。

你可能更好地考虑创建一个数据库管理类,这样可以管理一个单独的连接。

可以像这样做:

import sqlite3

class DatabaseManager(object):
    def __init__(self, db):
        self.conn = sqlite3.connect(db)
        self.conn.execute('pragma foreign_keys = on')
        self.conn.commit()
        self.cur = self.conn.cursor()

    def query(self, arg):
        self.cur.execute(arg)
        self.conn.commit()
        return self.cur

    def __del__(self):
        self.conn.close()

然后你应该可以这样使用:

dbmgr = DatabaseManager("testdb.db")
for row in dbmgr.query("select * from users"):
    print row

这样做会在对象存在的期间保持连接打开。

你可能还会发现这是一个更深层次的问题,但可以试试看,看看什么对你有效。

撰写回答