Руководство пользователя
Чтобы создать транзакцию в Mac версии программы, нажмите на кнопку «Новая транзакция…» в левом нижнем углу окна программы. Данная кнопка всегда доступна и имеет горячую клавишу ⌘ + N.
Существует несколько вариантов создания новой транзакции в iOS версии. Вы можете провести пальцем влево по счету в главном меню и выбрать «Новая транзакция». Вы также можете нажать на кнопку «+» при просмотре списка транзакций для этой же цели.
Для создания транзакции в watchOS, выберите счет и затем нажмите на кнопку «Расход» или на кнопку «Доход». Переводы нельзя создавать на Apple Watch.
Что необходимо знать
При создании транзакции вам будет предложено указать её сумму и ряд опциональных параметров, детально описанных здесь.
Некоторые параметры, такие как дата, заметки и файлы скрыты по умолчанию. Чтобы их изменить, нажмите на кнопку «Дополнительно» при изменении или создании транзакции.
Вы можете переключаться между расходом, доходом или переводом с помощью переключателя в верхней части формы новой транзакции. Типы транзакций описаны здесь.
Используйте калькулятор когда необходимо
Чтобы использовать калькулятор в Mac версии программы, начните писать уравнение в поле «Сумма» и поставьте знак ‘=’ на конце. Пример: «50*20/10 article_screenshot_image» width=»319″ height=»405″ poster=»images/ios-calculator-poster.png» autoplay=»autoplay» loop>
- © Ivan Pavlov Pty Ltd. All rights reserved.
- Design: HTML5 UP
# Как создать транзакцию и отправить ее на блокчейн
Все события на блокчейне представлены в виде транзакций. Например:
- транзакция данных записывает информацию в хранилище данных аккаунта;
- транзакция перевода отправляет заданное количество токенов с одного аккаунта на другой.
В Waves предусмотрено множество типов транзакций, см. раздел Тип транзакции. Набор полей транзакции зависит от ее типа.
Подтверждение транзакции
В Waves каждая транзакция отправлена с какого-либо аккаунта. Транзакция, отправленная с обычного аккаунта (без установленного скрипта), должна содержать подтверждение — цифровую подпись отправителя. (Смарт-аккаунты и dApp могут устанавливать собственные правила верификации исходящих транзакций.) Подробнее см. в разделе Подтверждение транзакциии.
Есть два способа сгенерировать подтверждение транзакции:
- Если приложение отправляет транзакции от вашего имени, вы можете использовать свою секретную фразу (seed) или закрытый ключ для подписания транзакций. Этот способ описан в подразделе Подписание с помощью секретной фразы ниже.
- Если приложение отправляет транзакции от имени разных пользователей, не следует запрашивать у них секретную фразу или закрытый ключ. Вместо этого используйте официальное приложение-кошелек — например, разработанное командой WX Network. Этот способ описан в подразделе Подписание от имени пользователя ниже.
Комиссия за транзакцию
Транзакции в Waves очень дешевые, но не бесплатные. В каждой транзакции должна быть указана комиссия не менее минимальной. Минимальные комиссии представлены в разделе Комиссия за транзакцию.
На Testnet пользователи могут пополнять баланс WAVES с помощью Testnet Faucet.
Процесс
Чтобы поместить транзакцию в блокчейн:
- Заполните поля транзакции.
- Подпишите транзакцию: сгенерируйте подтверждение и добавьте его к транзакции.
- Отправьте транзакцию на ноду Waves.
Вы можете отправить транзакцию на свою собственную ноду или одну из нод с публичным API:
Нода проверяет валидность транзакции. Если проверка прошла успешно, транзакция помещается в очередной сгенерированный блок, в противном случае транзакция отвергается блокчейном. (Транзакции вызова скрипта и транзакции обмена могут быть добавлены на блокчейн, даже если результат выполнения dApp-скрипта или скрипта ассета был неудачным, за такие транзакции взимается комиссия.)
# Подписание с помощью секретной фразы
# С помощью JavaScript
Используйте библиотеку waves-transactions . Для генерации подписи используется секретная фраза (seed) аккаунта. Если комиссия за транзакцию не указана, она рассчитывается автоматически.
Описание функций приведено в документации библиотеки
import broadcast > from "@waves/waves-transactions"; import data, transfer > from "@waves/waves-transactions"; const nodeUrl = 'https://nodes-testnet.wavesnodes.com'; const seed = 'insert your seed here'; // Транзакция данных: добавляет записи в хранилище данных аккаунта-отправителя const records = [ key: 'integerVal', value: 1 >, key: 'booleanVal', value: true >, key: 'stringVal', value: 'Lorem ipsum dolor sit amet' > ] const dataTx = data( data: records >, seed); // Создание и подписание транзакции данных broadcast(dataTx,nodeUrl).then(resp => console.log(resp)); // Транзакция перевода: отправляет 1 WAVES на заданный адрес const money = recipient: '3N1HYdheNiiTtHgi2n3jLAek6N3H4guaciG', amount: 100000000 // Фактическое количество ассета нужно умножить на 10^decimals > const transferTx = transfer(money, seed); // Создание и подписание транзакции перевода broadcast(transferTx,nodeUrl).then(resp => console.log(resp));
# С помощью Python
, разработанную сообществом Waves. Класс Address предназначен для операций в блокчейне. Подробнее см. в документации библиотеки
import pywaves as pw myAddress = pw.Address(seed='insert your seed here') data = ['type':'string', 'key': 'stringVal', 'value':'Lorem ipsum dolor sit amet'>, 'type':'integer', key: 'integerVal', value: 1 >, 'type':'boolean', key: 'booleanVal', value: true >] myAddress.dataTransaction(data) myAddress.sendWaves(recipient = pw.Address('3P8pGyzZL9AUuFs9YRYPDV3vm73T48ptZxs'), amount = 100000000)
# Подписание от имени пользователя
# С помощью JavaScript
Используйте библиотеку Signer вместе с библиотеками ProviderWeb и ProviderCloud , разработанными командой WX Network. Провайдер открывает окно, в котором пользователь может подтвердить транзакцию. Затем провайдер генерирует подтверждение транзакции.
Если комиссия за транзакцию не указана, она рассчитывается автоматически.
Полное описание приведено в документации Signer.
Пример:
import Signer > from '@waves/signer'; import ProviderWeb > from '@waves.exchange/provider-web'; // Инициализация библиотеки const signer = new Signer( NODE_URL: 'https://nodes-testnet.wavesnodes.com' >); signer.setProvider(new ProviderWeb()); // Транзакция данных: добавляет записи в хранилище данных аккаунта-отправителя const records = [ key: 'integerVal', value: 1 >, key: 'booleanVal', value: true >, key: 'stringVal', value: 'Lorem ipsum dolor sit amet' > ] const dataTx = signer .data( data: records >) .broadcast(); dataTx.then(resp => console.log(resp)); console.log('Data tx: ' + dataTx); // Транзакция перевода: отправляет 1 WAVES на заданный адрес const money = recipient: '3N1HYdheNiiTtHgi2n3jLAek6N3H4guaciG', amount: 100000000, > const transferTx = signer .transfer(money) .broadcast(); transferTx.then(resp => console.log(resp));
Создаём, подписываем и отправляем Ethereum транзакцию при помощи web3.js и Ganache

