Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,10 @@

Например, `КоннекторJSON` не умеет работать с транзакциями, однако, он имеет соответствующие методы, выводящие диагностические сообщения при их вызове.

Коннектор с транзакциями **обязан** сам знать, открыта ли транзакция, и отвечать на это методом `ВТранзакции()`: транзакцию может начать текстом запроса и бросить алгоритм `ВыполнитьСКоннектором`, и пул откатывает ее по этому ответу, прежде чем соединение достанется другому потоку. Коннектор без транзакций отвечает `Ложь`.

Сохранение сущности с подчиненными таблицами - несколько запросов, и библиотека выполняет их методом коннектора `ВыполнитьМонопольно(Действие)`: коннектор **обязан** выполнить действие так, чтобы другие потоки не видели его промежуточных состояний, - в транзакции или под своей блокировкой. Коннектор, не умеющий изолировать, просто выполняет действие.

Коннектор **может** дополнительно реализовать интерфейс [`НаблюдаемыйКоннектор`](docs/НаблюдаемыйКоннектор.md): тогда наблюдатели источника данных получают события его запросов к СУБД и описание соединения. Встроенные коннекторы реализуют оба интерфейса. Коннектор без второго интерфейса работает как раньше.

> Важно!
Expand Down
36 changes: 36 additions & 0 deletions docs/АбстрактныйКоннектор.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,42 @@
Процедура ОтменитьТранзакцию() Экспорт
```

### ВТранзакции

Коннектор с транзакциями ведет признак сам: транзакцию может начать и бросить алгоритм
`ВыполнитьСКоннектором` мимо библиотеки, и узнать о ней пул может только у коннектора. Коннектор
без транзакций отвечает `Ложь`.

```bsl
// Определяет, начата ли этим коннектором транзакция, которая еще не завершена: методом
// коннектора или текстом запроса прямого доступа.
//
// По ответу пул откатывает транзакцию, брошенную алгоритмом ВыполнитьСКоннектором, прежде чем
// соединение достанется другому потоку исполнения. Коннектор без транзакций отвечает Ложь.
//
// Возвращаемое значение:
// Булево - Истина, если транзакция начата и не завершена.
//
Функция ВТранзакции() Экспорт
```

### ВыполнитьМонопольно

Библиотека поручает коннектору операции из нескольких запросов - сохранение сущности с
подчиненными таблицами: другие потоки не должны видеть их промежуточных состояний. Встроенные
коннекторы SQL выполняют действие в своей транзакции (внутри уже начатой - просто выполняют),
InMemory и JSON - под блокировкой записи базы или каталога, без отката. Коннектор, не умеющий
изолировать, просто выполняет действие.

```bsl
// Выполняет действие так, чтобы другие потоки исполнения не видели его промежуточных состояний.
//
// Параметры:
// Действие - Действие - Действие без параметров.
//
Процедура ВыполнитьМонопольно(Действие) Экспорт
```

### ИнициализироватьТаблицу

```bsl
Expand Down
31 changes: 28 additions & 3 deletions docs/КоннекторJSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,31 @@
Процедура ОтменитьТранзакцию() Экспорт
```

### ВТранзакции

```bsl
// Определяет, начата ли транзакция. Транзакций коннектор не поддерживает.
//
// Возвращаемое значение:
// Булево - Всегда Ложь.
//
Функция ВТранзакции() Экспорт
```

### ВыполнитьМонопольно

```bsl
// Выполняет действие монопольно: под блокировкой записи каталога базы. Другие потоки процесса
// не читают и не пишут таблицы этого каталога, пока действие не закончится.
//
// Отката нет: если действие упало посередине, записанное до сбоя остается в файлах.
//
// Параметры:
// Действие - Действие - Действие без параметров.
//
Процедура ВыполнитьМонопольно(Действие) Экспорт
```

### ИнициализироватьТаблицу

```bsl
Expand Down Expand Up @@ -104,9 +129,9 @@
```bsl
// Осуществляет поиск строк в таблице по указанному отбору.
//
// Файл таблицы читается под блокировкой чтения: параллельные чтения одной таблицы не мешают
// друг другу, но не пересекаются с записью, поэтому одновременные чтение и запись из разных
// потоков одного процесса не конфликтуют за файл.
// Файл таблицы читается под блокировкой чтения каталога: параллельные чтения не мешают друг
// другу, но не пересекаются с записью, поэтому одновременные чтение и запись из разных потоков
// одного процесса не конфликтуют за файл, а монопольное действие не видно наполовину.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
Expand Down
34 changes: 34 additions & 0 deletions docs/КоннекторSQLite.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
```bsl
// Начинает новую транзакцию в БД.
//
// Транзакция отложенная: блокировку записи она берет на первой записи, поэтому параллельные
// читающие транзакции друг другу не мешают. Две транзакции, обе успевшие прочитать и затем
// пишущие, ждут друг друга до ошибки "database is locked" - такую работу следует выполнять
// монопольно, см. ВыполнитьМонопольно.
//
Процедура НачатьТранзакцию() Экспорт
```

Expand All @@ -64,6 +69,35 @@
Процедура ОтменитьТранзакцию() Экспорт
```

### ВТранзакции

