TRANSACTION Jannarong Wadthong


14/Feb/2020
TEXT
▸ Javascript


▸ Plain database connection


▸ Plain transaction


▸ Spring Transaction


▸ Declarative Transaction


▸ @Transaction Annotation
TRANSACTION IN
TRANSACTION IN JAVASCRIPT
WHAT WE GOING TO LEARN
Establishing connection


Performing queries


Terminating connection
npm install mysql
TRANSACTION IN JAVASCRIPT
ESTABLISHING CONNECTION
const mysql = require('mysql');


const connection = mysql.createConnection({


host : 'example.org',


user : 'bob',


password : 'secret'


});




(async function () {


const error = await connection.connect();


if (err) {


console.error('error connecting: ' + err.stack);


return;


}




console.log('connected as id ' + connection.threadId);


})();
TRANSACTION IN JAVASCRIPT
PERFORM QUERIES
const { error, result } = connection.query({


sql: 'SELECT * FROM `books` WHERE `author` = "David"'


timeout: 60000, // 60s


});


// Terminate connections


connection.end();
TRANSACTION IN JAVASCRIPT
WHAT WE GOING TO LEARN
Begin/End Transaction
TRANSACTION IN JAVASCRIPT
TRANSACTION OPERATIONS
1. Begin Transaction


2. Execute SQL query


3. Execute SQL query


4. ..


5. .


8. Commit Transaction
UNIT OF WORK
ALL-OR-NOTHING UNIT OF WORK
‣ ALL OPERATION SUCCEED, COMMIT A TRANSACTION


‣ ANY FAILS, ROLLBACK ALL OPERATIONS LIKE NOTHING HAPPENS
TRANSACTION IN JAVASCRIPT
TRANSACTION
// 1. Begin transaction / define transactional boundary


const [ trxError ] = await connection.beginTransaction(() => {




// 2. sql statements here // if failed, rollback


await connection.commit();




});


if (trxError) {


throw trxError;


}
TRANSACTION IN JAVASCRIPT
WHAT WE GOING TO TALK: 3 SCENARIOS IN ATM
Transfer


Deposit


Withdraw
TRANSACTION IN JAVASCRIPT
TRANSACTION: TRANSFER MONEY
const [ trxError ] = await connection.beginTransaction(() => {


try {


// deposit


await connection.query('UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance + amount, toAccount);


// withdraw


await connection.query('UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance - amount, fromAccount);


await connection.commit();


} catch (error) {


const [ rollbackFailed ] = await connection.rollback();


throw rollbackFailed;


}


});


if (trxError) {


throw trxError;


}
TRANSACTION IN JAVASCRIPT
TRANSACTION: TRANSFER MONEY
const [ trxError ] = await connection.beginTransaction(() => {


try {


await withdraw(to, amount, connection);


await deposit(to, amount, connection);


await connection.commit();


} catch (error) {


const [ rollbackFailed ] = await connection.rollback();


throw rollbackFailed;


}


});


if (trxError) {


throw trxError;


}
TRANSACTION IN JAVASCRIPT
TRANSACTION: TRANSFER MONEY
async function transfer(to, from, amount, connection) {


const [ trxError ] = await connection.beginTransaction(() => {


await withdraw(from, amount, connection);


await deposit(to, amount, connection);


});


if (trxError) {


throw trxError;


}


}
TRANSACTION IN JAVASCRIPT
TRANSACTION: TRANSFER MONEY
async function deposit(account, amount, connection) {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance + amount, account);


}


async function withdraw(account, amount, connection) {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance - amount, account);


}