В предыдущей статье я рассказал как установить окружение для ознакомления с библиотекой web3.js. Тогда мы использовали ethereum-блокчейн Ganache и библиотеку Truffle. В данной статье я покажу как формировать ethereum-транзакцию используя только библиотеку web3.js и Ganache, без использования библиотеки Truffle.
Мы подключимся к локальному блокчейну Ganache, я покажу как создать новый аккаунт в дополнение к стандартным 10-ти аккаунтам. Далее мы сформируем транзакцию вручную, выполним её подписание и отправим в сеть. Посмотрим на тело сериализованной и подписанной транзакции в том виде, в котором она передаётся в ethereum-блокчейн (raw transaction). Так как команд будет много, то все эти шаги мы выполним в форме js-скрипта.
Напомню, что Truffle это фреймворк, который внутри себя содержит библиотеку web3.js, но помимо web3.js Truffle предлагает множество других инструментов для тестирования, деплоя и отладки смарт-контрактов. Truffle пригодится нам в следующих статьях, когда речь пойдёт о написании смарт-контрактов, и отправки сообщений в их адрес, а пока спустимся на этаж ниже и посмотрим более детально на процесс формирования транзакции.
Что нам понадобится?
Итак, приступим!
Для начала запустим наш локальный блокчейн Ganache:

