1. 事务基本概念:
1. 原子性:
一个事务的所有操作,要么全部执行,要么全部不执行。
2. 一致性:
执行事务时保持数据库从一个一致的状态变更到另一个一致的状态。
3. 隔离性:
即使每个事务都能确保一致性和原子性,如果并发执行时,由于它们的操作以人们不希望的方式交叉运行,就会导致不一致的情况发生。确保事务与事务并发执行时,每个事务都感觉不到有其它事务在并发的执行。
2. 四种隔离级别:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 序列化异常 |
---|---|---|---|---|
read uncommitted | 不可能 | 可能 | 可能 | 可能 |
read committed | 不可能 | 可能 | 可能 | 可能 |
repeatable read | 不可能 | 不可能 | 不可能 | 可能 |
serializable | 不可能 | 不可能 | 不可能 | 不可能 |
2.1 查看和设置数据库的事务隔离级别:
# 查看全局事务隔离级别:
select name,setting from pg_settings where name='default_transaction_isolation';
# 修改全局事务隔离级别:
方法一:修改postgresql.conf配置文件中的default_transaction_isolation。
方法二:
alter system set default_transaction_isolation to 'repeatable read';
pg_ctl reload
# 查看当前会话的事务隔离级别:
show transaction_isolation;
# 设置当前会话的事务隔离级别:
set session characteristics as transaction isolation level read uncommitted;
# 设置当前事务的隔离级别:
begin isolation level read uncommitted read write;
commit;
3. 并发问题模拟
3.1 脏读问题: 🤷♂️
PG中不存在未提交读隔离级别,显示使用未提交读隔离级别时,PG内部会使用为提交读隔离级别处理,脏读在PG中不会发生。
# 脏读演示:(PG数据无法演示脏读,请用其它数据库)
create table tb1_mvcc (id serial not null primary key,ival int);
insert into tb1_mvcc (ival) values (1);
会话一:
set session transaction isolation level read uncommitted;
begin;
会话二:
set session transaction isolation level read uncommitted;
begin;
update tb1_mvcc set ival=10 where id=1;
会话一:
select * from tb1_mvcc where id=1;
会话二:
rollback;
3.2 不可重复读问题:
# 不可重复读:
会话一:
begin transaction isolation level read committed;
会话二:
begin;
update tb1_mvcc set ival=10 where id=1;
commit;
会话一:
select * from tb1_mvcc where id=1;
end;
3.3 幻读问题:
# 幻读
create table tb1_mvcc (id serial not null primary key,ival int);
insert into tb1_mvcc (ival) select generate_series(1,5);
会话一:
begin transaction isolation level read committed;
select id,ival from tb1_mvcc where id>3 and id<10;
会话二:
begin;
insert into tb1_mvcc (ival) values (6);
commit;
会话一:
select id,ival from tb1_mvcc where id>3 and id<10;
end;
3.4 序列化一场问题:
# 序列化异常:
create table tb1_mvcc (id serial not null primary key,ival int);
insert into tb1_mvcc (ival) values (1);
会话一:
begin transaction isolation level repeatable read;
select * from tb1_mvcc where id=1;
会话二:
update tb1_mvcc set ival=10 where id=1;
会话一:
update tb1_mvcc set ival= ival+1 where id=1;
rollback;
# 不可能出现幻读:
create table tb1_mvcc (id serial not null primary key,ival int);
insert into tb1_mvcc (ival) select generate_series(1,5);
会话一:
begin transaction isolation level repeatable read;
select id,ival from tb1_mvcc where id>3 and id<10;
会话二:
begin;
insert into tb1_mvcc (ival) values (6);
commit;
会话一:
select id,ival from tb1_mvcc where id>3 and id<10;
end;
4. 使用pg_repack解决表膨胀:
# 安装pg_repack工具:
## yum安装:(yum安装的repack只能针对yum安装的pg)
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install pg_repack13 -y
vi /etc/profile
export PATH=/usr/pgsql-13/bin:$PATH
## 源码安装:
yum install gcc postgresql-devel postgresql-static zlib-devel readline-devel -y
unzip pg_repack-master.zip
cd pg_repack-master
make && make install
pg_repack --version
# 创建pg_repack扩展:
create extension pg_repack;
# 进行对表进行重建:
pg_repack -t t1 -j 2 -D -k -U postgres -d postgres
1. 表膨胀的直接触发因素是表上的大量更新,如全表的update操作、大量的insert+delete操作等
2. 一个update操作执行后,被更改的数据的旧版本也被保留下来,直到对表做vacuum操作的时候,才考虑回收旧版本。
3. 旧版本不及时回收就会造成表膨胀
特点:
1. 更新过数据的事务,长时间不提交会造成表膨胀,只读的事务也是同样的,也要及时提交,同时避免在存在大量更新操作的实例上,跑运行时间很长的查询语句。
避免表膨胀的方法:
1. 尽早的、及时的提交事务;
2. 设计应用时,要使事务尽量短小;
3. 注意配置与应用规模相适应的硬件资源(IO能力、CPU、内存等),并调教好数据库,使其性能最优,避免有些事务因为资源或性能问题长时间无法完成;
4. 提交autovacuum,使其能按合理的周期运行。这方面的内容,我们今后专门介绍;
5. 定期监控系统中是否有长事务,可以使用下面的SQL监控持续时间超过一定时间的事务