async function getBalance(account, connection) {


const [ balance ] = await connection.query(


'SELECT balance FROM accounts WHERE account_no = ?', account);


return balance;


}
TEXT
TRANSFER MONEY
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN TRANSACTION
END TRANSACTION
CHECK BALANCE WITHDRAW DEPOSIT
CHECK BALANCE
TEXT
TRANSFER MONEY: HAPPY PATH
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
COMMIT
CHECK BALANCE WITHDRAW DEPOSIT
CHECK BALANCE
TEXT
TRANSFER MONEY: UNHAPPY PATH
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
ROLLBACK
CHECK BALANCE WITHDRAW DEPOSIT
CHECK BALANCE
TEXT
TRANSFER MONEY: 2ND CHECK BALANCE FAILS
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
ROLLBACK
CHECK BALANCE WITHDRAW DEPOSIT
CHECK BALANCE
TEXT
TRANSFER MONEY: 2ND CHECK BALANCE FAILS
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
ROLLBACK
CHECK BALANCE WITHDRAW DEPOSIT
CHECK BALANCE
TEXT
TRANSFER MONEY: LET’S CALL IT ‘TRANSACTIONAL FUNCTION’
ESTABLISH CONNECTION
TERMINATE CONNECTION
TRANSFER TRANSACTION BOUNDARY
TRANSACTION IN JAVASCRIPT
TRANSACTION: WITHDRAW MONEY
async function withdraw(account, amount, connection) {


const [ beginTrxFailed ] = await connection.beginTransaction(() => {


const balance = getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance - amount, account);


});


if (beginTrxFailed) {


throw beginTrxFailed;


}


}






async function getBalance(account, connection) {


const [ balance ] = await connection.query(


'SELECT balance FROM accounts WHERE account_no = ?', account);


return balance;


}
TRANSACTION IN JAVASCRIPT
COMPARISON: WITHDRAW VS TRANSFER
async function withdraw(account, amount, connection) {


const [ beginTrxFailed ] = await connection.beginTransaction(() => {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance - amount, account);


});


if (beginTrxFailed) {


throw beginTrxFailed;


}


}






async function withdraw(account, amount, connection) {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance - amount, account);


}




WITHDRAW FUNCTION IN TRANSFER SCENARIO
WITHDRAW FUNCTION IN WITHDRAW SCENARIO TRANSACTIONAL FUNCTION
NON-TRANSACTIONAL FUNCTION
TEXT
WITHDRAW MONEY
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
COMMIT
CHECK BALANCE WITHDRAW
TEXT
DEPOSIT MONEY
ESTABLISH CONNECTION
TERMINATE CONNECTION
BEGIN
COMMIT
CHECK BALANCE DEPOSIT
TRANSACTION IN JAVASCRIPT
TRANSACTION: DEPOSIT MONEY
async function deposit(account, amount, connection) {


const [ beginTrxFailed ] = await connection.beginTransaction(() => {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance + amount, account);


});


if (beginTrxFailed) {


throw beginTrxFailed;


}


}






async function getBalance(account, connection) {


const [ balance ] = await connection.query(


'SELECT balance FROM accounts WHERE account_no = ?', account);


return balance;


}
TRANSACTION IN JAVASCRIPT
COMPARISON: DEPOSIT VS TRANSFER
async function deposit(account, amount, connection) {


const [ beginTrxFailed ] = await connection.beginTransaction(() => {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance + amount, account);


});


if (beginTrxFailed) {


throw beginTrxFailed;


}


}






async function deposit(account, amount, connection) {


const balance = await getBalance(account, connection);


await connection.query(


'UPDATE accounts SET balance = ? WHERE account_no = ?’,


balance + amount, account);


}




DEPOSIT FUNCTION IN TRANSFER SCENARIO
DEPOSIT FUNCTION IN DEPOSIT SCENARIO TRANSACTIONAL FUNCTION
NON-TRANSACTIONAL FUNCTION
TEXT
PROGRAMMATIC TRANSACTIONAL MODEL
WITHDRAW
FUNCTION
DEPOSIT


FUNCTION
TRANSFER
FUNCTION
DEPOSIT SQL FUNCTION WITHDRAW SQL FUNCTION
DEPOSIT SQL FUNCTION
WITHDRAW SQL FUNCTION
TRANSACTIONAL BOUNDARY TRANSACTIONAL BOUNDARY TRANSACTIONAL BOUNDARY
TRANSACTION TEMPLATE TRANSACTION TEMPLATE TRANSACTION TEMPLATE
TRANSACTION IN JAVASCRIPT
PROGRAMATIC: TRANSFER SCENARIO
async function transfer(to, from, amount) {


transactionTemplate.exec(() => {


await withdrawSQL(from, amount);


await depositSQL(to, amount);


});


}


