基于Postgresql 事务的提交与回滚解析

用过oracle或mysql的人都知道在sqlplus或mysql中,做一个dml语句,如果发现做错了,还可以rollback;掉,但在PostgreSQL的psql中,如果执行一个dml,没有先运行begin;的话,一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,有没有什么办法避免这个风险呢?

当然有,在psql中默认是打开自动提交的,我们可以关闭自动提交,方法如下:

设置\set AUTOCOMMIT off

test=# create table test1 (x int);
CREATE TABLE
Time: 0.593 ms
test=# select * from test1;
 x
---
(0 rows)
Time: 0.309 ms
test=# rollback;
ROLLBACK
Time: 1.501 ms
test=# select * from test1;
ERROR: relation "test1" does not exist
LINE 1: select * from test1;
           ^
Time: 0.376 ms

这儿我们需要注意的是,不同步Oracle,PG的DDL事务一样是可以回滚的,并没有隐式提交的概念,这儿我们需要注意下

test=# \d
    List of relations
 Schema | Name | Type | Owner
--------+------+-------+-------
 public | foo | table | kiwi
 public | test | table | kiwi
(2 rows)

补充:PostgreSQL-事务与commit优化

基本概念

事务 Transaction 是 数据库管理系统DBMS 执行过程中的一个逻辑单元,是一个 sql命令组成的序列。

其特点在于,当事务被提交DBMS后,DBMS需要确保所有的操作被完成;如果事务中有的操作没有成功完成,那么所有操作都将回滚,回滚到事务提交之前的状态

属性

事务具有以下四个标准属性

原子性:事务作为一个整体被执行,相当于一个原子

一致性:确保修改前后数据库都满足约束

隔离性:多个事务能并发执行,互不影响

持久性:已被提交的事务对数据库的修改应该永久保存在数据库中

适用场景

某人在商店使用电子货币支付100元,包括以下两个操作:

1. 消费者账户减少100元

2. 商家账户增加100元

事务的作用就是保证这两个操作要么都发生,要么都不发生,否则可能出现100元凭空消失。

事务控制

使用如下命令控制事务

begin 或者 begin transaction:开始一个事务

commit 或者 end transaction:提交事务,执行一系列sql

rollback:事务回滚

在开始一个事务后,除非遇到 commit 或者 rollback 命令,事务才会被执行;

如果还没遇到 commit 或者 rollback,数据库发生异常,也会自动回滚。

注意,事务命令只能用于 insert、delete、update 操作,而其他命令,比如建表、删表,会被自动提交。

总结一下:事务需要手动开启,手动提交;而且这种方式能提高操作效率。

实例

假设有如下表

id | name | age | address  | salary
----+-------+-----+-----------+--------
 1 | Paul | 32 | California| 20000
 2 | Allen | 25 | Texas   | 15000
 3 | Teddy | 23 | Norway  | 20000
 4 | Mark | 25 | Rich-Mond | 65000
 5 | David | 27 | Texas   | 85000
 6 | Kim  | 22 | South-Hall| 45000
 7 | James | 24 | Houston  | 10000

操作1:开始事务,从表中删除年龄为25的记录,最后用rollback撤销所有操作

runoobdb=# BEGIN;
DELETE FROM COMPANY WHERE AGE = 25;
ROLLBACK;

结果如下

id | name | age | address  | salary
----+-------+-----+-----------+--------
 1 | Paul | 32 | California| 20000
 2 | Allen | 25 | Texas   | 15000
 3 | Teddy | 23 | Norway  | 20000
 4 | Mark | 25 | Rich-Mond | 65000
 5 | David | 27 | Texas   | 85000
 6 | Kim  | 22 | South-Hall| 45000
 7 | James | 24 | Houston  | 10000

我们发现原表没有任何改变

操作2:开始事务,从表中删除年龄为25的记录,最后用commit提交事务

runoobdb=# BEGIN;
DELETE FROM COMPANY WHERE AGE = 25;
COMMIT;

此时我们发现表中age为25的已删除。

Python 示例

time.clock()
conn = psycopg2.connect(host='172.16.89.80',user="postgres",password="postgres",database="postgres")
cur = conn.cursor()
cur.execute("BEGIN TRANSACTION")    # 开始事务
if __name__=='__main__':
  for i in range(0,1000):
    cur.execute('INSERT INTO test(a, b, c, d) VALUES (%d, %d, %d, %d);'%(i, i, i, i))
  cur.execute('commit')     # 提交事务
  cur.close()
  conn.close()
  print(time.clock())

执行成功,耗时约 2s

继续尝试

上面手动开始了事务,后面我做了如下尝试,发现耗时只有 1s      【commit 优化】