```bsl
// Определяет, начата ли этим коннектором транзакция, которая еще не завершена: методом
// коннектора или текстом запроса.
//
// Возвращаемое значение:
// Булево - Истина, если транзакция начата и не завершена.
//
Функция ВТранзакции() Экспорт
```

### ВыполнитьМонопольно

```bsl
// Выполняет действие в транзакции: в своей, если транзакция еще не начата, иначе - в уже
// начатой.
//
// Своя транзакция сразу берет блокировку записи (BEGIN IMMEDIATE): действие, читающее перед
// записью, в отложенной транзакции ждало бы такое же параллельное действие до ошибки
// "database is locked". Немедленная ждет предшественницу на начале - не дольше срока ожидания
// соединения, параметр строки соединения "Default Timeout", по умолчанию 30 секунд.
//
// Параметры:
// Действие - Действие - Действие без параметров.
//
Процедура ВыполнитьМонопольно(Действие) Экспорт
```

### ИнициализироватьТаблицу

```bsl
Expand Down
53 changes: 53 additions & 0 deletions docs/ПотокобезопаснаяРаботаСБД.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,33 @@ PostgreSQL это закрывает параметр строки соедин
КонецПопытки;
```

### Сохранение с подчиненными таблицами

Сущность с подчиненными таблицами сохраняется несколькими запросами: строка сущности, удаление
прежних строк коллекций, вставка новых. Библиотека выполняет их монопольно, методом коннектора
`ВыполнитьМонопольно`, поэтому параллельные сохранения одной сущности не смешивают строки коллекций,
а чтение не видит коллекцию наполовину:

- SQLite и PostgreSQL сохраняют в своей транзакции, если контекст транзакцию не начинал, иначе - в
его транзакции. Наблюдатели видят запросы `BEGIN` и `COMMIT`, событий транзакции нет. Своя
транзакция SQLite сразу берет блокировку записи (`BEGIN IMMEDIATE`) и ждет занятую базу не
дольше `Default Timeout` строки соединения, по умолчанию 30 секунд.
- InMemory сохраняет под блокировкой записи базы, JSON - под блокировкой записи каталога: чтения и
записи других потоков этой базы ждут. Отката нет: сохранение, упавшее посередине, оставит
записанное до сбоя.
- Наблюдатели запросов такого сохранения вызываются, пока коннектор держит транзакцию или
блокировку: работа наблюдателя с той же базой из другого потока будет ждать конца сохранения.

Блокировка JSON одна на каталог: записи разных таблиц одного каталога идут по одной, чтения -
параллельно.

Потерянное обновление это не лечит: из двух сохранений одной сущности остается последнее.

Транзакции SQLite, начатые `НачатьТранзакцию`, отложенные: блокировку записи они берут на первой
записи, поэтому параллельные читающие транзакции друг другу не мешают. Но две транзакции, обе
успевшие прочитать и затем пишущие, ждут друг друга до ошибки `database is locked`. Такую работу
выполняйте монопольно - методом коннектора `ВыполнитьМонопольно` в `ВыполнитьСКоннектором`.

### Прямой доступ к БД

Коннектор наружу не выдается: соединение принадлежит пулу, и вернуть его должен тот, кто взял.
Expand All @@ -158,6 +185,32 @@ PostgreSQL это закрывает параметр строки соедин
Если текущий контекст исполнения начал транзакцию, алгоритм получает коннектор этой транзакции и
попадает в нее.

Транзакцию для алгоритма открывайте менеджером: `МенеджерСущностей.НачатьТранзакцию()` до
`ВыполнитьСКоннектором`, фиксация или отмена - после. Транзакция, которую алгоритм начал сам -
методом коннектора или запросом `BEGIN`, - и не завершил, откатывается при возврате соединения в
пул: иначе она ушла бы с соединением к другому контексту, и его фиксация записала бы строки
алгоритма. Наблюдатели увидят запрос `ROLLBACK`, события транзакции у нее нет: начинала ее не
библиотека.

```bsl
// Удаление не применится: транзакция брошена алгоритмом и откатывается при возврате соединения
МенеджерСущностей.ВыполнитьСКоннектором(
"Коннектор -> Коннектор.ВыполнитьЗапрос(""BEGIN""); Коннектор.ВыполнитьЗапрос(Текст)",
Новый Структура("Текст", "DELETE FROM Авторы")
);
```

О транзакции коннектор узнает по первому оператору каждого выполненного запроса: `BEGIN` и
`START TRANSACTION` ее начинают, `COMMIT`, `END` и `ROLLBACK` завершают, откат к точке сохранения
(`ROLLBACK TO`) не завершает. Не видны ему транзакции, начатые или завершенные вторым оператором
многооператорного текста, процедурой на стороне СУБД, а в SQLite - еще и `SAVEPOINT` вне транзакции
и `RELEASE` последней точки сохранения. О транзакции пулу сообщает сам коннектор методом
`ВТранзакции()` интерфейса `АбстрактныйКоннектор`: сторонний коннектор с транзакциями должен вести
этот признак сам.

Коннектор не храните вне алгоритма: после выхода из него соединение принадлежит пулу и может
работать в другом контексте.

Прежний `ПолучитьКоннектор()` удален: он отдавал соединение наружу, не имея способа получить его
обратно, поэтому соединение оставалось за контекстом навсегда.

Expand Down
Loading
Loading