async function depositSQL(account, amount) {


// body omitted


}


async function withdrawSQL(account, amount) {


// body omitted


}




async function getBalanceSQL(account) {


// body omitted


}
TRANSACTION IN JAVASCRIPT
PROGRAMATIC: WITHDRAW SCENARIO
async function withdraw(account, amount) {


transactionTemplate.exec(() => {


await withdrawSQL(account, amount);


});


}


async function withdrawSQL(account, amount) {


// body omitted


}




async function getBalanceSQL(account) {


// body omitted


}
TRANSACTION IN JAVASCRIPT
PROGRAMATIC: DEPOSIT SCENARIO
async function deposit(account, amount) {


transactionTemplate.exec(() => {


await depositSQL(account, amount);


});


}


async function depositSQL(account, amount) {


// body omitted


}




async function getBalanceSQL(account) {


// body omitted


}
TEXT
DECLARATIVE TRANSACTIONAL MODEL
WITHDRAW
FUNCTION
DEPOSIT


FUNCTION
TRANSFER
FUNCTION
TRANSACTION BOUNDARY
TRANSACTION BOUNDARY
TRANSACTION BOUNDARY
DEPOSIT SQL FUNCTION WITHDRAW SQL FUNCTION
DEPOSIT SQL FUNCTION
WITHDRAW SQL FUNCTION
TRANSACTION IN JAVASCRIPT
DECLARATIVE: TRANSFER SCENARIO
@Transactional


async function transfer(to, from, amount) {


await withdrawSQL(from, amount);


await depositSQL(to, amount);


}


@Transactional
public void transfer(Account to, Account from, BigDecimal amount) {
withdraw(from, amount);
deposit(to, amount);
}
TRANSACTION IN JAVASCRIPT
DECLARATIVE: WITHDRAW SCENARIO
@Transactional


async function withdraw(account, amount) {


await withdrawSQL(account, amount);


}


@Transactional
public void withdraw(Account account, BigDecimal amount) {
accountRepository.withdraw(account.getAccountNo(), amount);
}
TRANSACTION IN JAVASCRIPT
DECLARATIVE: DEPOSIT SCENARIO
@Transactional


async function deposit(account, amount) {


await depositSQL(account, amount);


}


@Transactional
public void deposit(Account account, BigDecimal amount) {
accountRepository.deposit(account.getAccountNo(), amount);
}
TRANSACTION IN SPRING
COMPARISON: DEPOSIT VS TRANSFER
@Transactional
public void transfer(Account to, Account from, BigDecimal amount) {
withdraw(from, amount);
deposit(to, amount);
}
@Transactional
public void withdraw(Account account, BigDecimal amount) {
accountRepository.withdraw(account.getAccountNo(), amount);
}
@Transactional
public void deposit(Account account, BigDecimal amount) {
accountRepository.deposit(account.getAccountNo(), amount);
}
TRANSACTIONAL METHOD CALLS ANOTHER TWO TRANSACTIONAL METHODS
TRANSACTION IN SPRING
DEPOSIT AND WITHDRAW SCENARIOS
WITHDRAW METHOD
DEPOSIT


METHOD
TRANSACTION BOUNDARY
TRANSACTION BOUNDARY
TRANSACTION IN SPRING
TRANSFER SCENARIO
TRANSFER METHOD
TRANSACTION BOUNDARY
WITHDRAW METHOD
TRANSACTION BOUNDARY
DEPOSIT


METHOD
TRANSACTION BOUNDARY
TRANSACTION IN SPRING
EXPECTED TRANSFER SCENARIO
TRANSFER METHOD
TRANSACTION BOUNDARY
WITHDRAW METHOD
DEPOSIT


