From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00,FORGED_GMAIL_RCVD, FREEMAIL_FROM autolearn=no autolearn_force=no version=3.4.4 Path: buffer1.nntp.dca1.giganews.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!usenet.blueworldhosting.com!feeder01.blueworldhosting.com!feeder.erje.net!1.eu.feeder.erje.net!newsfeed.fsmpi.rwth-aachen.de!newsfeed.straub-nv.de!eternal-september.org!feeder.eternal-september.org!mx02.eternal-september.org!.POSTED!not-for-mail From: =?UTF-8?B?QmrDtnJuIEx1bmRpbg==?= Newsgroups: comp.lang.ada Subject: Re: Handling transactions? Date: Mon, 27 Jul 2015 16:16:25 +0200 Organization: A noiseless patient Spider Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Date: Mon, 27 Jul 2015 14:13:08 +0000 (UTC) Injection-Info: mx02.eternal-september.org; posting-host="6a09ccc49493ecf301ef65af9aa456c7"; logging-data="11586"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/NxVJkz2zIJnDnFwgq5ium" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Icedove/31.7.0 In-Reply-To: Cancel-Lock: sha1:RKwLyaLtprvhA9k0YU7sAFY66Fs= Xref: number.nntp.giganews.com comp.lang.ada:194337 Date: 2015-07-27T16:16:25+02:00 List-Id: On 2015-07-27 14:21, EGarrulo wrote: > What is the Ada idiom to handle transactions in procedures? I mean, let's suppose we perform the following steps in a procedure: > > Obj_1.A (); > Obj_2.B (); > Obj_3.C (); > Obj_4.D (); > > If we don't reach the last line because of an exception, we must undo the effects of any previous actions. My guess is that you would use a controlled type to embody a transaction, like this pseudo-code: > > Transaction.Start (); > Obj_1.A (); > Transaction.Add_Rollback (Rollback_Obj_1_A); > Obj_2.B (); > Transaction.Add_Rollback (Rollback_Obj_2_A); > Obj_3.C (); > Transaction.Add_Rollback (Rollback_Obj_3_A); > Obj_4.D (); > Transaction.Commit (); -- Don't run any registered rollback. > > Is this the way it is done, or is it any different? Thank you. > You do not mention what kind of transactions you mean. At work, where we do transactions towards databases in a multi-process environment, we do like this: loop begin Transaction.Start (); Obj_1.Read; Obj_2.Read; Obj_3.Read; Obj_4.Read; Obj_1.A (); Obj_2.B (); Obj_3.C (); Obj_4.D (); Transaction.Commit (); exit; exception when Transaction_Conflict => Transaction.Rollback; end; end loop; The idea is that you want to read values within the transaction, so you can re-read new values, if another process committed rows that affect the objects. You then want to roll EVERYTHING back, and start over, perhaps with another result-set. The reads may give different results, depending on what the external source did to cause the transaction_conflict. Now, exactly what raises Transaction_Conflict is up to you. We run db in read_committed mode, and each table has two columns, latest updater and latest updated timestamp. Each sql that modifies a row also HAVE to change these columns with its process-name and timestamp. This we ensure with auto-generated code We include the fields in the where-clause of the statement update T set A=1,B=2 where some-logical-condition and Last_Updater=:Last_Updater and Lastest_Updated=:Latest_Updated These two fields gets their value when reading the rows - Obj_1.Read; Then the update really does Sql.Execute(Statement, Rows_Affected); if Rows_Affected = 0 then raise Transaction_Conflict; end if; The two fields may be replaced with a row-version field of course. Some put triggers on each table to auto-increment this row-version, so user-code does not need to care. But the idea is the same: loop BEGIN read update if no row affected, raise exception COMMIT exit loop catch exception ROLLBACK end loop This way, the row is only locked when actual writing to it is done -- Björn