`
javachs
  • 浏览: 120646 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

sqlite的编码

阅读更多
编码

使用多个连接
如果你曾经为其它的关系型数据库编写过程序,你就会发现有些适用于那些数据库的方法不一定适用于SQLite。使用其它数据库时,经常会在同一个代码块中打开多个连接,典型的例子就是在一个连接中返复遍历一个表而在另一个连接中修改它的记录。
在SQLite中,在同一个代码块中使用多个连接会引起问题,必须小心地对待这种情况。请看下面代码:
c1 = open('foods.db')
c2 = open('foods.db')

stmt = c1.prepare('SELECT * FROM episodes')
while stmt.step()
    print stmt.column('name')
    c2.exec('UPDATE episodes SET …)
end
stmt.finalize()

c1.close()
c2.close()
问题很明显,当c2试图执行UPDATE时,c1拥有一个SHARED锁,这个锁只有等stmt.finalize()之后才会释放。所以,是不可能成功写数据库的。最好的办法是在一个连接中完成工作,并且在同一个BEGIN IMMEDIATE事务中完成。新程序如下:
c1 = open('foods.db')

# Keep trying until we get it
while c1.exec('BEGIN IMMEDIATE') != SQLITE_OK
end

stmt = c1.prepare('SELECT * FROM episodes')
while stmt.step()
    print stmt.column('name')
    c1.exec('UPDATE episodes SET …)
end
stmt.finalize()

c1.exec('COMMIT')
c1.close()
在这种情况下,你应该在单独的连接中使用语句(statement)来完成读和写,这样,你就不必担心数据库锁会引发问题了。但是,这个特别的示例仍然不能工作。如果你在一个语句(statement)中返复遍历一个表而在另一个语句中修改它的记录,还有一个附加的锁问题你需要了解,我们将在下面介绍。
表锁
即使只使用一个连接,在有些边界情况下也会出现问题。不要认为一个连接中的两个语句(statements)就能协调工作,至少有一个重要的例外。
当在一个表上执行了SELECT命令,语句对象会在表上创建一个B-tree游标。如果表上有一个活动的B-tree游标,即使是本连接中的其它语句也不能够再修改这个表。如果做这种尝试,将会得到SQLITE_BUSY。看下面的例子:
c = sqlite.open("foods.db")
stmt1 = c.compile('SELECT * FROM episodes LIMIT 10')

while stmt1.step() do
    # Try to update the row
    row = stm1.row()
    stmt2 = c.compile('UPDATE episodes SET …')
    # Uh oh: ain't gonna happen
    stmt2.step()
end

stmt1.finalize()
stmt2.finalize ()
c.close()
这里我们只使用了一个连接。但当调用stmt2.step()则不会工作,因为stmt1拥有episodes表的一个游标。在这种情况下,stmt2.step()有可能成功地将锁升级到EXCLUSIVE,但仍会返回SQLITE_BUSY,因为episodes的游标会阻止它修改表。完成这种操作有两种方法:
 遍历一个语句的结果集,在内存中保存需要的信息。定案这个读语句,然后执行修改操作。
 将SELECT的结果存到一个临时表中并用读游标打开它。这时同时有一个读语句和一个写语句,但它们在不同的表上,所以不会影响主表上的写操作。写完成后,删掉临时表就是了。
当表上打开了一个语句,它的B-tree游标在两种情况下会被移除:
 到达了语句结果集的尾部。这时step()会自动地关闭语句的游标。从VDBE的角度,当到达结果集的尾部时,CDBE遇到Close命令,这将导致所有相关游标的关闭。
 程序显式地调用了finalize(),所有相关游标将关闭。
在很多编程语言扩展中,statement对象的close()函数会自动调用sqlite3_finalize()。
有趣的临时表
临时表使你可以做到不违反规则。如果你确实需要在一个代码块中使用两个连接,或者使用两个语句(statement)操作同一个表,你可以安全地在临时表上如此做。当一个连接创建了一个临时表,不需要得到RESERVED锁,因为临时表存在于数据库文件之外。有两种方法可以做到这一点,看你想如何管理并发。请看如下代码:
c1 = open('foods.db')
c2 = open('foods.db')

c2.exec('CREATE TEMPORARY TABLE temp_epsidodes as SELECT * from episodes')
stmt = c1.prepare('SELECT * FROM episodes')
while stmt.step()
    print stmt.column('name')
    c2.exec('UPDATE temp_episodes SET …')
end
stmt.finalize()

c2.exec('BEGIN IMMEDIATE')
c2.exec('DELETE FROM episodes')
c2.exec('INSERT INTO episodes SELECT * FROM temp_episodes')
c2.exec('COMMIT')

c1.close()
c2.close()
上面的例子可以完成功能,但不好。episodes表中的数据要全部删除并重建,这将丢失episodes表中的所有完整性约束和索引。下面的方法比较好:
c1 = open('foods.db')
c2 = open('foods.db')

c1.exec('CREATE TEMPORARY TABLE temp_episodes as SELECT * from episodes')
stmt = c1.prepare('SELECT * FROM temp_episodes')
while stmt.step()
    print stmt.column('name')
    c2.exec('UPDATE episodes SET …') # What about SQLITE_BUSY?
end
stmt.finalize()

c1.exec('DROP TABLE temp_episodes')
c1.close()
c2.close()
定案的重要性
使用SELECT语句必须要意识到,其SHARED锁(大多数时候)直到finalize()被调用后才会释放,请看下面代码:
stmt = c1.prepare('SELECT * FROM episodes')
while stmt.step()
    print stmt.column('name')
end
c2.exec('BEGIN IMMEDIATE; UPDATE episodes SET …; COMMIT;')
stmt.finalize()
如果你用C API写了与上例等价的程序,它实际上是能够工作的。尽管没有调用finalize(),但第二个连接仍然能够修改数据库。在告诉你为什么之前,先来看第二个例子:
c1 = open('foods.db')
c2 = open('foods.db')

stmt = c1.prepare('SELECT * FROM episodes')
stmt.step()
stmt.step()
stmt.step()

c2.exec('BEGIN IMMEDIATE; UPDATE episodes SET …; COMMIT;')

stmt.finalize()
假设episodes中有100条记录,程序仅仅访问了其中的3条,这时会发生什么情况呢?第2个连接会得到SQLITE_BUSY。
在第1个例子中,当到达语句结果集尾部时,会释放SHARED锁,尽管还没有调用finalize()。在第2个例子中,没有到达语句结果集尾部,SHARED锁没有释放。所以,c2不能执行UPDATE操作。
这个故事的中心思想是:不要这么做,尽管有时这么做是可以的。在用另一个连接进行写操作之前,永远要先调用finalize()。
共享缓冲区模式
现在你对并发规则已经很清楚了,但我还要找些事来扰乱你。SQLite提供一种可选的并发模式,称为共享缓冲区模式,它允许在单一的线程中操作多个连接。
在共享缓冲区模式中,一个线程可以创建多个连接来共享相同的页缓冲区。进而,这组连接可以有多个“读”和一个“写”同时工作于相同的数据库。缓冲区不能在线程间共享,它被严格地限制在创建它的线程中。因此,“读”和“写”就需要准备处理与表锁有关的一些特殊情况。
当 readers读表时, SQLite自动在这些表上加锁,writer就不能再改这些表了。如果writer试图修改一个有读锁的表,会得到SQLITE_LOCKED。如果readers运行在read-uncommitted模式(通过read_uncommitted pragma来设置),则当readers读表时,writer也可以写表。在这种情况下,SQLite不为readers所读的表加读锁,结果就是readers和writer互不干扰。也因此,当一个writer修改表时,这些readers可能得到不一致的结果。

分享到:
评论

相关推荐

    sqlite测试用数据库(utf8编码,繁体字)

    sqlite测试用数据库(utf8编码,繁体字)

    fltk+sqlite设计的编码生成器

    这是一个用FLTK+sqlite编写的一个编码分配器,编程语言为C++。关于FLTK是一个C++ GUI库,更多信息请访问(http://www.fltk.org/index.php)。关于sqlite的更多信息请访问(http://www.sqlite.org/index.html)。 为...

    android Sqlite城市编码表带city_num

    城市编码附带city_num

    VC++6/MFC操作SQLITE3(创建,查询,插入,删除等操作)以及中文编码插入与显示,使用VC6下的sqlite控件

    VC++6/MFC操作SQLITE3(创建,查询,插入,删除等操作)以及中文编码插入与显示,使用VC6下的sqlite控件

    sqlite常见问题中文

    sqlite_libencoding —— 返回SQLite库(SQLite library)的编码(encoding)。 sqlite_libversion —— 返回SQLite库(SQLite library)的版本。 sqlite_next —— 返回下一行的行号。 sqlite_num_fields —— 取得...

    VC++2015/MFC操作SQLITE3(创建,查询,插入,删除等操作)以及中文编码插入与显示,VC2015的sqlite控件

    VC++2015/MFC操作SQLITE3(创建,查询,插入,删除等操作)以及中文编码插入与显示,VC2015的sqlite控件

    SQLite C# 多字符集支持

    海康储存文本是c++用gb2312存储的,而sqlite默认是以utf8编码存储的,System.Data.SQLite默认也是以utf8进行存取的。 结果读取出来后的中文字符都是乱码。 查了网上的资料,这个问题存在已久,歪果仁官方似乎也没有...

    SQLiteStudio-2.1.5执行文件,SQLite可视化工具

    sqlitestudio是一款可以帮助用户管理sqlite数据库的工具,该sqlite数据库管理工具具有功能完善的sqlite2和sqlite3工具,视图编码支持utf8,还可以同时打开多个数据库文件,软件支持查看和编辑二进制字段。sqlite...

    sqlite3.36集成加密版_vs2008

    sqlite3.36集成加密版_vs2008,实现了sqlite3_key,sqlite3_rekey接口。VS2008多字节工程。

    sqlite汉字拼音对照表

    sqlite汉字拼音对照表,有 常用汉字表6986个 和 gbk汉字库21000个 两张表,带汉字的gbk编码

    sqlitestudio

    功能完善的sqlite2和sqlite3工具,视图编码支持utf8。 支持导出数据格式:csv、html、plain、sql、xml, 可同时打开多个数据库文件 支持查看和编辑二进制字段

    sqlitestudio-3.1.1

    SQLiteStudio中文版是一款可以帮助用户管理sqlite数据库的工具,该sqlite数据库管理工具具有功能完善的sqlite2和sqlite3工具,视图编码支持utf8,还可以同时打开多个数据库文件。SQLiteStudio中文版支持查看和编辑二...

    WP7开发 Sqlite数据库的使用 解决编码问题

    WP7本身不支持Sqlite数据库,但我们可以添加第三方组件让它支持Sqlite. 首先在项目中添加引用Community.CsharpSqlite.WP.dll,编译了一下,直接引用就可以了. 因为网上下得源码 在查询特殊字符时候 报错 比如“大” ...

    SQLite3中文编码 Python的实现

    读取十万多条文本写入SQLite类型数据库,由于文本中存在中文字符,插入到数据库没错,取出时一直是UnicodeDecodeError,导致折腾了一天。 最后的解决方法: Python连接数据时进行如下设置: ...以上这篇SQLite3中文编码

    Sqlite3数据库支持库2.0#2版(静态版)

    数据库内部文本编码为UTF-8。易语言sqlite3_static.lib支持库为静态支持库,需要易系统5.0版本的支持,需要系统核心支持库5.0版本的支持,提供了10种库定义数据类型,提供了230种命令。操作系统需求: Windows、...

    sqlite数据库存取中文乱码的全部解决方案

    sqlite数据库存取中文乱码的全部解决方案(包括其它数据库oracle+sqlserver+mysql) 数据库的连接方式、数据库里存放数据的字体编码、所选编程语言的缺省字体编码。如果在编程中遇到不能正确显示中文时、、、、

    SQLiteStudio

    SqliteStudio 是一个可视化的Sqlite工具,功能完善的sqlite2和sqlite3工具,视图编码支持utf8,支持导出数据格式:csv、html、plain、sql、xml,可同时打开多个数据库文件,支持查看和编辑二进制字段

    WP7开发 Sqlite数据库的使用 解决汉字 编码问题

    WP7本身不支持Sqlite数据库,但我们可以添加第三方组件让它支持Sqlite. 首先在项目中添加引用Community.CsharpSqlite.WP.dll,编译了一下,直接引用就可以了. 因为网上下得源码 在查询特殊字符时候 报错 比如“大” ...

    C# sqlite 中文乱码的解决方法

    可以解决中文乱码问题,共享给大家,解决UTF-8 转换 gb2312,直接放到Bin目录中并引用

Global site tag (gtag.js) - Google Analytics