Далее, создадим рабочую директорию и установим в ней библиотеку web3:
$ mkdir web3-transaction $ cd web3-transaction $ npm install web3
Запустим консоль node.js командой:
$ node
В консоли настроим подключение к Ganache:
> const Web3 = require('web3'); > const web3 = new Web3('http://127.0.0.1:7545'); > Web3
Если вы увидели вывод, представленный ниже, значит вы успешно подключились:

Проверим соединение ещё раз, запросив Ganache показать нам предустановленные аккаунты:
> web3.eth.getAccounts().then(console.log);
[ '0xbc1415C5059aC055aE44Bd02ff1ad59AbEA8123f', '0x76770DdEb60e538C7A4fE43583772c4cfED09Aab', '0×3888942905f12974Fb0306D5E578da79811b0aE0', // other accounts . ]
Поскольку getAccounts() возвращает объект Promise , то необходимо дописать .then(console.log) . Тот же самый вывод можно получить используя await перед вызовом:
> await web3.eth.getAccounts();
Создание нового аккаунта в Ganache
Теперь я хочу продемонстрировать, как к существующим 10-ти аккаунтам мы можем создавать новые аккаунты, и эти аккаунты ничем не будут отличаться от предустановленных аккаунтов, ну почти ничем, ниже я расскажу про их небольшое различие.
Создадим новый аккаунт:
> web3.eth.accounts.create();
В консоли мы видим данные по новому аккаунту, в частности адрес и связанный с ним приватный ключ.
А вот теперь про небольшое отличие между аккаунтами созданными вручную, и теми, которые были сгенерированы при старте Ganache. Если вы откроете Ganache, то вы не увидите вновь созданный аккаунт. Почему так происходит? На самом деле Ganache при запуске создаёт аккаунты в отдельном объекте, назовём его массив. При отображении аккаунтов в GUI он использует этот массив, точно так же как и метод web3.eth.getAccounts() . Созданный нами аккаунт хоть и отсутствует в этом массиве, но существует в том же самом блокчейне. Поэтому с технической точки зрения они идентичны. Чтобы в этом убедиться, давайте отправим несколько Ether c предустановленного аккаунта на наш новый аккаунт.
Перед отправкой Ether, проверим баланс нашего нового аккаунта:
> await web3.eth.getBalance('0x4bec925613AF22cC98886f6EbCb68BcB0B5f02F1'); // Out: '0'
Видим, что вновь созданный аккаунт не имеет средств на балансе.
Теперь отправим на этот аккаунт 70 Ether с аккаунта, который Ganache создал при старте, а заодно убедимся, что все аккаунты существуют в рамках одного блокчейна:
> await web3.eth.sendTransaction();
Проверим новый аккаунт:
> await web3.eth.getBalance('0x4bec925613AF22cC98886f6EbCb68BcB0B5f02F1'); // '70000000000000000000'
Вывод показан в Wei. Если мы хотим получить вывод в Ether, то можем применить следующий вызов:
> await web3.eth.getBalance('0x4bec925613AF22cC98886f6EbCb68BcB0B5f02F1', (call, wei) => < balance = web3.utils.fromWei(wei, 'ether') >); // Out: '70000000000000000000' > balance // Out: '70'
Здесь мы передали методу getBalance() вторым аргументом функцию, которая сконвертировала полученный результат в Ether и сохранила его в переменной balance .
Отлично, теперь откроем Ganache GUI и убедимся, что с аккаунта-отправителя списались средства.

Теперь у нас достаточно средств на новом аккаунте, и мы убедились что не имеет значения каким образом был создан аккаунт, вручную или же при старте Ganache.
Формируем транзакцию по шагам
Теперь я покажу как отдельно сформировать транзакцию, отдельно её подписать и отдельно отправить подписанную транзакцию в сеть Ethereum.
Для отправки подписанной транзакции мы будем использовать метод sendSignedTransaction() . Это метод берёт подписанную сериализованную транзакцию, и отправляет в сеть Ethereum как есть.
Но перед этим я хотел бы рассказать, что же происходило под капотом предыдущего метода отправки.
Ранее для отправки транзакции мы использовали метод sendTransaction() библиотеки web3. Данный метод под капотом совершает множество операций за нас. Вот лишь некоторые из них:
- Находит приватный ключ отправителя
- Генерирует поле nonce
- Определяет значения полей gasPrice и gas
- Создаёт объект транзакции
- Подписывает эту транзакцию
- Сериализует транзакцию используя RLP кодирование
- Отправляет подписанную и сериализованную транзакцию в сеть Ethereum
Может возникнуть вопрос — для чего нам нужно отдельно вручную выполнять эти шаги, если уже есть готовый метод, который за нас всё сделает? Дело в том, что иногда при написании Dapp приложений, нам действительно нужен ручной контроль над этапами формирования транзакции.
Вот лишь один из примеров. Представьте, что вы имеете аккаунт с очень большим количеством криптовалюты на нём, и вам бы не очень хотелось каким-то образом скомпрометировать приватный ключ от этого аккаунта. Самый верный способ обеспечить безопасность приватного ключа — это хранить его на offline устройстве, там же осуществлять формирование и подписание транзакции. В роли такого устройства может выступать полностью изолированный от сети компьютер. После формирования, подписания, и сериализации транзакции на offline устройстве, необходимо перенести её на online компьютер. Компьютер, подключённый к сети будет выступать в роли гейта к блокчейн-сети, и отправит транзакцию в сеть как есть. В таком случае никто не будет иметь онлайн-доступа к нашему приватному ключу.
Перенести транзакцию можно как при помощи флеш-накопителя, так и при помощи QR-кода, который считывается устройством-отправителем. Кстати, такой вид оффлайн-устройства называется ещё холодный кошелёк, или cold-wallet, а кошелёк, который хранит приватные ключи на онлайн-устройстве называют горячий кошелёк, или hot-wallet. В качестве cold-wallet на рынке присутствуют готовые решения в виде usb-устройств. Примером hot-wallet может служить расширение к браузеру MetaMask. Как правило, на hot-wallet рекомендуют хранить приватные ключи от тех аккаунтов, на которых хранятся незначительные средства. Hot-wallet крайне не рекомендуется использовать для хранения приватных ключей от аккаунтов с крупными суммами на балансе. Можно провести аналогию с банковской картой, на которой хранят небольшую сумму денег для повседневных платежей, а основная сумма лежит на счетах не привязанных к банковской карте.
В приведённом списке параметров существует ещё загадочное поле nonce , чтобы вас не утруждать техническими подробностями, и быстрее перейти к практике, скажу лишь что это целочисленный счётчик транзакций, который есть в каждом аккаунте и прописывается в каждую транзакцию. В конце статьи я к нему ещё вернусь, и опишу его назначение, а пока примем этот параметр как данность.
Про назначение полей gas и gasPrice я писал в предыдущей статье. Напомню лишь, что это плата за пользование вычислительными ресурсами сети Ethereum.
Итак, практика
В качестве участников транзакции я советую выбрать первый и второй аккаунты из Ganache, чтобы было удобнее смотреть изменения на балансах после многократного выполнения скрипта. Но для интереса вы можете потом поэкспериментировать и с тем аккаунтом, который мы создали ранее. Для того чтобы взять приватный ключ, кликаем на значок ключа в строке аккаунта-отправителя.
Поскольку команд будет много, то удобнее создать js-скрипт. Создадим внутри нашей папки web3-transfer файл transfer.js и поместим туда скрипт (имя файла не имеет значения, вы можете назвать как вам больше нравится).
Наш скрипт transfer.js :
const Web3 = require("web3"); const web3 = new Web3("http://127.0.0.1:7545"); // replace this data with data from your blockchain const senderAddress = "0xbc1415C5059aC055aE44Bd02ff1ad59AbEA8123f"; const senderPrivateKey = "0xa81eab077a97ed7e3bc312894292839ed96ee051c6b11fa9c29600792c11c6bb"; const recepientAddress = "0x76770DdEb60e538C7A4fE43583772c4cfED09Aab"; console.log("Sending 1 ether from address:", senderAddress, "to address:", recepientAddress); async function transfer() < // nonce starts at 0 and increments by 1 after each transaction const nonce = await web3.eth.getTransactionCount(senderAddress, "latest"); const transaction = < to: recepientAddress, value: web3.utils.toWei("1", "ether"), gas: 30000, nonce: nonce, >; const signedTransaction = await web3.eth.accounts.signTransaction( transaction, senderPrivateKey ); const rawTransaction = signedTransaction.rawTransaction; console.log("Nonce for address", senderAddress, "is:", nonce); console.log("Raw transaction:", rawTransaction); web3.eth.sendSignedTransaction(rawTransaction, function (error, hash) < if (!error) < console.log("The hash of your transaction is: ", hash, "\n Check Transactions tab in Ganache to view your transaction!"); >else < console.log("Something went wrong while submitting your transaction:", error); >>); > transfer();
В скрипте я добавил логи, чтобы можно было отслеживать изменение поля nonce и видеть транзакцию в чистом виде.
Выйдем из консоли node (Ctrl + D) и запустим транзакцию в терминале:
$ node transfer.js
Sending 1 ether from address: 0xbc1415C5059aC055aE44Bd02ff1ad59AbEA8123f to address: 0x76770DdEb60e538C7A4fE43583772c4cfED09Aab Nonce for address 0xbc1415C5059aC055aE44Bd02ff1ad59AbEA8123f is: 1 Raw transaction: 0xf86e018504a817c8008275309476770ddeb60e538c7a4fe43583772c4cfed09aab880de0b6b3a764000080820a95a02bd617982bbf2cca3f332f1cc6c93fd5a1e10e3586f49d3bd936d5e5509c128ca0759cf486fb9289280ecd2a8d18f7686d1604474ecd263c54aedfc4d646db0d85 The hash of your transaction is: 0x7c5257dc29eab0d579931674927004089b6141a6d0127d3d30be43ae24041d97 Check Transactions tab in Ganache to view your transaction!
Видим, что nonce у адреса-отправителя равен 1, так как до этого мы уже производили с него транзакцию в пользу вновь созданного аккаунта. Так же видим транзакцию в том виде, в котором она понятна протоколу Ethereum:
0xf86e018504a817c8008275309476770ddeb60e538c7a4fe43583772c4cfed09aab880de0b6b3a764000080820a95a02bd617982bbf2cca3f332f1cc6c93fd5a1e10e3586f49d3bd936d5e5509c128ca0759cf486fb9289280ecd2a8d18f7686d1604474ecd263c54aedfc4d646db0d85
Зайдём в Ganache и посмотрим на изменения:

Отлично, балансы изменились, транзакция прошла успешно. Можете несколько раз позапускать этот скрипт и увидеть, как изменяется nonce и баланс.
В выводе скрипта мы видим так же хэш нашей транзакции:
0x7c5257dc29eab0d579931674927004089b6141a6d0127d3d30be43ae24041d97
По этому хэшу находят транзакцию в блокчейне. Если мы откроем вкладку Transactions в GUI Ganache, то увидим все наши транзакции (я запустил скрипт несколько раз):

Аналогично во вкладке Blocks мы можем обнаружить блоки в котором находятся наши транзакции. По одной транзакции на блок. В реальном мире в одном блоке содержатся сотни транзакций, а сами блоки формируются нодами-майнерами, за что получают финансовое вознаграждение, так как выступают в роли формирователей сети blockchain.

Ну и в заключение, несколько слов про поле Nonce
Nonce, он же «number only used once», предназначен для защиты от двух видов атак: replay-attack и double-spending attack. Про механизм этих атак можно почитать здесь, а если вкратце, то во-первых, без поля nonce в сети Ethereum мы могли бы многократно повторить транзакцию, которая уже была осуществлена, причём выполнить её без ведома самого отправителя (replay-attack), а во-вторых сеть Ethereum не обладала бы информацией об очередности обработки транзакций с одного и того же аккаунта (double-spending attack).
Как же работает nonce? Nonce это дополнительное целочисленное поле внутри каждого аккаунта, которое проставляется в отправляемую транзакцию. Иными словами, это счётчик отправленных транзакций с конкретного аккаунта. С каждой новой транзакцией с одного и того же аккаунта, данный параметр увеличивается на один. Допустим мы создали новый аккаунт, поле nonce у него будет равняться нулю, отправили транзакцию, поле nonce у этой транзакции тоже будет равняться нулю. После отправки транзакции, аккаунт увеличит это поле на 1, таким образом в следующей транзакции это поле будет равняться 1, и так далее. И если мы захотим отправить точно такую же транзакцию на такой же адрес и с тем же количеством Ether, то nonce изменит хэш этой транзакции, а следовательно и её подпись. Забегу немного вперёд — у аккаунта на котором задеплоен смарт контракт, поле nonce инициализируется не нулём, а единицей (EIP-161).
Таким образом, с полем nonce хэш SHA-3 (а точнее Keccak-256) любой транзакции всегда будет разный, следовательно подпись никогда не будет повторяться, каждая транзакция будет уникальной, а сеть Ethereum может учитывать порядок обработки транзакций.
На этом всё. Мы научились новым методам библиотеки web3.js, в частности: создание новых аккаунтов, подписание транзакции и отправки её в сеть. Посмотрели из чего состоит транзакция и увидели её сырое представление. Надеюсь информация была полезной 🙂
- JavaScript
- Программирование
- Node.JS
- Криптовалюты
Как создать транзакцию
Транзакции — это фундаментальное понятие во всех СУБД. Суть транзакции в том, что она объединяет последовательность действий в одну операцию «всё или ничего». Промежуточные состояния внутри последовательности не видны другим транзакциям, и если что-то помешает успешно завершить транзакцию, ни один из результатов этих действий не сохранится в базе данных.
Например, рассмотрим базу данных банка, в которой содержится информация о счетах клиентов, а также общие суммы по отделениям банка. Предположим, что мы хотим перевести 100 долларов со счёта Алисы на счёт Боба. Простоты ради, соответствующие SQL-команды можно записать так:
UPDATE accounts SET balance = balance - 100.00 WHERE name = 'Alice'; UPDATE branches SET balance = balance - 100.00 WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice'); UPDATE accounts SET balance = balance + 100.00 WHERE name = 'Bob'; UPDATE branches SET balance = balance + 100.00 WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');
Точное содержание команд здесь не важно, важно лишь то, что для выполнения этой довольно простой операции потребовалось несколько отдельных действий. При этом с точки зрения банка необходимо, чтобы все эти действия выполнились вместе, либо не выполнились совсем. Если Боб получит 100 долларов, но они не будут списаны со счёта Алисы, объяснить это сбоем системы определённо не удастся. И наоборот, Алиса вряд ли будет довольна, если она переведёт деньги, а до Боба они не дойдут. Нам нужна гарантия, что если что-то помешает выполнить операцию до конца, ни одно из действий не оставит следа в базе данных. И мы получаем эту гарантию, объединяя действия в одну транзакцию. Говорят, что транзакция атомарна: с точки зрения других транзакций она либо выполняется и фиксируется полностью, либо не фиксируется совсем.
Нам также нужна гарантия, что после завершения и подтверждения транзакции системой баз данных, её результаты в самом деле сохраняются и не будут потеряны, даже если вскоре произойдёт авария. Например, если мы списали сумму и выдали её Бобу, мы должны исключить возможность того, что сумма на его счёте восстановится, как только он выйдет за двери банка. Транзакционная база данных гарантирует, что все изменения записываются в постоянное хранилище (например, на диск) до того, как транзакция будет считаться завершённой.
Другая важная характеристика транзакционных баз данных тесно связана с атомарностью изменений: когда одновременно выполняется множество транзакций, каждая из них не видит незавершённые изменения, произведённые другими. Например, если одна транзакция подсчитывает баланс по отделениям, будет неправильно, если она посчитает расход в отделении Алисы, но не учтёт приход в отделении Боба, или наоборот. Поэтому свойство транзакций «всё или ничего» должно определять не только, как изменения сохраняются в базе данных, но и как они видны в процессе работы. Изменения, производимые открытой транзакцией, невидимы для других транзакций, пока она не будет завершена, а затем они становятся видны все сразу.
В PostgreSQL транзакция определяется набором SQL-команд, окружённым командами BEGIN и COMMIT . Таким образом, наша банковская транзакция должна была бы выглядеть так:
BEGIN; UPDATE accounts SET balance = balance - 100.00 WHERE name = 'Alice'; -- . COMMIT;
Если в процессе выполнения транзакции мы решим, что не хотим фиксировать её изменения (например, потому что оказалось, что баланс Алисы стал отрицательным), мы можем выполнить команду ROLLBACK вместо COMMIT , и все наши изменения будут отменены.
PostgreSQL на самом деле отрабатывает каждый SQL-оператор как транзакцию. Если вы не вставите команду BEGIN , то каждый отдельный оператор будет неявно окружён командами BEGIN и COMMIT (в случае успешного завершения). Группу операторов, окружённых командами BEGIN и COMMIT иногда называют блоком транзакции.
Примечание
Некоторые клиентские библиотеки добавляют команды BEGIN и COMMIT автоматически и неявно создают за вас блоки транзакций. Подробнее об этом вы можете узнать в документации интересующего вас интерфейса.
Операторами в транзакции можно также управлять на более детальном уровне, используя точки сохранения. Точки сохранения позволяют выборочно отменять некоторые части транзакции и фиксировать все остальные. Определив точку сохранения с помощью SAVEPOINT , при необходимости вы можете вернуться к ней с помощью команды ROLLBACK TO . Все изменения в базе данных, произошедшие после точки сохранения и до момента отката, отменяются, но изменения, произведённые ранее, сохраняются.
Когда вы возвращаетесь к точке сохранения, она продолжает существовать, так что вы можете откатываться к ней несколько раз. С другой стороны, если вы уверены, что вам не придётся откатываться к определённой точке сохранения, её можно удалить, чтобы система высвободила ресурсы. Помните, что при удалении или откате к точке сохранения все точки сохранения, определённые после неё, автоматически уничтожаются.
Всё это происходит в блоке транзакции, так что в других сеансах работы с базой данных этого не видно. Совершённые действия становятся видны для других сеансов все сразу, только когда вы фиксируете транзакцию, а отменённые действия не видны вообще никогда.
Вернувшись к банковской базе данных, предположим, что мы списываем 100 долларов со счёта Алисы, добавляем их на счёт Боба, и вдруг оказывается, что деньги нужно было перевести Уолли. В данном случае мы можем применить точки сохранения:
BEGIN; UPDATE accounts SET balance = balance - 100.00 WHERE name = 'Alice'; SAVEPOINT my_savepoint; UPDATE accounts SET balance = balance + 100.00 WHERE name = 'Bob'; -- ошибочное действие. забыть его и использовать счёт Уолли ROLLBACK TO my_savepoint; UPDATE accounts SET balance = balance + 100.00 WHERE name = 'Wally'; COMMIT;
Этот пример, конечно, несколько надуман, но он показывает, как можно управлять выполнением команд в блоке транзакций, используя точки сохранения. Более того, ROLLBACK TO — это единственный способ вернуть контроль над блоком транзакций, оказавшимся в прерванном состоянии из-за ошибки системы, не считая возможности полностью отменить её и начать снова.
| Пред. | Наверх | След. |
| 3.3. Внешние ключи | Начало | 3.5. Оконные функции |