Практикум
Подготовка
-
Откройте два графических эмулятора терминала или же просто два терминала. Задайте в них переменной PS1 такой вид приглашения командной строки, чтобы их можно было отличить друг от друга.
В первом терминале (далее будем выделять синим цветом):
[student@p620 ~]$ PS1=$(echo $PS1 | sed 's/\\h/TERM1/') [student@TERM1 ~]$
Во втором (красный цвет для отличия):
[student@p620 ~]$ PS1=$(echo $PS1 | sed 's/\\h/TERM2/') [student@TERM2 ~]$
В примере для первого терминала в приглашении командной строки теперь видно
TERM1
, а во втором терминале -TERM2
. Вид приглашения командной строки оболочки Shell задает переменнаяPS1
(Prompt String). -
В третьей вкладке или терминале запустите оболочку от имени postgres и зайдите в сеанс psql (черный цвет для отличия):
[student@p620 ~]$ sudo -iu postgres [postgres@p620 ~]$ psql
psql (15.5)
Type "help" for help.
postgres=# -
Сбросьте все настройки в
postgresql.auto.conf
, выполнив командуALTER SYSTEM RESET ALL
:postgres=# alter system reset all; ALTER SYSTEM
-
В одном из сеансов
student
перезапустите сервер PostgreSQL:[student@TERM1 ~]$ sudo systemctl restart postgresql
-
Рестартуйте сессию
postgres
в клиенте psql:postgres=# \c
You are now connected to database "postgres" as user "postgres". postgres=# -
Удалите все БД, кроме
template1
,template0
иpostgres
:postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access
privileges
-----------+----------+----------+------------+------------+------------+-----------------+---------
arch_db | student | UTF8
localdb | postgres | UTF8
postgres | postgres | UTF8
repbase | postgres | UTF8
student | student | UTF8
template0 | postgres | UTF8
|| template1 | postgres | UTF8
||
(7 rows)
postgres=# DROP DATABASE arch_db; DROP DATABASE
postgres=# DROP DATABASE localdb; DROP DATABASE
postgres=# DROP DATABASE repbase; DROP DATABASE
postgres=# DROP DATABASE student; DROP DATABASEЭти БД были удалены в качестве примера. В Вашей системе набор БД может быть другой, получите его в сеансе postgres в psql метакомандой
\l
. -
В СУБД должны быть зарегистри рованы только две роли:
postgres
иstudent
. Все остальные роли должны быть удалены:postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
dbuser1 | | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
student |
user1 |
postgres=# DROP ROLE dbuser1; DROP ROLE
postgres=# DROP ROLE user1; DROP ROLEМетакоманда
\du
выводит в psql список зарегистрированных в СУБД ролей. -
Создайте БД student, владельцем которой будет роль
student
:postgres=# CREATE DATABASE student OWNER student; CREATE DATABASE
postgres=# \l student
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access | privileges
---------+---------+----------+------------+------------+------------+-----------------+------------
student | student | UTF8 | en_US.UTF8 | en_US.UTF8 | | libc |
(1 row)
Транзакции
-
В первом терминале зайдите в сеанс ролью
student
, подключившись к одноименной БД:[student@TERM1 ~]$ psql psql (15.5)
Type "help" for help.
student@student=> SELECT user; user
---------
student
(1 row)
student@student=> SELECT current_catalog; current_catalog
-----------------
student
(1 row)Функция SQL user возвращает имя роли в сеансе, функция current_catalog - имя БД, к которой выполнено подключение.
-
В первом терминале создайте таблицу stab с текстовым столбцом:
student@student=> CREATE TABLE stab(msg text); CREATE TABLE
student@student=> \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+---------
public | stab | table | student
(1 row)
student@student=> \d stab
Table "public.stab"
Column | Type | Collation | Nullable | Default
-------+------+-----------+----------+---------
msg | text | | |Метакоманда
\d
без аргументов выдает спис ок таблиц (и других отношений). Если метакоманде\d
задать имя существующей таблицы, она напечатает структуру этой таблицы. -
Начните транзакцию в первом терминале:
student@student=> BEGIN; BEGIN
student@student=*>Обратите внимание на изменение приглашения командной строки psql. Там появился символ звездочки, который и говорит о том, что в сеансе запущена транзакция.
-
Получите номер текущей транзакции в первом терминале:
student@student=*> SELECT pg_current_xact_id(); pg_current_xact_id
--------------------
885
(1 row)Функция
pg_current_xact_id()
возвращает номер XID транзакции, если он был назначен. Если он не был назначен - назначает. -
Вставьте в таблицу произвольную строку:
student@student=*> INSERT INTO stab VALUES ('Вставка'); INSERT 0 1
student@student=*> SELECT * FROM stab; msg
---------
Вставка
(1 row)Изменения данных, производимые командами DML в транзакции видны сразу.
-
Проверьте, видны ли изменения в таблице
stab
вне транзакции, обратившись к таблице с запросом на чтение во втором сеансе:[student@TERM2 ~]$ psql psql (15.5)
Type "help" for help.
student@student=> SELECT * FROM stab; msg
-----
(0 rows)Обратите внимание, что активная пишущая транзакция, в которой изменяются данные таблицы
stab
, не блокирует операции чтения. Однако, система MVCC предоставляет командам и транзакциям разные представления данных - снимки. Во втором сеансе снимок данных таблицы stab не содержит в себе строк. Это связано с тем, что транзакция в первом сеансе не зафиксирована. -
Зафиксируйте транзакцию и проверьте содержимое таблицы в обоих сеансах. В первом сеансе:
COMMIT
student@student=> SELECT * FROM stab; msg
---------
Вставка
(1 row)Во втором:
student@student=> SELECT * FROM stab; msg
---------
Вставка
(1 row)После фиксации транзакции внесенные ей изменения в данных видны всем командам и транзакциям.
Откат при ошибке в командах транзакции
-
Начните транзакцию, но сделайте в какой-либо команде транзакции ошибку. Попробуйте зафиксировать транзакцию:
student@student=> BEGIN; BEGIN
student@student=*> амбигоус_цомманд;
ERROR: syntax error at or near "амбигоус_цомманд" LINE 1: амбигоус_цомманд;
^
student@student=!> SELECT pg_current_xact_id();
ERROR: current transaction is aborted, commands ignored until end of transaction block
student@student=!> COMMIT; ROLLBACKВ режиме по умолчанию, если в какой-либо команде транзакции произошла ошибка, транзакция отменяется и при попытке ее фиксации происходит откат.
-
Получите текущее значение встроенной переменной psql
ON_ERROR_ROLLBACK
. Установите значение этой переменной в on:student@student=> \echo :ON_ERROR_ROLLBACK off
student@student=> \set ON_ERROR_ROLLBACK on
student@student=> \echo :ON_ERROR_ROLLBACK on -
Снова повторите действия и пункта 3.1. Проверьте отличия:
student@student=> BEGIN; BEGIN
student@student=*> амбигоус_цомманд;
ERROR: syntax error at or near "амбигоус_цомманд" LINE 1: амбигоус_цомманд;
^
student@student=*> SELECT pg_current_xact_id();
pg_current_xact_id
--------------------
886
(1 row)
student@student=*> COMMIT; COMMITУстановка
ON_ERROR_ROLLBACK
on неявно устанавливает перед каждой командой транзакции точку сохраненияSAVEPOINT
, и при возникновения ошибки не происходит откат всей транзакции, а отка т к предыдущей успешной команде транзакции. https://www.postgresql.org/docs/15/sql-savepoint.html. Однако, в этом есть существенный минус - значительно возрастает нагрузка на сервер из-за обилия точек отката. Поэтому такой настройкой не следует злоупотреблять. -
Сбросьте
ON_ERROR_ROLLBACK
:student@student=> \unset ON_ERROR_ROLLBACK
student@student=> \echo :ON_ERROR_ROLLBACK off