- 浏览: 174036 次
- 来自: ...
文章分类
最新评论
-
fsword:
同事拿着试了一下,说是把第五步放到第二步之前就可以了
在windows下安装ruby1.9.2,rails3.0.3和DevKit--转 -
dothwinds:
[flash=200,200][/flash][url][/u ...
打包ruby or rails成exe(英文)
SQLite中如何用触发器执行取消和重做逻辑
<script></script>标签:
知识/探索 |
<!-- 正文开始 -->
这页主要描述一个使用SQLite作为主要数据结构的应用程序如何使用触发器去执行取消和重做逻辑。
我的想法是创建一个特殊的表格(例如名为撤销记录),表格保存数据库撤销和重做变化所需的信息。因为数据库中的每个表格都需要参与撤销和重做,每个DELETE,INSERT,和UPDATE都生成了触发器,DELETE,INSERT,和UPDATE可以在撤销日志表格中生成登记项,这个登记项将撤销操作。撤销表格中的登记项由一般的SQL语句组成,为了完成撤销,SQL语句可以被重新运行。
例如,如果你想在类似下面表格中执行撤销或重:
CREATE TABLE ex1(a,b,c);
Then triggers would be created as follows:
CREATE TEMP TRIGGER _ex1_it AFTER INSERT ON ex1 BEGIN INSERT INTO undolog VALUES(NULL,'DELETE FROM ex1 WHERE rowid='||new.rowid); END; CREATE TEMP TRIGGER _ex1_ut AFTER UPDATE ON ex1 BEGIN INSERT INTO undolog VALUES(NULL,'UPDATE ex1 SET a='||quote(old.a)||',b='||quote(old.b)||',c='||quote(old.c)||' WHERE rowid='||old.rowid); END; CREATE TEMP TRIGGER _ex1_dt BEFORE DELETE ON ex1 BEGIN INSERT INTO undolog VALUES(NULL,'INSERT INTO ex1(rowid,a,b,c) VALUES('||old.rowid||','||quote(old.a)||','||quote(old.b)|| ','||quote(old.c)||')'); END;
在ex1表格中执行每个INSERT后, the _ex1_it 触发器生成DELETE语句的文本,它将撤销INSERT操作。 The _ex1_ut触发器生成UPDATE语句,这语句将取消一个UPDATE所产生的作用。_ex1_dt触发器生成一个语句,这语句将取消一个 DELETE所具有的作用。
要注意quote()函数在这些触发器中的使用。quote()函数在SQLite中是标准的。它把它的参数转换成一种适合被包含在 SQL语句中的形式。数字值不改变。单个的quotes被加在字符串之前或之后,任何内在的单个quotes都被逃逸。quote()函数被加入 SQLite是为了执行撤销和重做操作。
当然,你也可以像上面一样用手生成触发器。但这个技术最突出的特点就是这些触发器可以自动生成。
例子中编码的语言是TCL。使用其它语言也是可以的,但是有可能要做更多工作。记住,这里的编码是demonstration技术,不是一个方便的模式,不能自动的为你做每件事。下面所示的demonstration编码是源于程序执行过程中所使用的真实的代码。但你在使用它的时候,为了满足你的需要,你需要做些改变。
为了激活撤销和重做的逻辑,激活要参加撤销和重做的所有种类的(表格)undo::activate指令作为参数。用undo::deactivate, undo::freeze, and undo::unfreeze来控制undo/redo机制的状态。
The undo::activate指令在数据库中生成临时的触发器,它记录表格中所有被命名为参数的变化。
在一系列的改变定义了一个单独的undo/redo步骤后,激活undo::barrier指令来定义那步的局限性。在一个交互式的程序中,在做任何改动后,你可以调用undo::event,undo::barrier将被自动调用作为一个等待的回调。
当使用者按下Undo按钮,激活undo::undo。当使用者按下Redo按钮,激活undo::redo。
在调用undo::undo or undo::redo,undo/redo模块将自动在所有顶级有名字的空间激活程序status_refresh和reload_all。这些程序应该被定义用来重建画面,或者更新基于undone/redon在数据库中变化的程序的状态。
下面的 demonstration代码包含一个status_refresh程序,它激活Undo and Redo按钮,根据没做的和要重做的事来选菜单。你需要重新定义这个程序,用来涉及特定的Undo和Redo按钮,为你的应用线则进入菜单。这里所提供的执行只是一个例子。demonstration代码假定SQLite数据库是用一个名为"db"的句柄打开的。对于一个内置内存的数据库来说,合适的指令应如下:
sqlite3 db :memory:
这里是demonstration代码:
# 每件事都在一个私有的有名称的空间里进行
namespace eval ::undo {
# proc: ::undo::activate TABLE ...
# title: Start up the undo/redo system
#
# 参数应是在一个或多个数据库表格(在数据库中和句柄"db"相关联)
# 它们的变化被记录下来是为了撤销和重做的目的。
proc activate {args} {
variable _undo
if {$_undo(active)} return
eval _create_triggers db $args
set _undo(undostack) {}
set _undo(redostack) {}
set _undo(active) 1
set _undo(freeze) -1
_start_interval
}
# proc: ::undo::deactivate
# title: Halt the undo/redo system and delete the undo/redo stacks
#
proc deactivate {} {
variable _undo
if {!$_undo(active)} return
_drop_triggers db
set _undo(undostack) {}
set _undo(redostack) {}
set _undo(active) 0
set _undo(freeze) -1
}
# proc: ::undo::freeze
# title: Stop accepting database changes into the undo stack
#
# 当这个例行程序被启用直到下一步被解冻前,新的数据库的变化将不被记录在撤销存储栈。
#
proc freeze {} {
variable _undo
if {![info exists _undo(freeze)]} return
if {$_undo(freeze)>=0} {error "recursive call to ::undo::freeze"}
set _undo(freeze) [db one {SELECT coalesce(max(seq),0) FROM undolog}]
}
# proc: ::undo::unfreeze
# title: Begin accepting undo actions again.
#
proc unfreeze {} {
variable _undo
if {![info exists _undo(freeze)]} return
if {$_undo(freeze)<0} {error "called ::undo::unfreeze while not frozen"}
db eval "DELETE FROM undolog WHERE seq>$_undo(freeze)"
set _undo(freeze) -1
}
# proc: ::undo::event
# title: Something undoable has happened
#
# 当一个不可撤销的操作发生的时候调用这个程序。在下一个空闲时刻之前激活::undo::barrier。
#
proc event {} {
variable _undo
if {$_undo(pending)==""} {
set _undo(pending) [after idle ::undo::barrier]
}
}
# proc: ::undo::barrier
# title: Create an undo barrier right now.
#
proc barrier {} {
variable _undo
catch {after cancel $_undo(pending)}
set _undo(pending) {}
if {!$_undo(active)} {
refresh
return
}
set end [db one {SELECT coalesce(max(seq),0) FROM undolog}]
if {$_undo(freeze)>=0 && $end>$_undo(freeze)} {set end $_undo(freeze)}
set begin $_undo(firstlog)
_start_interval
if {$begin==$_undo(firstlog)} {
refresh
return
}
lappend _undo(undostack) [list $begin $end]
set _undo(redostack) {}
refresh
}
# proc: ::undo::undo
# title: Do a single step of undo
#
proc undo {} {
_step undostack redostack
}
# proc: ::undo::redo
# title: Redo a single step
#
proc redo {} {
_step redostack undostack
}
# proc: ::undo::refresh
# title: Update the status of controls after a database change
#
# 基于现行数据库的状态,为了合理的进行控制,撤销模块在任何撤销和重做后调用这个例行程序。
这个模块通过激活所有顶级有名称的空间中的status_refresh模块来工作。
#
proc refresh {} {
set body {}
foreach ns [namespace children ::] {
if {[info proc ${ns}::status_refresh]==""} continue
append body ${ns}::status_refresh\n
}
proc ::undo::refresh {} $body
refresh
}
# proc: ::undo::reload_all
# title: Redraw everything based on the current database
#
# 为了使屏幕在数据库内容的基础上被完全重新绘图,撤销模块在任何的撤销和重做后都调用这个
# 例行程序。通过在每个顶级的有名称的空间调用"reload" 模块而不是::undo来完成这个程序。
proc reload_all {} {
set body {}
foreach ns [namespace children ::] {
if {[info proc ${ns}::reload]==""} continue
append body ${ns}::reload\n
}
proc ::undo::reload_all {} $body
reload_all
}
##############################################################################
# 这个模块的公共接口程序在上面。例行程序和变量静态追踪(名字以"_"开头的)是这个模块私有的。
##############################################################################
# state information
#
set _undo(active) 0
set _undo(undostack) {}
set _undo(redostack) {}
set _undo(pending) {}
set _undo(firstlog) 1
set _undo(startstate) {}
# proc: ::undo::status_refresh
# title: Enable and/or disable menu options a buttons
#
proc status_refresh {} {
variable _undo
if {!$_undo(active) || [llength $_undo(undostack)]==0} {
.mb.edit entryconfig Undo -state disabled
.bb.undo config -state disabled
} else {
.mb.edit entryconfig Undo -state normal
.bb.undo config -state normal
}
if {!$_undo(active) || [llength $_undo(redostack)]==0} {
.mb.edit entryconfig Redo -state disabled
.bb.redo config -state disabled
} else {
.mb.edit entryconfig Redo -state normal
.bb.redo config -state normal
}
}
# xproc: ::undo::_create_triggers DB TABLE1 TABLE2 ...
# title: Create change recording triggers for all tables listed
#
# 在数据库中创建一个名为"undolog"的临时表格。创建可以激发任何 insert, delete, or update of TABLE1, TABLE2, ....的触发器。
# 当这些触发器激发的时候,insert records in 在未做日志中插入记录,这些未做日志中包含SQL语句的文本,这些语句将撤销insert, delete,或update。
#
proc _create_triggers {db args} {
catch {$db eval {DROP TABLE undolog}}
$db eval {CREATE TEMP TABLE undolog(seq integer primary key, sql text)}
foreach tbl $args {
set collist [$db eval "pragma table_info($tbl)"]
set sql "CREATE TEMP TRIGGER _${tbl}_it AFTER INSERT ON $tbl BEGIN\n"
append sql " INSERT INTO undolog VALUES(NULL,"
append sql "'DELETE FROM $tbl WHERE rowid='||new.rowid);\nEND;\n"
append sql "CREATE TEMP TRIGGER _${tbl}_ut AFTER UPDATE ON $tbl BEGIN\n"
append sql " INSERT INTO undolog VALUES(NULL,"
append sql "'UPDATE $tbl "
set sep "SET "
foreach {x1 name x2 x3 x4 x5} $collist {
append sql "$sep$name='||quote(old.$name)||'"
set sep ","
}
append sql " WHERE rowid='||old.rowid);\nEND;\n"
append sql "CREATE TEMP TRIGGER _${tbl}_dt BEFORE DELETE ON $tbl BEGIN\n"
append sql " INSERT INTO undolog VALUES(NULL,"
append sql "'INSERT INTO ${tbl}(rowid"
foreach {x1 name x2 x3 x4 x5} $collist {append sql ,$name}
append sql ") VALUES('||old.rowid||'"
foreach {x1 name x2 x3 x4 x5} $collist {append sql ,'||quote(old.$name)||'}
append sql ")');\nEND;\n"
$db eval $sql
}
}
# xproc: ::undo::_drop_triggers DB
# title: Drop all of the triggers that _create_triggers created
#
proc _drop_triggers {db} {
set tlist [$db eval {SELECT name FROM sqlite_temp_master
WHERE type='trigger'}]
foreach trigger $tlist {
if {![regexp {^_.*_(i|u|d)t$} $trigger]} continue
$db eval "DROP TRIGGER $trigger;"
}
catch {$db eval {DROP TABLE undolog}}
}
# xproc: ::undo::_start_interval
# title: Record the starting conditions of an undo interval
#
proc _start_interval {} {
variable _undo
set _undo(firstlog) [db one {SELECT coalesce(max(seq),0)+1 FROM undolog}]
}
# xproc: ::undo::_step V1 V2
# title: Do a single step of undo or redo
#
# For an undo V1=="undostack" and V2=="redostack". For a redo,
# V1=="redostack" and V2=="undostack".
#
proc _step {v1 v2} {
variable _undo
set op [lindex $_undo($v1) end]
set _undo($v1) [lrange $_undo($v1) 0 end-1]
foreach {begin end} $op break
db eval BEGIN
set q1 "SELECT sql FROM undolog WHERE seq>=$begin AND seq<=$end
ORDER BY seq DESC"
set sqllist [db eval $q1]
db eval "DELETE FROM undolog WHERE seq>=$begin AND seq<=$end"
set _undo(firstlog) [db one {SELECT coalesce(max(seq),0)+1 FROM undolog}]
foreach sql $sqllist {
db eval $sql
}
db eval COMMIT
reload_all
set end [db one {SELECT coalesce(max(seq),0) FROM undolog}]
set begin $_undo(firstlog)
lappend _undo($v2) [list $begin $end]
_start_interval
refresh
}
# End of the ::undo namespace
}
发表评论
-
DBDesigner使用笔记 --转,改
2011-08-18 10:26 1382DBDesigner使用笔记 表格之间的关系 ... -
DBDesigner4连接mysql出错的处理
2011-08-18 10:12 1296DBDesigner自mysql4.0之后没有更新对新版mys ... -
数据库设计经验谈-- 转
2011-08-01 17:42 738一个成功的管理系统,是由:[50% 的业务 + 50% ... -
两个数据库设计实例--转
2011-08-01 16:58 4233(注:摘自 http://blog. ... -
数据库设计三大范式应用实例剖析--转
2011-08-01 13:04 795引言 数据库的设计范式是数据库设计所需要满足的规范,满 ... -
SQLite Foreign Key Support --sqlite3.6.19--from sqlite.org
2011-07-30 12:30 1373Table Of Contents 1. Intro ... -
sqlite3 --sql命令简单介绍(zt)--转
2011-04-23 22:46 1672sqlite3 --sql命 ... -
SQLite3 C/C++ 开发接口简介(API函数)1(zt)--转
2011-04-23 22:44 1108SQLite3 C/C++ 开发接 ... -
SQLite3 C/C++ 开发接口简介(API函数) 二(zt)--转
2011-04-23 22:43 1396SQLite3 C/C++ 开发接口简介(API函数 ... -
SQLite适用的范围(zt)-转
2011-04-23 22:40 758SQLite适用的范围(zt) (2007-12- ... -
SQLite的体系结构简介(zt)--转
2011-04-23 22:39 1048SQLite的体系结构简 ... -
SQLite 第三版总览(简介)--转
2011-04-23 22:38 1266SQLite 第三版总览 SQLite 第三版主要 ... -
董淳光SQLITE3 使用总结(1)--转
2011-04-23 22:36 957董淳光SQLITE3 使用总结(1) 转载 ... -
董淳光SQLITE3 使用总结(2)--转
2011-04-23 22:34 1288董淳光SQLITE3 使用 ... -
董淳光SQLITE3 使用总结(3)-转
2011-04-23 22:30 943董淳光SQLITE3 使用总结(3) 转载 ... -
董淳光SQLITE3 使用总结(4)--转
2011-04-23 22:26 1152董淳光SQLITE3 使用总结(4) 转载 ... -
董淳光SQLITE3 使用总结(5)--转
2011-04-23 22:17 1403董淳光SQLITE3 使用总结(5) 转载 ... -
Oracle 常用函数
2008-12-04 12:08 723SQL中的单记录函数 1.ASCII 返回与指定的字符对应 ...
相关推荐
sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器sqlite 触发器...
赠送jar包:sqlite-jdbc-3.34.0.jar; 赠送原API文档:sqlite-jdbc-3.34.0-javadoc.jar; 赠送源代码:sqlite-jdbc-3.34.0-sources.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。
2. 为了方便命令行执行,将sqlite3.exe放到svn 项目的主目录下,和.svn目录同级下。 3. cmd进入该目录下,执行 sqlite3 .svn/wc.db "select * from work_queue".看到有4条记录。就是刚才我执行的一些操作。 226539|...
赠送jar包:sqlite-jdbc-3.15.1.jar; 赠送原API文档:sqlite-jdbc-3.15.1-javadoc.jar; 赠送源代码:sqlite-jdbc-3.15.1-sources.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。
2. 为了方便命令行执行,将sqlite3.exe放到svn 项目的主目录下,和.svn目录同级下。 3. 执行 sqlite3 .svn/wc.db "select * from work_queue".看到有4条记录。就是刚才我执行的一些操作。 226539|(sync-file-flags ...
最近在做数码相框上的嵌入式开发,开发过程中使用的SQLite数据库,但是编码的过程中,遇到个问题,SQLite不支持外键约束,外键约束会被解析但不会被执行。
sqlite-netFx40-setup-bundle-x86-2010-1.0.113.0.exe
sqlite-shell-win32-x86-3080200.zip sqlite的windows版本
sqlite库下载,国外太慢了 Precompiled Binaries for Windows sqlite-dll-win64-x64-3300100.zip (788.50 KiB) 64-bit DLL (x64) for SQLite version 3.30.1. (sha1: 725eb6588492b5728993815a6e5f0f8f08ddfcb4...
sqlite-jdbc-3.36.0.3.jar 最新吧2021 8月底更新
GeoServer2.15的MBtilesStore插件:geoserver-2.15-SNAPSHOT-gwc-sqlite-plugin.zip
sqlite-netFx46-binary-bundle-x64-2015-1.0.113.0.zip
sqlite-3.7.15&sqlite-jdbc-3.7.15 sqlite是sourceforge上的资源,sqlite-jdbc是Maven上的资源
sqlite-netFx40-setup-bundle-x64-2010-1.0.113.0
如题 sqlite .net 源码包 sqlite-netFx-source-1.0.86.0
sqlite-tools-linux-x86-3350400.zip
在发行部分中,您可以下载pg2sqlite.jar的预构建版本。 如何建造 git clone https://github.com/caiiiycuk/postgresql-to-sqlite.git cd postgresql-to-sqlite sbt one-jar cp target/scala-2.11/postgresql-to-...
sqlite工具:sqldiff、sqlite3、sqlite3_analyzer
赠送jar包:sqlite-jdbc-3.34.0.jar; 赠送原API文档:sqlite-jdbc-3.34.0-javadoc.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语对照,边学技术、边学英语。
Sqlite Developer是SharpPlus出品的一款强大数据库管理软件。支持对sqlite3数据库的管理。 SharpPlus Sqlite Developer 特性: -强大的SQL编辑器 *Sqlite Sql语法高亮 *Sql编辑历史 *Sql关键字自动完成 *...