time.clock()
conn = psycopg2.connect(host='172.16.89.80',user="postgres",password="postgres",database="postgres")
cur = conn.cursor()
if __name__=='__main__':
  for i in range(0,1000):
    cur.execute('INSERT INTO test(a, b, c, d) VALUES (%d, %d, %d, %d);'%(i, i, i, i))
  conn.commit()
  cur.close()
  conn.close()
  print(time.clock())

执行了一系列sql,最后来个 commit,同样执行成功,且耗时更少,我猜测是python自动开始了事务,以 commit 命令提交,无需手动开始。【后续有空会验证下这个猜测】

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • PostgreSQL 使用raise函数打印字符串

    raise函数 在PostgreSQL中,该函数用于打印字符串,类似于Java中的System.out.println(),Oracle中的dbms_output.put_line(). 用法如下: raise notice 'My name is %, I am a %.', 'Lewis', 'coder'; 以上sql会在控制台输出My name is Lewis, I am a coder..如果是在DBeaver里使用该函数,则会在output的tab里输出字符串. raise后面的n

  • postgresql 如何关闭自动提交

    postgresql中默认是自动提交的 查看是否是自动提交: postgres=# \echo :AUTOCOMMIT on 关闭自动提交: postgres=# \set AUTOCOMMIT off postgres=# \echo :AUTOCOMMIT off 另一种方式就在会话开始的时候以begin开始相当于关闭了自动提交,以end或者commit结束就可以了 补充:pg(hgdb)默认事务自动提交 默认情况下,AUTOCOMMIT(自动提交)是开着的,也就是说任何一个SQL语句执行完

  • PostgreSQL 打印日志信息所在的源文件和行数的实例

    一直好奇在PG中, 当输出错误日志时, 如何能够附带错误信息所在的源代码文件名以及发生错误的代码行数. postgres.conf中, log信息冗余级别为"default(默认)", terse: 表示更加简单的日志信息, verbose: 表示更加冗余的日志信息(即: 附带"文件名和行数) #log_error_verbosity = default # terse, default, or verbose messages 修改为下面的"verbose&quo

  • PostgreSQL 日志文件的所在位置

    1.查看postgresql.conf文件的配置,看日志文件在哪 logging_collector = on log_directory = 'pg_log' log_filename = 'postgresql-%a.log' log_truncate_on_rotation = o 2.日志的分类 pg_log(数据库运行日志) 内容可读 默认关闭的,需要设置参数启动 pg_xlog(WAL 日志,即重做日志) 内容一般不具有可读性 强制开启 pg_clog(事务提交日志,记录的是事务的元

  • PostgreSQL 实现给查询列表增加序号操作

    利用 ROW_NUMBER() over( ) 给查询序列增加排序字段 SELECT ROW_NUMBER() over(ORDER bY biztypename DESC ) AS num,biztypename FROM (SELECT DISTINCT biztypename FROM bizmaptype) t; 效果如下: 补充:PostgreSql 使用自定义序列(Sequence)向表插入数据 id 自增长 按照以往Oracle建表的流程,我们来新建表,并且向表中导入数据. 1.创

  • Postgresql 解决pg掉电后无法重启的问题

    机房断电后重启pg数据库,报如下错误: < 2019-01-01 22:42:59.240 EST >LOG: database system was interrupted while in recovery at 2019-01-01 22:00:58 EST < 2019-01-01 22:42:59.240 EST >HINT: This probably means that some data is corrupted and you will have to use

  • PostgreSQL 恢复误删数据的操作

    在Oracle中:删除表或者误删表记录:有个闪回特性,不需要停机操作,可以完美找回记录.当然也有一些其他的恢复工具:例如odu工具,gdul工具.都可以找回数据.而PostgreSQL目前没有闪回特性.如何在不停机情况下恢复误删数据.还好是有完整的热备份. 本文描述的方法是:利用热备份在另一台服务器进行数据恢复:再导入正式环境:这样不影响数据库操作.这方法也适用在Oracle恢复.必须满足几个条件 1.有完整的基础数据文件备份和归档文件备份.所以备份是很重要的. 2.有一台装好同款Postgre

  • 利用python为PostgreSQL的表自动添加分区

    PostgreSQL引进"分区"表特性,解放了之前采用"表继承"+"触发器"来实现分区表的繁琐.低效.而添加分区,都是手动执行SQL. 演示目的:利用python来为PostgreSQL的表自动添加分区. python版本:python3+ pip3 install psycopg2 一.配置数据源 database.ini 文件:记录数据库连接参数 [adsas] host=192.168.1.201 database=adsas user=a

  • 基于Postgresql 事务的提交与回滚解析

    用过oracle或mysql的人都知道在sqlplus或mysql中,做一个dml语句,如果发现做错了,还可以rollback;掉,但在PostgreSQL的psql中,如果执行一个dml,没有先运行begin;的话,一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,有没有什么办法避免这个风险呢? 当然有,在psql中默认是打开自动提交的,我们可以关闭自动提交,方法如下: 设置\set AUTOCOMMIT off test=# create table test1 (x int); C

  • 详解Java的JDBC API中事务的提交和回滚

    如果JDBC连接是在自动提交模式下,它在默认情况下,那么每个SQL语句都是在其完成时提交到数据库. 这可能是对简单的应用程序,但有三个原因,你可能想关闭自动提交和管理自己的事务: 为了提高性能 为了保持业务流程的完整性 使用分布式事务 若要控制事务,以及何时更改应用到数据库.它把单个SQL语句或一组SQL语句作为一个逻辑单元,而且如果任何语句失败,整个事务失败. 若要启用,而不是JDBC驱动程序默认使用auto-commit模式手动事务支持,使用Connection对象的的setAutoComm

  • mysql实现事务的提交与回滚的实例详解

    最近要对数据库的数据进行一个定时迁移,为了防止在执行过程sql语句因为某些原因报错而导致数据转移混乱,因此要对我们的脚本加以事务进行控制. 首先我们建一张tran_test表 CREATE TABLE tran_test( f1 VARCHAR(10) NOT NULL, f2 INT(1) DEFAULT NULL, PRIMARY KEY (f1) )ENGINE=INNODB CHARSET=utf8 我想对tran_test插入两条数据,但是为了防止插入中报错,因此我要把插入语句控制在一

  • golang实现mysql数据库事务的提交与回滚

    MySQL 事务主要用于处理操作量大,复杂度高的数据.在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务. 事务用来管理 insert,update,delete 语句,事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行. 一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性).一致性(Consistency).隔离性(Isolation,又称独立性).持久性(Durability). 本文主要

  • mysql实现事务的提交和回滚实例

    mysql创建存储过程的官方语法为: 复制代码 代码如下: START TRANSACTION | BEGIN [WORK]COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]SET AUTOCOMMIT = {0 | 1} 我这里要说明的mysql事务处理多个SQL语句的回滚情况.比如说在一个存储过程中启动一个事务,这个事务同时往三个表中插入数据,每插完一张表需要

  • 浅谈MySQL中是如何实现事务提交和回滚的

    目录 什么是事务 redo log undo log 总结一下 什么是事务 事务是由数据库中一系列的访问和更新组成的逻辑执行单元 事务的逻辑单元中可以是一条SQL语句,也可以是一段SQL逻辑,这段逻辑要么全部执行成功,要么全部执行失败 举个最常见的例子,你早上出去买早餐,支付宝扫码付款给早餐老板,这就是一个简单的转账过程,会包含两步 从你的支付宝账户扣款10元 早餐老板的账户增加10元 这两步其中任何一部出现问题,都会导致整个账务出现问题 假如你的支付宝账户扣款10元失败,早餐老板的账户增加成功

  • Redis事务为什么不支持回滚

    目录 前言 Redis 有事务吗 Redis 事务实现原理 Redis 事务 ACID 特性 A - 原子性 C - 一致性 I - 隔离性 D - 持久性 watch 命令 watch 命令的作用 watch 原理分析 总结 前言 事务是关系型数据库的特征之一,那么作为 Nosql 的代表 Redis 中有事务吗?如果有,那么 Redis 当中的事务又是否具备关系型数据库的 ACID 四大特性呢? Redis 有事务吗 这个答案可能会令很多人感到意外,Redis 当中是存在"事务"的

  • Spring事务捕获异常后依旧回滚的解决

    目录 前沿 问题阐述 知识点前置条件 问题追踪 总结 前沿 一段生产事故发人深省,在Spring的声明式事务中手动捕获异常,居然判定回滚了,这是什么操作?话不多说直接上代码 @Service public class A {     @Autowired     private B b;     @Autowired     private C c;     @Transactional(propagation = Propagation.REQUIRED, isolation = Isolat

  • java事务回滚失败问题分析

    Spring-Java事物回滚失效处理最近在做项目中,无意间发现有个类在抛事物回滚操作,数据也正常的插入到数据库当中了,于是仔细查看看一下具体原因. 一切还是要从Java的检查型异常和非检查型异常说起. 那么什么是检查型异常什么又是非检查型异常呢? 最简单的判断点有两个: 1.继承自RuntimeException或Error的是非检查型异常,而继承自Exception的则是检查型异常(当然,RuntimeException本身也是Exception的子类). 2.对非检查型类异常可以不用捕获,

  • 基于postgresql行级锁for update测试

    创建表: CREATE TABLE db_user ( id character varying(50) NOT NULL, age integer, name character varying(100), roleid character varying, CONSTRAINT db_user_pkey PRIMARY KEY (id) ) 随便插入几条数据即可. 一.不加锁演示 1.打开一个postgreSQL的SQL Shell或pgAdmin的SQL编辑器窗口,执行: begin; s

随机推荐