METHOD
TRANSACTION IN SPRING
TRANSFER SCENARIO
▸ Reuse existing methods


▸ Expect 1 physical transaction


▸ Unexpected 2 extra transactions


▸ Logical transaction solves the
problem


▸ Introducing Propagation
TRANSFER METHOD
TRANSACTION BOUNDARY
WITHDRAW METHOD
TRANSACTION BOUNDARY
DEPOSIT


METHOD
TRANSACTION BOUNDARY
ATM SERVICE CLASS
@Service
public class ATMService {
private AccountRepository accountRepository;
public ATMService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
@Transactional
public void transfer(Account to, Account from, BigDecimal amount) {
medthodA();
a.withdraw(from, amount);
b.deposit(to, amount);
}
@Transactional
public void withdraw(Account account, BigDecimal amount) {
accountRepository.withdraw(account.getAccountNo(), amount);
}
@Transactional
public void deposit(Account account, BigDecimal amount) {
accountRepository.deposit(account.getAccountNo(), amount);
}
}
TEXT
ATMService
+ transfer()


+ withdraw()


+ deposit()
TRANSACTION IN SPRING
@Service
public class UserService {
@Autowired
private InvoiceService invoiceService;
@Transactional
public void invoice() {
invoiceService.createPdf();
// send invoice as email, etc.
}
}
@Service
class InvoiceService {
@Transactional
public void createPdf() {
// ...
}
}
TRANSACTION IN SPRING
TWO LOGICAL TRX. MAPS TO TWO PHYSICAL TRX.
@Service
public class UserService {
private InvoiceService invoiceService;
public UserService(InvoiceService invoiceService) {
this.invoiceService = invoiceService;
}
@Transactional
public void invoice() {
invoiceService.createPdf();
// send invoice as email, etc.
}
}
@Service
class InvoiceService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createPdf() {
// ...
TEXT
TO SUM UP: PHYSICAL TRANSACTION VS LOGICAL TRANSACTION
▸ Physical Transactions: Are your actual JDBC transactions.


▸ Logical Transactions: Are the (potentially nested)
@Transactional-annotated (Spring) methods.
TRANSACTION IN SPRING
@TRANSACTIONAL UNDER THE COVERS
@Transactional


ATMService Proxy


1.open transaction


2.close transaction
ATMController Real ATMService
+ transfer()


+ withdraw()


+ deposit()
As you can see from that diagram, the proxy has one job.
• Opening and closing database connections/transactions.
• And then delegating to the real ATMService, the one we wrote.
• And ATMController will never know that they are talking to a proxy, and not the real thing.
@Transactional


ATMService Proxy
TRANSACTION IN SPRINGTEXT
@TRANSACTIONAL UNDER THE COVERS: TRANSFER SCENARIO
TRANSFER METHOD
WITHDRAW METHOD
DEPOSIT METHOD
1.Open transaction
2.Close transaction
TRANSACTION IN SPRING
TRANSACTION PROPAGATION: REQUIRE
DEPOSIT WITHDRAW
TRANSACTION IN SPRING
TRANSACTION PROPAGATION: REQUIRE_NEW
INVOICE CREATE-PDF
TRANSACTION IN SPRING
THE MOST COMMON @TRANSACTIONAL PITFALL
@Service
public class UserService {
@Transactional
public void invoice() {
createPdf();
// send invoice as email, etc.
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createPdf() {
// ...
}
}
How many physical transactions would you expect to be open, once someone calls
invoice()?
TEXT
THE MOST COMMON @TRANSACTIONAL PITFALL
There’s some tricks (like self-injection), which you can use to get around
this limitation.
But the main takeaway is: always keep the proxy transaction boundaries
in mind.
TEXT
ROLLBACK WITH SPRING PROPAGATION
▸ Number of remaining products (2)

Spring Transaction

