PB中 autocommit 和 commitondisconnect 两个连接参数的应用

想必大致了解PB的朋友都知道 transaction 的 autocommit 属性,但是我知道很多朋友对这个属性了解得并不很透彻,在今天晚上之前,我也如此,刚才仔细查了一下关于这些属性的东西,明白了一些,现在写下来,权当现炒现卖了,呵呵。

        AutoCommit

        the automatic commit indicator (SQL Server only).

       pb帮助中简单的这样描述这个属性,自动提交的指示器,只针对 SQL SERVER 数据库。

       但有时候我们看到了令人十分费解的的现象。当我们将全局的trsaction 的 autocommit 置为 false 我们在数据窗口的保存脚本中,仅仅简单的写上一句 dw_1.update(),并不进行commit; ,数据窗口是能够进行更新的。

       这看起来视乎非常不可思议,这样的话,autocommit 有何意义呢?commit 又有何意义呢?

       大家忽略了一个另外的参数commitondisconnect 这只是 数据库的一个连接参数,并不是transaction 的一个属性。他的含义是:如果该值为“yes”,那么不管autocommit 是true还是false,在disconnect之前,如果还没有没有提交的DML,transaction将会自动的提交一次。

       这样我们上面碰到的问题就不能解释了。注意这个参数的默认值是YES,也就是说如果你不主动的这样设置的话   SQLCA.DBParm = "CommitOnDisconnect='No'"   ,你所做的修改将会保存进数据库。这个看似实用的功能却经常会给我们带来麻烦,导致数据的不一致性。

      例如 当一个较长的事务执行了前面几步尚未Commit时发生数据库连接断开(非法操作、强行退出、死机等)此时会发生已执行的SQL不能回滚,但在退出前transaction 会自做多情地 将已经执行但还没来得及提交的DML 提交,从而导致数据错误(如库存已加但入库单却未打上入库标志)   为防止此类错误发生应设置为:数据库连接断开前不自动提交,即CommitOnDisconnect='No'

     再回到最开始提出的那个问题,如果我们将CommitOnDisconnect置为 yes,而 autoCommit 置为 false的话,将会发生更加严重的后果,就是 如果我们在 程序中 有 DML 或者 数据窗口的update()时如果,我们忘了手动的Commit的话,被操做的那个或那些表将会被锁住,其余的人不能访问,或者已经将表的数据读到本地,但不能保存,直到第一个人访问该表的那个Transaction 断开连接。

      上面说的是忘了写commit的情况,实际上即使你写了,commit ,如果commit和DML或者update()如果相隔太远的话,也会在执行DML或者update()   和 执行 commit 之间的时间内被锁住

     可以试着做这样一个实例来验证:

      假设有表t_test ,仅一个字段 test   numeric 10

     做一个数据窗口对象 d_test,其SQL语句为 select test from t_test

     做一个窗口 w_test,有如下控件 dw_1 ,cb_new,cb_save,cb_commit,cb_disconnect,cb_exit

      窗口open事件为   dw_1.dataobject = 'd_test'

                                dw_1.settransobject(sqlca)

                                  dw_1.retrieve()

      按钮的click 事件分别为 cb_new :dw_1.scrolltorow(dw_1.insertrow(0))

                                            cb_save:dw_1.update()

                                           cb_commit:commit;

                                          cb_disconnect:disconnect;

                                          cb_exit:close(parent)

      当然 Application 的open事件里要将autocommit 设为 FALSE 将commitondisconnect 设为 yes

典型代码为为

SQLCA.DBMS = "MSS Microsoft SQL Server 6.x"
SQLCA.Database = "qhet"
SQLCA.ServerName = "."
SQLCA.LogId = "sa"
SQLCA.AutoCommit = false
SQLCA.DBParm = "CommitOnDisconnect='yes'"
connect using sqlca;

open(w_test)

运行后点new 按钮,填上符合的数据后,点 save ,然后,在PB的数据库画板中执行任何关于表t_test的sql语句均无法执行,如select * from t_test,将会一直处于等待中,直到你点按钮 commit 或者 disconnect 中的任何一个,sql语句才能得以执行。

上面这个小例子模拟了以上所说的过程。

以前我曾遇到过遇到过这些问题,当时不知道什么原因,现在总算恍然大悟了。

那么我们该怎么解决这个问题了.

可以这样,我们将autocommit 设为true,将commitondisconnect 设为 no,

autocommit 设为true 有如下好处,1.如果我们的更新很简单,比如仅仅涉及对一个表,那么我们可以仅仅写一条 upate()就行了,将commit 或rollback的工作交给tansaction 来完成,考虑oracle和其他数据库,最好不要这样做,但如果确定是针对 SQLserver的,这样做师妹有问题的。

                                                       2.杜绝了上面说的长时间等待的情况,即使我们忘了写commit,程序会自动commit,其他用户不用等待。

但这样做又有一个隐患,即如果要对多个表进行更新,我么不能简单的将commit和rollback 托付给transaction,如果我们这样做将会使数据不完整,也就是说transaction将会自动 一个表一个表的commit或者rollback,这样就会出现如 订单数据保存进数据库,但订单明细没有保存进数据库 的问题

我们可以这样来处理一下

做以下三个全局函数

//************************************

gf_begin_transaction

//参数ao_environment 类型 transaction

//返回值类型 boolean

ao_Environment.AutoCommit = False
if ao_Environment.SQLCode<>0 then return False
return True

   //***********************************************

//**********************************************

gf_commit_transaction//参数返回值同前一个

Commit Using ao_Environment;
if ao_Environment.SQLCode<>0 then return False
ao_Environment.AutoCommit = True
if ao_Environment.SQLCode<>0 then return False
return True

//************************************************

//************************************************

gf_rollback_transaction//参数返回值同前一个

Rollback Using ao_Environment;
if ao_Environment.SQLCode<>0 then return False
ao_Environment.AutoCommit = True
if ao_Environment.SQLCode<>0 then return False
return True

//********************************************

这样我们一旦又多个表更新的情况可以使用l类似这样的结构来处理

gf_begin_transaction(SQLCA)

dw_1.update()

dw_2.update()

delete from table_1......

insert into table_2 ......

...................

...............

if sqlca.sqlcode = 0 then

gf_commit_transaction(sqlca)

retrun

else

gf_rollback_transaction(sqlca)

//error handle code here

end if

考虑到autocommit对除了sqlserver以外的其他数据库不起作用,我们可以在每一个需要更新的地方都已这三个函数来包围。

这样就可以万无一失了。

说明:1.autocommit 仅对sqlserver 起作用,而commitondisconnect 对大多数数据库都起作用,可以查看相应DBMS的手册

           2.autocommit 仅在 PB 脚本中起作用,而在数据库画板中是不起作用的,不如即使你在database profile 中将 autocommit 设为false,在数据库画板中执行的DML语句也会马上被commit掉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值