在lightdb/pg中,事務是自動提交的,也就是除非明確通過BEGIN;開啓事務,否則任何語句都是獨立事務。在ltsql客戶端,可以通過\echo :AUTOCOMMIT查看自動提交模式,如下:
[zjh@hs-10-20-30-193 ~]$ ltsql -p9999 ltsql (13.3-22.2) Type "help" for help. zjh@postgres=# \echo :AUTOCOMMIT on zjh@postgres=# \set AUTOCOMMIT off zjh@postgres=# \echo :AUTOCOMMIT off zjh@postgres=#
因爲ltsql是客戶端工具,不是libpq/ltjdbc實現,所以它不具典型意義。
強制自動提交,無參數控制有個缺點,對於一些oracle/mysql不會提交的場景也會自動提交,而我們認爲它不會提交。如explain analyze,如下:
zjh@postgres=*# select count(1) from scott.departments where dept_id<10000; count ------- 64 (1 row) zjh@postgres=*# explain analyze update scott.departments set dept_id=dept_id+10000 where dept_id<10000; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- Update on departments (cost=0.00..54236.67 rows=396542 width=236) (actual time=688.890..688.892 rows=0 loops=1) -> Seq Scan on departments (cost=0.00..54236.67 rows=396542 width=236) (actual time=0.015..688.719 rows=64 loops=1) Filter: (dept_id < 10000) Rows Removed by Filter: 6024736 Planning Time: 0.089 ms Execution Time: 689.190 ms (6 rows) zjh@postgres=*# select count(1) from scott.departments where dept_id<10000; count ------- 0 (1 row)
explain analyze實際上被提交了,而如果數據被修改後和原來的數據不唯一,就可能無法恢復。這是非常麻煩的。
要正確執行更新,需要先BEGIN,然後rollback,如下:
zjh@postgres=# begin; BEGIN zjh@postgres=*# select count(1) from scott.departments where dept_id<20000; count ------- 64 (1 row) zjh@postgres=*# explain analyze update scott.departments set dept_id=dept_id+10000 where dept_id<20000; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Update on departments (cost=0.00..54236.67 rows=396542 width=236) (actual time=694.907..694.908 rows=0 loops=1) -> Seq Scan on departments (cost=0.00..54236.67 rows=396542 width=236) (actual time=694.636..694.654 rows=64 loops=1) Filter: (dept_id < 20000) Rows Removed by Filter: 6024736 Planning Time: 0.064 ms Execution Time: 695.004 ms (6 rows) zjh@postgres=*# rollback; ROLLBACK zjh@postgres=# select count(1) from scott.departments where dept_id<20000; count ------- 64 (1 row)
因爲這很難控制,因此lightdb在內核中基於隱藏字段實現自動更新時間戳,能夠記錄行最後更新時間,這樣能夠做到恢復。如下:
zjh@postgres=# create table test_lut(id int) WITH UPDATE CURRENT_TIMESTAMP; WARNING: LightDB DDL check warn! keyword not allowed with [column name]:id WARNING: LightDB DDL check warn! no primary key! WARNING: LightDB DDL check warn! no gmt_create or no gmt_modified! CREATE TABLE zjh@postgres=# insert into test_lut values(1); INSERT 0 1 zjh@postgres=# select * from test_lut ; id ---- 1 (1 row) zjh@postgres=# \dS+ test_lut Table "public.test_lut" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+-----------------------------+-----------+----------+-------------------+---------+--------------+------------- id | integer | | | | plain | | ltaut | timestamp without time zone | | | CURRENT_TIMESTAMP | plain | | Access method: heap zjh@postgres=# select id,ltaut from test_lut ; id | ltaut ----+---------------------------- 1 | 2022-06-11 20:53:47.295945 (1 row) zjh@postgres=# update test_lut set id=id+1; UPDATE 1 zjh@postgres=# select id,ltaut from test_lut ; id | ltaut ----+---------------------------- 2 | 2022-06-11 20:54:33.041471 (1 row)