  • 1.
  • 2.
    TEXT ▸ Javascript ▸ Plaindatabase connection ▸ Plain transaction ▸ Spring Transaction ▸ Declarative Transaction ▸ @Transaction Annotation
  • 3.
  • 4.
    TRANSACTION IN JAVASCRIPT WHATWE GOING TO LEARN Establishing connection Performing queries Terminating connection npm install mysql
  • 5.
    TRANSACTION IN JAVASCRIPT ESTABLISHINGCONNECTION const mysql = require('mysql'); const connection = mysql.createConnection({ host : 'example.org', user : 'bob', password : 'secret' }); (async function () { const error = await connection.connect(); if (err) { console.error('error connecting: ' + err.stack); return; } console.log('connected as id ' + connection.threadId); })();
  • 6.
    TRANSACTION IN JAVASCRIPT PERFORMQUERIES const { error, result } = connection.query({ sql: 'SELECT * FROM `books` WHERE `author` = "David"' timeout: 60000, // 60s }); // Terminate connections connection.end();
  • 7.
    TRANSACTION IN JAVASCRIPT WHATWE GOING TO LEARN Begin/End Transaction
  • 8.
    TRANSACTION IN JAVASCRIPT TRANSACTIONOPERATIONS 1. Begin Transaction 2. Execute SQL query 3. Execute SQL query 4. .. 5. . 8. Commit Transaction UNIT OF WORK ALL-OR-NOTHING UNIT OF WORK ‣ ALL OPERATION SUCCEED, COMMIT A TRANSACTION ‣ ANY FAILS, ROLLBACK ALL OPERATIONS LIKE NOTHING HAPPENS
  • 9.
    TRANSACTION IN JAVASCRIPT TRANSACTION //1. Begin transaction / define transactional boundary const [ trxError ] = await connection.beginTransaction(() => { // 2. sql statements here // if failed, rollback await connection.commit(); }); if (trxError) { throw trxError; }
  • 10.
    TRANSACTION IN JAVASCRIPT WHATWE GOING TO TALK: 3 SCENARIOS IN ATM Transfer Deposit Withdraw
  • 11.
    TRANSACTION IN JAVASCRIPT TRANSACTION:TRANSFER MONEY const [ trxError ] = await connection.beginTransaction(() => { try { // deposit await connection.query('UPDATE accounts SET balance = ? WHERE account_no = ?’, balance + amount, toAccount); // withdraw await connection.query('UPDATE accounts SET balance = ? WHERE account_no = ?’, balance - amount, fromAccount); await connection.commit(); } catch (error) { const [ rollbackFailed ] = await connection.rollback(); throw rollbackFailed; } }); if (trxError) { throw trxError; }
  • 12.
    TRANSACTION IN JAVASCRIPT TRANSACTION:TRANSFER MONEY const [ trxError ] = await connection.beginTransaction(() => { try { await withdraw(to, amount, connection); await deposit(to, amount, connection); await connection.commit(); } catch (error) { const [ rollbackFailed ] = await connection.rollback(); throw rollbackFailed; } }); if (trxError) { throw trxError; }
  • 13.
    TRANSACTION IN JAVASCRIPT TRANSACTION:TRANSFER MONEY async function transfer(to, from, amount, connection) { const [ trxError ] = await connection.beginTransaction(() => { await withdraw(from, amount, connection); await deposit(to, amount, connection); }); if (trxError) { throw trxError; } }
  • 14.
    TRANSACTION IN JAVASCRIPT TRANSACTION:TRANSFER MONEY async function deposit(account, amount, connection) { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance + amount, account); } async function withdraw(account, amount, connection) { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance - amount, account); } async function getBalance(account, connection) { const [ balance ] = await connection.query( 'SELECT balance FROM accounts WHERE account_no = ?', account); return balance; }
  • 15.
    TEXT TRANSFER MONEY ESTABLISH CONNECTION TERMINATECONNECTION BEGIN TRANSACTION END TRANSACTION CHECK BALANCE WITHDRAW DEPOSIT CHECK BALANCE
  • 16.
    TEXT TRANSFER MONEY: HAPPYPATH ESTABLISH CONNECTION TERMINATE CONNECTION BEGIN COMMIT CHECK BALANCE WITHDRAW DEPOSIT CHECK BALANCE
  • 17.
    TEXT TRANSFER MONEY: UNHAPPYPATH ESTABLISH CONNECTION TERMINATE CONNECTION BEGIN ROLLBACK CHECK BALANCE WITHDRAW DEPOSIT CHECK BALANCE
  • 18.
    TEXT TRANSFER MONEY: 2NDCHECK BALANCE FAILS ESTABLISH CONNECTION TERMINATE CONNECTION BEGIN ROLLBACK CHECK BALANCE WITHDRAW DEPOSIT CHECK BALANCE
  • 19.
    TEXT TRANSFER MONEY: 2NDCHECK BALANCE FAILS ESTABLISH CONNECTION TERMINATE CONNECTION BEGIN ROLLBACK CHECK BALANCE WITHDRAW DEPOSIT CHECK BALANCE
  • 20.
    TEXT TRANSFER MONEY: LET’SCALL IT ‘TRANSACTIONAL FUNCTION’ ESTABLISH CONNECTION TERMINATE CONNECTION TRANSFER TRANSACTION BOUNDARY
  • 21.
    TRANSACTION IN JAVASCRIPT TRANSACTION:WITHDRAW MONEY async function withdraw(account, amount, connection) { const [ beginTrxFailed ] = await connection.beginTransaction(() => { const balance = getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance - amount, account); }); if (beginTrxFailed) { throw beginTrxFailed; } } async function getBalance(account, connection) { const [ balance ] = await connection.query( 'SELECT balance FROM accounts WHERE account_no = ?', account); return balance; }
  • 22.
    TRANSACTION IN JAVASCRIPT COMPARISON:WITHDRAW VS TRANSFER async function withdraw(account, amount, connection) { const [ beginTrxFailed ] = await connection.beginTransaction(() => { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance - amount, account); }); if (beginTrxFailed) { throw beginTrxFailed; } } async function withdraw(account, amount, connection) { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance - amount, account); } WITHDRAW FUNCTION IN TRANSFER SCENARIO WITHDRAW FUNCTION IN WITHDRAW SCENARIO TRANSACTIONAL FUNCTION NON-TRANSACTIONAL FUNCTION
  • 23.
    TEXT WITHDRAW MONEY ESTABLISH CONNECTION TERMINATECONNECTION BEGIN COMMIT CHECK BALANCE WITHDRAW
  • 24.
    TEXT DEPOSIT MONEY ESTABLISH CONNECTION TERMINATECONNECTION BEGIN COMMIT CHECK BALANCE DEPOSIT
  • 25.
    TRANSACTION IN JAVASCRIPT TRANSACTION:DEPOSIT MONEY async function deposit(account, amount, connection) { const [ beginTrxFailed ] = await connection.beginTransaction(() => { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance + amount, account); }); if (beginTrxFailed) { throw beginTrxFailed; } } async function getBalance(account, connection) { const [ balance ] = await connection.query( 'SELECT balance FROM accounts WHERE account_no = ?', account); return balance; }
  • 26.
    TRANSACTION IN JAVASCRIPT COMPARISON:DEPOSIT VS TRANSFER async function deposit(account, amount, connection) { const [ beginTrxFailed ] = await connection.beginTransaction(() => { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance + amount, account); }); if (beginTrxFailed) { throw beginTrxFailed; } } async function deposit(account, amount, connection) { const balance = await getBalance(account, connection); await connection.query( 'UPDATE accounts SET balance = ? WHERE account_no = ?’, balance + amount, account); } DEPOSIT FUNCTION IN TRANSFER SCENARIO DEPOSIT FUNCTION IN DEPOSIT SCENARIO TRANSACTIONAL FUNCTION NON-TRANSACTIONAL FUNCTION
  • 27.
    TEXT PROGRAMMATIC TRANSACTIONAL MODEL WITHDRAW FUNCTION DEPOSIT FUNCTION TRANSFER FUNCTION DEPOSITSQL FUNCTION WITHDRAW SQL FUNCTION DEPOSIT SQL FUNCTION WITHDRAW SQL FUNCTION TRANSACTIONAL BOUNDARY TRANSACTIONAL BOUNDARY TRANSACTIONAL BOUNDARY TRANSACTION TEMPLATE TRANSACTION TEMPLATE TRANSACTION TEMPLATE
  • 28.
    TRANSACTION IN JAVASCRIPT PROGRAMATIC:TRANSFER SCENARIO async function transfer(to, from, amount) { transactionTemplate.exec(() => { await withdrawSQL(from, amount); await depositSQL(to, amount); }); } async function depositSQL(account, amount) { // body omitted } async function withdrawSQL(account, amount) { // body omitted } async function getBalanceSQL(account) { // body omitted }
  • 29.
    TRANSACTION IN JAVASCRIPT PROGRAMATIC:WITHDRAW SCENARIO async function withdraw(account, amount) { transactionTemplate.exec(() => { await withdrawSQL(account, amount); }); } async function withdrawSQL(account, amount) { // body omitted } async function getBalanceSQL(account) { // body omitted }
  • 30.
    TRANSACTION IN JAVASCRIPT PROGRAMATIC:DEPOSIT SCENARIO async function deposit(account, amount) { transactionTemplate.exec(() => { await depositSQL(account, amount); }); } async function depositSQL(account, amount) { // body omitted } async function getBalanceSQL(account) { // body omitted }
  • 31.
    TEXT DECLARATIVE TRANSACTIONAL MODEL WITHDRAW FUNCTION DEPOSIT FUNCTION TRANSFER FUNCTION TRANSACTIONBOUNDARY TRANSACTION BOUNDARY TRANSACTION BOUNDARY DEPOSIT SQL FUNCTION WITHDRAW SQL FUNCTION DEPOSIT SQL FUNCTION WITHDRAW SQL FUNCTION
  • 32.
    TRANSACTION IN JAVASCRIPT DECLARATIVE:TRANSFER SCENARIO @Transactional async function transfer(to, from, amount) { await withdrawSQL(from, amount); await depositSQL(to, amount); } @Transactional public void transfer(Account to, Account from, BigDecimal amount) { withdraw(from, amount); deposit(to, amount); }
  • 33.
    TRANSACTION IN JAVASCRIPT DECLARATIVE:WITHDRAW SCENARIO @Transactional async function withdraw(account, amount) { await withdrawSQL(account, amount); } @Transactional public void withdraw(Account account, BigDecimal amount) { accountRepository.withdraw(account.getAccountNo(), amount); }
  • 34.
    TRANSACTION IN JAVASCRIPT DECLARATIVE:DEPOSIT SCENARIO @Transactional async function deposit(account, amount) { await depositSQL(account, amount); } @Transactional public void deposit(Account account, BigDecimal amount) { accountRepository.deposit(account.getAccountNo(), amount); }
  • 35.
    TRANSACTION IN SPRING COMPARISON:DEPOSIT VS TRANSFER @Transactional public void transfer(Account to, Account from, BigDecimal amount) { withdraw(from, amount); deposit(to, amount); } @Transactional public void withdraw(Account account, BigDecimal amount) { accountRepository.withdraw(account.getAccountNo(), amount); } @Transactional public void deposit(Account account, BigDecimal amount) { accountRepository.deposit(account.getAccountNo(), amount); } TRANSACTIONAL METHOD CALLS ANOTHER TWO TRANSACTIONAL METHODS
  • 36.
    TRANSACTION IN SPRING DEPOSITAND WITHDRAW SCENARIOS WITHDRAW METHOD DEPOSIT METHOD TRANSACTION BOUNDARY TRANSACTION BOUNDARY
  • 37.
    TRANSACTION IN SPRING TRANSFERSCENARIO TRANSFER METHOD TRANSACTION BOUNDARY WITHDRAW METHOD TRANSACTION BOUNDARY DEPOSIT METHOD TRANSACTION BOUNDARY
  • 38.
    TRANSACTION IN SPRING EXPECTEDTRANSFER SCENARIO TRANSFER METHOD TRANSACTION BOUNDARY WITHDRAW METHOD DEPOSIT METHOD
  • 39.
    TRANSACTION IN SPRING TRANSFERSCENARIO ▸ Reuse existing methods ▸ Expect 1 physical transaction ▸ Unexpected 2 extra transactions ▸ Logical transaction solves the problem ▸ Introducing Propagation TRANSFER METHOD TRANSACTION BOUNDARY WITHDRAW METHOD TRANSACTION BOUNDARY DEPOSIT METHOD TRANSACTION BOUNDARY
  • 40.
    ATM SERVICE CLASS @Service publicclass ATMService { private AccountRepository accountRepository; public ATMService(AccountRepository accountRepository) { this.accountRepository = accountRepository; } @Transactional public void transfer(Account to, Account from, BigDecimal amount) { medthodA(); a.withdraw(from, amount); b.deposit(to, amount); } @Transactional public void withdraw(Account account, BigDecimal amount) { accountRepository.withdraw(account.getAccountNo(), amount); } @Transactional public void deposit(Account account, BigDecimal amount) { accountRepository.deposit(account.getAccountNo(), amount); } }
  • 41.
  • 42.
    TRANSACTION IN SPRING @Service publicclass UserService { @Autowired private InvoiceService invoiceService; @Transactional public void invoice() { invoiceService.createPdf(); // send invoice as email, etc. } } @Service class InvoiceService { @Transactional public void createPdf() { // ... } }
  • 43.
    TRANSACTION IN SPRING TWOLOGICAL TRX. MAPS TO TWO PHYSICAL TRX. @Service public class UserService { private InvoiceService invoiceService; public UserService(InvoiceService invoiceService) { this.invoiceService = invoiceService; } @Transactional public void invoice() { invoiceService.createPdf(); // send invoice as email, etc. } } @Service class InvoiceService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void createPdf() { // ...
  • 44.
    TEXT TO SUM UP:PHYSICAL TRANSACTION VS LOGICAL TRANSACTION ▸ Physical Transactions: Are your actual JDBC transactions. ▸ Logical Transactions: Are the (potentially nested) @Transactional-annotated (Spring) methods.
  • 45.
    TRANSACTION IN SPRING @TRANSACTIONALUNDER THE COVERS @Transactional 
 ATMService Proxy 1.open transaction 2.close transaction ATMController Real ATMService + transfer() + withdraw() + deposit() As you can see from that diagram, the proxy has one job. • Opening and closing database connections/transactions. • And then delegating to the real ATMService, the one we wrote. • And ATMController will never know that they are talking to a proxy, and not the real thing.
  • 46.
    @Transactional 
 ATMService Proxy TRANSACTION INSPRINGTEXT @TRANSACTIONAL UNDER THE COVERS: TRANSFER SCENARIO TRANSFER METHOD WITHDRAW METHOD DEPOSIT METHOD 1.Open transaction 2.Close transaction
  • 47.
    TRANSACTION IN SPRING TRANSACTIONPROPAGATION: REQUIRE DEPOSIT WITHDRAW
  • 48.
    TRANSACTION IN SPRING TRANSACTIONPROPAGATION: REQUIRE_NEW INVOICE CREATE-PDF
  • 49.
    TRANSACTION IN SPRING THEMOST COMMON @TRANSACTIONAL PITFALL @Service public class UserService { @Transactional public void invoice() { createPdf(); // send invoice as email, etc. } @Transactional(propagation = Propagation.REQUIRES_NEW) public void createPdf() { // ... } } How many physical transactions would you expect to be open, once someone calls invoice()?
  • 50.
    TEXT THE MOST COMMON@TRANSACTIONAL PITFALL There’s some tricks (like self-injection), which you can use to get around this limitation. But the main takeaway is: always keep the proxy transaction boundaries in mind.
  • 51.
    TEXT ROLLBACK WITH SPRINGPROPAGATION ▸ Number of remaining products (2)