为啥查询sqlite数据库时需要创建游标?

Posted

技术标签:

【中文标题】为啥查询sqlite数据库时需要创建游标?【英文标题】:Why do you need to create a cursor when querying a sqlite database?为什么查询sqlite数据库时需要创建游标? 【发布时间】:2011-09-13 04:07:30 【问题描述】:

我对@9​​87654321@(和一般的SQL)完全陌生,这完全让我难过。大量缺乏对cursor objects 的描述(更确切地说,它们的必要性)似乎也很奇怪。

这个sn-p的代码是首选的做事方式:

import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()

这个不是,即使它工作得一样好并且没有(看似毫无意义的)cursor

import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()

谁能告诉我为什么我需要cursor? 这似乎是毫无意义的开销。对于脚本中访问数据库的每个方法,我都应该创建和销毁cursor? 为什么不直接使用connection 对象?

【问题讨论】:

【参考方案1】:

在我看来只是一个误用的抽象。 db 游标是一种抽象,用于数据集遍历。

来自Wikipedia article on subject:

在计算机科学和技术中,数据库游标是一个控件 允许遍历数据库中记录的结构。 光标与 遍历,例如数据库的检索、添加和删除 记录。遍历的数据库游标特性使得游标 类似于迭代器的编程语言概念。

还有:

游标不仅可以用于将数据从 DBMS 提取到 应用程序,还可以识别表中要更新的行或 删除。 SQL:2003 标准定义了定位更新和 为此目的定位删除 SQL 语句。这样的陈述确实 不要使用带有谓词的常规 WHERE 子句。相反,一个光标 标识行。光标必须已打开且已定位 通过 FETCH 语句在一行上。

如果您检查docs on Python sqlite module,您可以看到即使CREATE TABLE 语句也需要python 模块cursor,因此它用于仅connection 对象就足够的情况 - 正如正确指出的那样由 OP。这种抽象不同于人们对 db 游标的理解,因此,用户的困惑/沮丧。不管效率如何,这只是概念上的开销。如果在文档中指出 python 模块 cursor 与 SQL 和数据库中的游标有点不同,那就太好了。

【讨论】:

+1 承认“传统”数据库游标和 Python 中用于数据库的游标之间(起初)非常令人困惑的区别 其实也可以直接create a table even without using a cursor。 游标的使用似乎与您提供的定义一致:“数据库游标是一种控制结构,可以遍历数据库中的记录”。例如c.execute('''SELECT * FROM users''') 返回一个迭代器,您可以在该迭代器上调用fetchall()(或其他游标方法)。一些 SQL 查询返回空迭代器,但这应该是意料之中的,并不奇怪。【参考方案2】:

根据官方docsconnection.execute() 是一个非标准快捷方式,它创建了一个中间光标对象:

连接.执行 这是一个非标准的快捷方式,它通过调用 cursor() 方法创建一个游标对象,使用给定的参数调用游标的 execute() 方法,并返回游标。

【讨论】:

【参考方案3】:

您需要一个游标对象来获取结果。您的示例有效,因为它是 INSERT,因此您不会尝试从中获取任何行,但是如果您查看 sqlite3 docs,您会注意到连接上没有任何 .fetchXXXX 方法对象,因此如果您尝试在没有游标的情况下执行 SELECT,您将无法获取结果数据。

游标对象允许您跟踪哪个结果集是哪个结果集,因为您可以在完成获取第一个结果之前运行多个查询。

【讨论】:

另外值得记住的是:PEP 249 没有在连接对象上定义execute,这是一个sqlite3 扩展。 它仍然适用于 SELECT 语句:pastebin.com/5ZbhfEn7。原因是您没有在连接对象上调用任何 .fetchXXXX 方法,而是在连接的 .execute() 方法返回的对象上调用 .fetchXXXX 方法。 是的。但是,您最终会得到一个(看似)不必要的游标来查询数据库:p 显式使用游标是一个养成的好习惯,因为您将来可能会从事的项目不会自动提交。 很公平。感谢您的信息:)【参考方案4】:

12.6.8。使用 sqlite3 高效ly

12.6.8.1。使用快捷方式方法

使用 Connection 对象的 非标准 execute()executemany()executescript() 方法,您的代码可以写得更简洁,因为您不需要必须显式地创建(通常是多余的)Cursor 对象。相反,Cursor 对象是隐式创建的,并且这些快捷方法返回光标对象。这样,您可以执行 SELECT 语句并直接使用对 Connection 对象的单个调用对其进行迭代。

(sqlite3 documentation;强调我的。)

为什么不直接使用连接对象?

因为连接对象的那些方法是 nonstandard,即它们不是 Python Database API Specification v2.0 (PEP 249) 的一部分。

只要您使用 Cursor 对象的标准方法,您就可以确定,如果您切换到遵循上述规范的另一个数据库实现,您的代码将是完全可移植的。也许您只需要更改import 行。

但如果您使用connection.execute,则切换可能不会那么简单。这就是您可能想要改用 cursor.execute 的主要原因。

但是,如果您确定不会切换,我会说使用 connection.execute 快捷方式并“高效”是完全可以的。

【讨论】:

【参考方案5】:

它使我们能够通过同一个数据库连接拥有多个独立的工作环境。

【讨论】:

以上是关于为啥查询sqlite数据库时需要创建游标?的主要内容,如果未能解决你的问题,请参考以下文章

SQLite SELECT MAX() 查询返回 null 到游标?

如何在 SQLite 数据库上使用游标

如何从 sqlite 游标中获取列值?

如何在android中使用游标(sqlite查询)搜索数据库

从 Sqlite 游标创建 Pojo 类花费了太多时间

SQLite Android数据库游标窗口分配2048 kb失败