/* * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: MIT-0 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package software.amazon.qldb.doubleentry.tasks; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import software.amazon.qldb.doubleentry.actions.Banking; import software.amazon.qldb.doubleentry.dagger.components.BankingComponent; import software.amazon.qldb.doubleentry.dagger.components.DaggerBankingComponent; import software.amazon.qldb.doubleentry.models.Balance; import software.amazon.qldb.doubleentry.models.TransferRequest; import software.amazon.qldb.doubleentry.models.TransferResponse; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** *
* This class illustrates the use case of transferring the money between * two accounts. We show case two cases in this: *
* ** In the first use case, we will do only one transfer at a time and assume that * there is no other * conflicting transaction happening in the system. * * In the second use case, we will spawn multiple threads each doing a * transaction of its own but with the same accounts involved. * In doing so, some threads will get an OCC error, and they will retry their * transaction and eventually succeed. Once all the threads complete, * we ensure that the balance across accounts is as expected *
* ** In these use cases we leverage the ".execute" method of QLDB Java driver. * This is a convenience method which takes care of starting the transaction, * executing the statements, and committing the transaction. * If, during the commit phase, there is an OCC exception, the method will retry * the entire transaction again (till it has exhausted the maximum retry * attempts or it times out). With this, the application does not have to worry * about doing the retries manually. *
*/ @Slf4j public class TransferMoney { private Banking banking; public TransferMoney(@NonNull final Banking banking) { this.banking = banking; } /** * This shows transfer of 5000 USD from Account A001 to Account A003 * We log the balances of Accounts A001 and A003 before and after the * transfer. * * After the Transfer: * 1) The USD balance in account A001 should be $5000 less than what we * logged initially * * 2) The USD balance in account A003 should be $5000 more than what we * logged initially */ public void runSingleTransfer() { final List* In this case, we demonstrate how the OCC can get transparently handled * if you use the convenience method (.execute) of the qldbSession. * If you want more control on your qldb transactions and manage the OCC * yourself, check the examples in "ManualQLDBTransactions" class *
* ** Example used in this method: * There are three transactions we want to do, in parallel. * 1) Transfer $500 from Account A001 to Account A003 * 2) Transfer $400 from Account A001 to Account A004 * 3) Transfer $300 from Account A003 to Account A004 *
* ** Let's assume that all the accounts have enough balances in order to do * the transactions (no case of overdraw) We first log the balances of * Account A001, A003 and A004. This logging is just for debugging and not * part of the banking activity. * * At the end of these transactions: * 1) The USD balance in account A001 should be $900 less than what we * logged initially * * 2) The USD balance in account A003 should be $200 more than what we * logged initially(since it gets $500 from A001 and gives $300 to A004) * * 3) The USD balance in account A004 should be $700 more than what we * logged initially *
*/ public void runParallelTransfers() throws InterruptedException { //check the Balances for all the accounts before beginning the transfers final List