Support for the SQLite database.
The following dialect/DBAPI options are available. Please refer to individual DBAPI sections for connect information.
sqlite没有内置的日期、时间或日期时间类型,并且pysqlite不提供在python之间转换值的开箱即用功能。 datetime 对象和支持sqlite的格式。SQLAlchemy自己的 DateTime
当使用sqlite时,相关类型提供日期格式和解析功能。实现类是 DATETIME
, DATE
和 TIME
. 这些类型将日期和时间表示为ISO格式的字符串,这也很好地支持排序。这些函数不依赖于典型的“libc”内部结构,因此完全支持历史日期。
为这些类型呈现的DDL是标准的 DATE
, TIME
和 DATETIME
指标。但是,自定义存储格式也可以应用于这些类型。当检测到存储格式不包含字母字符时,这些类型的DDL将呈现为 DATE_CHAR
, TIME_CHAR
和 DATETIME_CHAR
使该列继续具有文本相关性。
参见
Type Affinity -在sqlite文档中
sqlite的autoincrement的背景是:http://sqlite.org/autoinc.html
关键概念:
sqlite有一个隐式的“自动递增”特性,它适用于使用“整数主键”为类型+主键专门创建的任何非组合主键列。
sqlite还具有一个显式的“autoincrement”关键字,即 not 相当于隐式自动增量功能;建议不要将此关键字用于一般用途。除非使用特殊的sqlite特定指令,否则sqlAlchemy不会呈现此关键字(请参见下文)。但是,它仍然要求列的类型名为“integer”。
要在呈现DDL时具体呈现主键列上的autoincrement关键字,请添加标志 sqlite_autoincrement=True
到表结构:
Table('sometable', metadata,
Column('id', Integer, primary_key=True),
sqlite_autoincrement=True)
sqlite的类型模型基于命名约定。除此之外,这意味着任何包含子字符串的类型名 "INT"
将被确定为“整数亲和力”。名为 "BIGINT"
, "SPECIAL_INT"
甚至 "XYZINTQPR"
,将被sqlite视为“整数”关联。然而, 无论是隐式启用还是显式启用,sqlite autoincrement功能都要求列类型的名称正好是字符串“integer” . 因此,如果应用程序使用类似 BigInteger
对于主键,在sqlite上,需要将此类型呈现为名称 "INTEGER"
当发出初始信号时 CREATE TABLE
语句以使自动增量行为可用。
实现这一点的一种方法是 Integer
仅在sqlite上使用 TypeEngine.with_variant()
::
table = Table(
"my_table", metadata,
Column("id", BigInteger().with_variant(Integer, "sqlite"), primary_key=True)
)
另一种方法是使用 BigInteger
将其DDL名称重写为 INTEGER
根据sqlite编译时:
from sqlalchemy import BigInteger
from sqlalchemy.ext.compiler import compiles
class SLBigInteger(BigInteger):
pass
@compiles(SLBigInteger, 'sqlite')
def bi_c(element, compiler, **kw):
return "INTEGER"
@compiles(SLBigInteger)
def bi_c(element, compiler, **kw):
return compiler.visit_BIGINT(element, **kw)
table = Table(
"my_table", metadata,
Column("id", SLBigInteger(), primary_key=True)
)
SQLite不是为高级别的写并发而设计的。数据库本身是一个文件,在事务中的写操作期间完全被锁定,这意味着在此期间只有一个“连接”(实际上是一个文件句柄)对数据库具有独占访问权限-在此期间所有其他“连接”都将被阻止。
python dbapi规范还调用始终在事务中的连接模型;没有 connection.begin()
方法,仅 connection.commit()
和 connection.rollback()
立即开始新的交易。这似乎意味着,理论上,sqlite驱动程序在任何时候都只允许对特定数据库文件使用一个filehandle;但是,sqlite本身以及pysqlite驱动程序中都存在许多因素,这些因素大大放宽了这一限制。
但是,无论使用何种锁定模式,一旦启动了一个事务,并且至少发出了DML(例如插入、更新、删除),sqlite仍将始终锁定数据库文件,并且这将至少在其他事务也尝试发出DML时阻止其他事务。默认情况下,此块上的时间长度在出错超时之前非常短。
当与SQLAlchemy ORM结合使用时,此行为变得更加重要。SQLAlchemy Session
默认情况下,对象在事务中运行,并且其自动刷新模型可以在任何select语句之前发出dml。这可能导致SQLite数据库的锁定速度比预期的快。sqlite和pysqlite驱动程序的锁定模式可以在某种程度上被操作,但是需要注意的是,与sqlite实现高度的写并发是一场失败的战斗。
有关sqlite在设计上缺乏写并发性的详细信息,请参阅 Situations Where Another RDBMS May Work Better - High Concurrency 靠近页面底部。
下面的小节介绍受sqlite基于文件的体系结构影响的区域,另外,在使用pysqlite驱动程序时,通常需要解决方法才能工作。
SQLite支持非标准方式的“事务隔离”,沿着两个轴。一个是 PRAGMA read_uncommitted 指令。此设置基本上可以在其默认模式之间切换sqlite SERIALIZABLE
隔离和“脏读”隔离模式通常称为 READ UNCOMMITTED
.
sqlAlchemy使用 create_engine.isolation_level
参数 create_engine()
. 与sqlite一起使用时,此参数的有效值为 "SERIALIZABLE"
和 "READ UNCOMMITTED"
分别对应于0和1的值。sqlite默认为 SERIALIZABLE
但是,它的行为受pysqlite驱动程序的默认行为的影响。
影响sqlite事务锁定的另一个轴是通过 BEGIN
使用的语句。这三个品种是“延期”、“立即”和“独家”,如中所述。 BEGIN TRANSACTION . 笔直的 BEGIN
语句使用“延迟”模式,在第一次读或写操作之前数据库文件不会被锁定,并且读访问权在第一次写操作之前对其他事务保持打开状态。但同样重要的是要注意,pysqlite驱动程序通过 甚至没有发出开始 直到第一次写入操作。
警告
sqlite的事务范围受pysqlite驱动程序中未解决的问题的影响,该驱动程序将begin语句延迟到比通常可行的更大的程度。见剖面图 可序列化的隔离/保存点/事务性DDL 对于解决这种行为的技术。
sqlite支持保存点,该保存点只在事务开始时起作用。SQLAlchemy的保存点支持可以使用 Connection.begin_nested()
核心层面的方法,以及 Session.begin_nested()
在ORM级别。但是,保存点在pysqlite中根本不起作用,除非采取了解决方法。
警告
sqlite的保存点功能受pysqlite驱动程序中未解决的问题的影响,该驱动程序将begin语句延迟到比通常可行的更大的程度。见剖面图 可序列化的隔离/保存点/事务性DDL 对于解决这种行为的技术。
sqlite数据库支持事务性 DDL 也。在这种情况下,pysqlite驱动程序不仅无法启动事务,而且在检测到DDL时,它还会终止任何现有的事务,因此需要解决方法。
警告
sqlite的事务性ddl受pysqlite驱动程序中未解决的问题的影响,该驱动程序无法发出begin,并且在遇到ddl时强制提交以取消任何事务。见剖面图 可序列化的隔离/保存点/事务性DDL 对于解决这种行为的技术。
当为表发出CREATE语句时,SQLite支持外键语法,但是默认情况下,这些约束对表的操作没有影响。
对sqlite的约束检查有三个先决条件:
必须至少使用sqlite的3.6.19版本
必须编译sqlite库 没有 已启用sqlite_omit_foreign_键或sqlite_omit_触发器符号。
这个 PRAGMA foreign_keys = ON
在使用之前,必须在所有连接上发出语句。
SQLAlchemy允许 PRAGMA
通过使用事件自动为新连接发出的语句:
from sqlalchemy.engine import Engine
from sqlalchemy import event
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
警告
当启用sqlite外键时,它是 不可能 要为包含相互依赖的外键约束的表发出CREATE或DROP语句;要为这些表发出DDL,需要分别使用ALTER TABLE来创建或删除这些约束,而SQLite不支持这些约束。
参见
SQLite Foreign Key Support -在sqlite网站上。
事件 -SQLAlchemy事件API。
相互依赖的外键约束。
sqlite支持一个名为on conflict的非标准子句,该子句可以应用于主键、unique、check和非空约束。在DDL中,它要么在“constraint”子句中呈现,要么在列定义本身中呈现,具体取决于目标约束的位置。要在DDL中呈现此子句,扩展参数 sqlite_on_conflict
可以使用字符串冲突解决算法在 PrimaryKeyConstraint
, UniqueConstraint
, CheckConstraint
对象。内 Column
对象,有单独的参数 sqlite_on_conflict_not_null
, sqlite_on_conflict_primary_key
, sqlite_on_conflict_unique
它们分别对应于三种类型的相关约束类型,这些约束类型可以从 Column
对象。
参见
ON CONFLICT -在sqlite文档中
1.3 新版功能.
这个 sqlite_on_conflict
参数接受一个字符串参数,该参数只是要选择的解析名称,在sqlite上可以是rollback、abort、fail、ignore和replace之一。例如,要添加指定忽略算法的唯一约束,请执行以下操作:
some_table = Table(
'some_table', metadata,
Column('id', Integer, primary_key=True),
Column('data', Integer),
UniqueConstraint('id', 'data', sqlite_on_conflict='IGNORE')
)
上面将创建表DDL呈现为:
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER,
PRIMARY KEY (id),
UNIQUE (id, data) ON CONFLICT IGNORE
)
当使用 Column.unique
将唯一约束添加到单个列的标志, sqlite_on_conflict_unique
参数可以添加到 Column
同时,它将添加到DDL中的唯一约束:
some_table = Table(
'some_table', metadata,
Column('id', Integer, primary_key=True),
Column('data', Integer, unique=True,
sqlite_on_conflict_unique='IGNORE')
)
致使::
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER,
PRIMARY KEY (id),
UNIQUE (data) ON CONFLICT IGNORE
)
要对非空约束应用失败算法, sqlite_on_conflict_not_null
用途:
some_table = Table(
'some_table', metadata,
Column('id', Integer, primary_key=True),
Column('data', Integer, nullable=False,
sqlite_on_conflict_not_null='FAIL')
)
这将在冲突短语上以内联方式呈现列:
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER NOT NULL ON CONFLICT FAIL,
PRIMARY KEY (id)
)
同样,对于内联主键,使用 sqlite_on_conflict_primary_key
::
some_table = Table(
'some_table', metadata,
Column('id', Integer, primary_key=True,
sqlite_on_conflict_primary_key='FAIL')
)
SQLAlchemy单独呈现主键约束,因此冲突解决算法应用于约束本身:
CREATE TABLE some_table (
id INTEGER NOT NULL,
PRIMARY KEY (id) ON CONFLICT FAIL
)
sqlite类型不同于大多数其他数据库后端,因为类型的字符串名称通常不会以一对一的方式与“类型”对应。相反,sqlite根据类型的字符串匹配模式将每列的类型行为链接到五个所谓的“类型关联”中的一个。
当检查类型时,SQLAlchemy的反射过程使用简单的查找表将返回的关键字链接到提供的SQLAlchemy类型。此查阅表格在sqlite方言中存在,与所有其他方言一样。但是,对于查找映射中没有特定类型名称的情况,sqlite方言具有不同的“回退”例程;它实现了位于http://www.sqlite.org/datatype3.html第2.1节的sqlite“类型关联”方案。
所提供的类型映射将直接从与以下类型匹配的确切字符串名称进行关联:
BIGINT
, BLOB
,
BOOLEAN
, BOOLEAN
,
CHAR
, DATE
,
DATETIME
, FLOAT
,
DECIMAL
, FLOAT
,
INTEGER
, INTEGER
,
NUMERIC
, REAL
,
SMALLINT
, TEXT
,
TIME
, TIMESTAMP
,
VARCHAR
, NVARCHAR
,
NCHAR
当类型名称与上述类型之一不匹配时,将使用“类型关联”查找:
INTEGER
is returned if the type name includes the
string INT
TEXT
is returned if the type name includes the
string CHAR
, CLOB
or TEXT
NullType
is returned if the type name includes the
string BLOB
REAL
如果类型名称包含字符串,则返回 REAL
, FLOA
或 DOUB
.
否则, NUMERIC
使用类型。
0.9.3 新版功能: 反射列时支持SQLite类型关联规则。
部分索引,例如使用WHERE子句的索引,可以使用该参数与DDL系统一起指定。 sqlite_where
::
tbl = Table('testtbl', m, Column('data', Integer))
idx = Index('test_idx1', tbl.c.data,
sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10))
索引将在创建时呈现为:
CREATE INDEX test_idx1 ON testtbl (data)
WHERE data > 5 AND data < 10
0.9.9 新版功能.
使用其中显式包含句点的表或列名称是 未推荐的 . 对于关系数据库来说,这通常是一个坏主意,因为点是一个语法上有意义的字符,所以sqlite驱动程序直到版本 3.10.0 sqlite有一个bug,它要求sqlAlchemy在结果集中过滤掉这些点。
在 1.1 版更改: 从3.10.0版的sqlite开始,以下sqlite问题已得到解决。SQLAlchemy自 1.1 根据此版本的检测自动禁用其内部解决方案。
完全不属于sqlAlchemy的bug可以通过以下方式进行说明:
import sqlite3
assert sqlite3.sqlite_version_info < (3, 10, 0), "bug is fixed in this version"
conn = sqlite3.connect(":memory:")
cursor = conn.cursor()
cursor.execute("create table x (a integer, b integer)")
cursor.execute("insert into x (a, b) values (1, 1)")
cursor.execute("insert into x (a, b) values (2, 2)")
cursor.execute("select x.a, x.b from x")
assert [c[0] for c in cursor.description] == ['a', 'b']
cursor.execute('''
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
''')
assert [c[0] for c in cursor.description] == ['a', 'b'], \
[c[0] for c in cursor.description]
第二个断言失败:
Traceback (most recent call last):
File "test.py", line 19, in <module>
[c[0] for c in cursor.description]
AssertionError: ['x.a', 'x.b']
在上面的地方,驱动程序错误地报告列的名称,包括表的名称,这与不存在联合时完全不一致。
sqlAlchemy依赖于列名在如何与原始语句匹方法面是可预测的,因此sqlAlchemy方言除了筛选这些之外别无选择:
from sqlalchemy import create_engine
eng = create_engine("sqlite://")
conn = eng.connect()
conn.execute("create table x (a integer, b integer)")
conn.execute("insert into x (a, b) values (1, 1)")
conn.execute("insert into x (a, b) values (2, 2)")
result = conn.execute("select x.a, x.b from x")
assert result.keys() == ["a", "b"]
result = conn.execute('''
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
''')
assert result.keys() == ["a", "b"]
注意上面,尽管SQLAlchemy过滤掉了这些点, 两个名称仍然可以寻址 ::
>>> row = result.first()
>>> row["a"]
1
>>> row["x.a"]
1
>>> row["b"]
1
>>> row["x.b"]
1
因此,sqlAlchemy应用的解决方案只会影响 ResultProxy.keys()
和 RowProxy.keys()
在公共API中。在非常特殊的情况下,应用程序必须使用包含点的列名以及 ResultProxy.keys()
和 RowProxy.keys()
需要返回这些未修改的点式名称, sqlite_raw_colnames
可提供执行选项,可根据 -Connection
依据:
result = conn.execution_options(sqlite_raw_colnames=True).execute('''
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
''')
assert result.keys() == ["x.a", "x.b"]
或按 -Engine
依据:
engine = create_engine("sqlite://", execution_options={"sqlite_raw_colnames": True})
使用PER时 -Engine
执行选项,注意 使用联合的核心查询和ORM查询可能无法正常工作 .
与所有的sqlAlchemy方言一样,已知对sqlite有效的所有大写类型都可以从顶级方言导入,无论它们是否源自 sqlalchemy.types
或者来自当地方言:
from sqlalchemy.dialects.sqlite import \
BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, \
INTEGER, NUMERIC, JSON, SMALLINT, TEXT, TIME, TIMESTAMP, \
VARCHAR
sqlalchemy.dialects.sqlite.
DATETIME
(*args, **kwargs)¶基地: sqlalchemy.dialects.sqlite.base._DateTimeMixin
, sqlalchemy.types.DateTime
使用字符串在sqlite中表示python datetime对象。
默认字符串存储格式为::
"%(year)04d-%(month)02d-%(day)02d %(hour)02d:%(min)02d:%(second)02d.%(microsecond)06d"
例如。::
2011-03-15 12:05:57.10558
可以使用 storage_format
和 regexp
参数,例如:
import re
from sqlalchemy.dialects.sqlite import DATETIME
dt = DATETIME(storage_format="%(year)04d/%(month)02d/%(day)02d "
"%(hour)02d:%(min)02d:%(second)02d",
regexp=r"(\d+)/(\d+)/(\d+) (\d+)-(\d+)-(\d+)"
)
sqlalchemy.dialects.sqlite.
DATE
(storage_format=None, regexp=None, **kw)¶基地: sqlalchemy.dialects.sqlite.base._DateTimeMixin
, sqlalchemy.types.Date
使用字符串在sqlite中表示python日期对象。
默认字符串存储格式为::
"%(year)04d-%(month)02d-%(day)02d"
例如。::
2011-03-15
可以使用 storage_format
和 regexp
参数,例如:
import re
from sqlalchemy.dialects.sqlite import DATE
d = DATE(
storage_format="%(month)02d/%(day)02d/%(year)04d",
regexp=re.compile("(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)")
)
sqlalchemy.dialects.sqlite.
JSON
(none_as_null=False)¶sqlite json类型。
从3.9版起,sqlite通过其 JSON1 延伸。注意 JSON1 是一个 loadable extension 因此可能不可用,或者可能需要运行时加载。
这个 sqlite.JSON
类型支持JSON值的持久性以及由提供的核心索引操作 types.JSON
数据类型,通过调整操作来呈现 JSON_EXTRACT
函数包装在 JSON_QUOTE
数据库级别的函数。引用提取的值以确保结果始终是JSON字符串值。
1.3 新版功能.
参见
sqlalchemy.dialects.sqlite.
TIME
(*args, **kwargs)¶基地: sqlalchemy.dialects.sqlite.base._DateTimeMixin
, sqlalchemy.types.Time
使用字符串在sqlite中表示python时间对象。
默认字符串存储格式为::
"%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
例如。::
12:05:57.10558
可以使用 storage_format
和 regexp
参数,例如:
import re
from sqlalchemy.dialects.sqlite import TIME
t = TIME(storage_format="%(hour)02d-%(minute)02d-"
"%(second)02d-%(microsecond)06d",
regexp=re.compile("(\d+)-(\d+)-(\d+)-(?:-(\d+))?")
)
通过pysqlite驱动程序支持sqlite数据库。请注意,pysqlite与python发行版中包含的sqlite3模块是相同的驱动程序。
Documentation and download information (if applicable) for pysqlite is available at: http://docs.python.org/library/sqlite3.html
当使用python 2.5及更高版本时,内置的 sqlite3
驱动程序已安装,不需要额外安装。否则, pysqlite2
司机必须在场。这是同一个司机 sqlite3
只是换了个名字。
这个 pysqlite2
将首先加载驱动程序,如果找不到, sqlite3
已加载。这允许显式安装的pysqlite驱动程序优先于内置驱动程序。与所有方言一样,可以向 create_engine()
要明确控制这一点:
from sqlite3 import dbapi2 as sqlite
e = create_engine('sqlite+pysqlite:///file.db', module=sqlite)
sqlite数据库的文件规范被视为URL的“数据库”部分。请注意,sqlAlchemy URL的格式为:
driver://user:pass@host/database
这意味着要使用的实际文件名以 正确的 第三个斜线。因此,连接到相对文件路径的方式如下:
# relative path
e = create_engine('sqlite:///path/to/database.db')
绝对路径(以斜线开头)表示您需要 four 斜线:
# absolute path
e = create_engine('sqlite:////path/to/database.db')
要使用Windows路径,可以使用常规的驱动器规格和反斜杠。可能需要双反斜杠:
# absolute path on Windows
e = create_engine('sqlite:///C:\\path\\to\\database.db')
SQLite :memory:
如果不存在文件路径,则默认为标识符。指定 sqlite://
除此之外:
# in-memory database
e = create_engine('sqlite://')
pysqlite驱动程序包括sqlite3.parse_decltypes和sqlite3.parse_colnames选项,这些选项具有显式转换为“日期”或“时间戳”的任何列或表达式的效果,将转换为python日期或日期时间对象。pysqlite方言提供的日期和日期时间类型当前与这些选项不兼容,因为它们呈现的是包括微秒在内的ISO日期/日期时间,而pysqlite的驱动程序不提供微秒。此外,SQLAlchemy此时不会自动呈现独立函数“current_timestamp”和“current_date”以本机返回日期时间/日期类型所需的“cast”语法。不幸的是,pysqlite没有在 cursor.description
,使SQLAlchemy无法在不进行昂贵的每行类型检查的情况下即时检测这些类型。
请记住,不建议使用pysqlite的解析选项,也不应使用该选项。如果在create_engine()上配置“native_datetime=true”,则可以强制使用parse_decltypes:
engine = create_engine('sqlite://',
connect_args={'detect_types':
sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES},
native_datetime=True
)
启用此标志后,日期和时间戳类型(但请注意,不是日期时间或时间类型…还不清楚?)不会执行任何绑定参数或结果处理。执行“func.current_date()”将返回字符串。func.current_timestamp()“注册为在sqlAlchemy中返回日期时间类型,因此此函数仍接收sqlAlchemy级别的结果处理。
pysqlite的默认行为是禁止在多个线程中使用单个连接。这最初是为了与在各种情况下不支持多线程操作的旧版本的sqlite一起使用。特别是,旧的sqlite版本不允许 :memory:
在任何情况下都要在多个线程中使用的数据库。
pysqlite不包括现在未记录的标志,即 check_same_thread
这将禁用此检查,但是请注意,在多个线程中并发使用pysqlite连接仍然不安全。特别是,任何语句执行调用都需要在外部进行互斥,因为pysqlite不提供错误消息的线程安全传播。所以即使当 :memory:
在现代的sqlite中,数据库可以在线程之间共享,而pysqlite没有提供足够的线程安全性来保证这种使用的价值。
sqlAlchemy设置池以使用pysqlite的默认行为:
当A :memory:
指定了sqlite数据库,默认情况下方言将使用 SingletonThreadPool
. 此池为每个线程维护一个连接,以便当前线程内对引擎的所有访问都使用相同的连接 :memory:
数据库-其他线程将访问 :memory:
数据库。
当指定了基于文件的数据库时,方言将使用 NullPool
作为联系的来源。此池关闭并丢弃立即返回池的连接。基于sqlite文件的连接开销非常低,因此不需要池。该方案还防止在不同的线程中再次使用连接,并且最好使用sqlite的粗粒度文件锁定。
使用A :memory:
数据库在多线程方案中,同一个连接对象必须在线程之间共享,因为该数据库只存在于该连接的范围内。这个 StaticPool
实现将在全球保持单一连接,并且 check_same_thread
标志可以作为 False
::
from sqlalchemy.pool import StaticPool
engine = create_engine('sqlite://',
connect_args={'check_same_thread':False},
poolclass=StaticPool)
注意,使用 :memory:
多线程中的数据库需要最新版本的sqlite。
由于sqlite处理临时表的方式,如果您希望在基于文件的sqlite数据库中跨连接池的多个签出使用临时表,例如使用ORM时 Session
临时表应在此后继续保留的位置 Session.commit()
或 Session.rollback()
调用时,必须使用维护单个连接的池。使用 SingletonThreadPool
如果作用域仅在当前线程中需要,或者 StaticPool
对于这种情况,多个线程中是否需要作用域:
# maintain the same connection per thread
from sqlalchemy.pool import SingletonThreadPool
engine = create_engine('sqlite:///mydb.db',
poolclass=SingletonThreadPool)
# maintain the same connection across all threads
from sqlalchemy.pool import StaticPool
engine = create_engine('sqlite:///mydb.db',
poolclass=StaticPool)
注意 SingletonThreadPool
应该针对要使用的线程数进行配置;超过该数目,连接将以非确定性方式关闭。
pysqlite驱动程序只返回python unicode
结果集中的对象,而不是纯字符串,并且 unicode
在所有情况下,绑定参数值中的对象。不管使用的是什么sqlachemy字符串类型,基于字符串的结果值都将由python unicode
在Python 2中。这个 Unicode
但是,类型仍应用于指示那些需要Unicode的列,因此无意中传递的非“unicode”值将发出警告。如果传递包含非ASCII字符的非“unicode”字符串,则pysqlite将发出错误。
在本节中 数据库锁定行为/并发性 ,我们参考了pysqlite驱动程序的各种问题,这些问题阻止了sqlite的几个功能正常工作。pysqlite DBAPI驱动程序有几个长期存在的错误,这些错误会影响其事务行为的正确性。在其默认操作模式中,SQLite功能(如可序列化隔离、事务性DDL和保存点支持)是不起作用的,为了使用这些功能,必须采取解决方法。
问题实质上是,驱动程序试图再次猜测用户的意图,未能启动事务,有时过早地结束事务,以尽量减少sqlite数据库的文件锁定行为,即使sqlite本身对只读活动使用“共享”锁。
默认情况下,SQLAlchemy选择不更改此行为,因为这是Pysqlite驱动程序的长期预期行为;如果并且当Pysqlite驱动程序尝试修复这些问题时,这将更像是SQLAlchemy的默认驱动程序。
好消息是,通过一些事件,我们可以通过完全禁用pysqlite的特性并发出begin-self来完全实现事务支持。这是通过两个事件监听器实现的:
from sqlalchemy import create_engine, event
engine = create_engine("sqlite:///myfile.db")
@event.listens_for(engine, "connect")
def do_connect(dbapi_connection, connection_record):
# disable pysqlite's emitting of the BEGIN statement entirely.
# also stops it from emitting COMMIT before any DDL.
dbapi_connection.isolation_level = None
@event.listens_for(engine, "begin")
def do_begin(conn):
# emit our own BEGIN
conn.execute("BEGIN")
上面,我们截获了一个新的pysqlite连接并禁用了任何事务集成。然后,在SQLAlchemy知道事务范围即将开始的时候,我们发出 "BEGIN"
我们自己。
当我们控制 "BEGIN"
,我们还可以直接控制sqlite的锁定模式,在 BEGIN TRANSACTION ,通过将所需的锁定模式添加到 "BEGIN"
::
@event.listens_for(engine, "begin")
def do_begin(conn):
conn.execute("BEGIN EXCLUSIVE")
参见
BEGIN TRANSACTION -在sqlite站点上
sqlite3 SELECT does not BEGIN a transaction -在python bug跟踪器上
sqlite3 module breaks transactions and potentially corrupts data -在python bug跟踪器上
Support for the SQLite database via the pysqlcipher driver.
pysqlcipher
是标准的叉子 pysqlite
司机利用 SQLCipher 后端。
pysqlcipher3
是一把叉子 pysqlcipher
对于Python 3。如果 pysqlcipher
是不存在的。
1.1.4 新版功能: -为pysqlcipher3添加了回退导入
0.9.9 新版功能: -添加了pysqlcipher方言
Documentation and download information (if applicable) for pysqlcipher is available at: https://pypi.python.org/pypi/pysqlcipher
这里的司机是 pysqlcipher 驱动程序,它使用sqlcipher引擎。这个系统本质上向sqlite引入了新的pragma命令,它允许设置密码和其他加密参数,从而允许对数据库文件进行加密。
pysqlcipher3 是一把叉子 pysqlcipher 对于python 3的支持,驱动程序是相同的。
连接字符串的格式与 pysqlite
驱动程序,除了"password"字段现在被接受,它应该包含一个密码短语:
e = create_engine('sqlite+pysqlcipher://:testing@/foo.db')
对于绝对文件路径,数据库名称应使用两个前导斜杠::
e = create_engine('sqlite+pysqlcipher://:testing@//path/to/foo.db')
如https://www.zettic.net/sqlcipher/sqlcipher-api/所述,sqlcipher支持的其他与加密相关的pragma的选择可以在查询字符串中传递,并将导致为每个新连接调用该pragma。目前, cipher
, kdf_iter
cipher_page_size
和 cipher_use_hmac
支持:
e = create_engine('sqlite+pysqlcipher://:testing@/foo.db?cipher=aes-256-cfb&kdf_iter=64000')
驱动程序更改pysqlite的默认池行为,如中所述。 线程/池行为 . 据观察,pysqlicpher驱动程序在连接上比pysqlite驱动程序慢得多,这很可能是由于加密开销,因此这里的方言默认使用 SingletonThreadPool
实现,而不是 NullPool
pysqlite使用的池。和往常一样,池实现是完全可配置的,使用 create_engine.poolclass
参数; StaticPool
可能更适合单线程使用,或 NullPool
可以用来防止未加密的连接长时间保持打开状态,代价是新连接的启动时间变慢。