Learnings While Working with Real Money and MySQL

Bhavin Gandha
Yudiz Solutions
Published in
4 min readMay 10, 2023

In the world of financial technology, or FinTech, handling real money requires the utmost precision, accuracy, and security. As a developer, you need to ensure that your database transactions are secure and free from data inconsistencies. In this blog, we’ll discuss some key learnings I’ve gathered from working with real money and MySQL, focusing on the use of transactions, isolation levels, row locking, and stored procedures.

  1. Always Use Transactions

Transactions are a fundamental concept in database systems, providing an all-or-nothing guarantee that ensures your database remains in a consistent state. In the context of financial applications, this means that if any part of the transaction fails, the entire transaction will be rolled back, and no changes will be made to the database. This prevents scenarios like transferring money between accounts only for half the transaction to succeed.

With MySQL, you can use the following commands to work with transactions:

  • START TRANSACTION;: Initiates a new transaction.
  • COMMIT;: Commits the transaction, making all changes permanent.
  • ROLLBACK;: Rolls back the transaction, undoing all changes.

Always use transactions when performing multiple, related operations that involve real money to maintain data consistency.

2. Isolation Level Matter a Lot

Isolation levels determine the degree to which transactions are isolated from one another. In other words, they control the visibility of data modifications made by one transaction to other concurrent transactions. MySQL supports four isolation levels:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ (default)
  • SERIALIZABLE

Higher isolation levels provide greater consistency guarantees but may reduce concurrency and performance. Choose the appropriate isolation level for your application, considering factors such as data integrity requirements, performance, and potential deadlock scenarios.

3. Use FOR UPDATE to Lock Rows

When dealing with real money, preventing concurrent modifications to the same data is crucial. Using the FOR UPDATE clause in your SELECT the statement allows you to lock the selected rows, preventing other transactions from modifying them until your transaction is complete. This ensures that your application operates with the most accurate and up-to-date information when performing financial operations.

For example:

START TRANSACTION;
SELECT amount FROM accounts WHERE account_id = 1 FOR UPDATE;
-- Perform necessary calculations and updates here
COMMIT;

4. If No Rows Return, Then There Are No Lockings

If a SELECT ... FOR UPDATE the query returns no rows, which means there are no row lockings in place. This is useful for avoiding deadlocks and improving overall application performance. You can use this behavior to your advantage by checking for the absence of locked rows before proceeding with your transaction.

5. For Long Transactions/Queries, Use Stored Procedures

Stored procedures are pre-compiled routines stored in the database that can be executed with a single call. They offer several advantages in financial applications:

  • Improved performance: Stored procedures are compiled once and cached, reducing the overhead of parsing and compiling SQL statements repeatedly.
  • Reduced network traffic: Since the procedure is stored in the database, only the call to execute it is sent over the network, not the entire SQL statement.
  • Enhanced security: By encapsulating complex logic in stored procedures, you can limit direct access to the underlying tables and enforce stricter access controls.

For long transactions or complex queries, using stored procedures can boost performance and security, making your application more efficient and reliable when handling real money

6. Use SKIP LOCKED and NOWAIT for Better Concurrency Control

In addition to the FOR UPDATE clause, MySQL provides two more options for better concurrency control: SKIP LOCKED and NOWAIT. These options can help you handle situations where waiting for a locked row might lead to inefficiencies or deadlocks.

  • SKIP LOCKED: This option allows you to skip over rows that are currently locked by other transactions. This can be helpful in cases where you want to process multiple records without waiting for locks held by other transactions to be released. For example, if you're processing a queue of financial transactions, you can use SKIP LOCKED it to process unlocked records without waiting for locked records to become available:
SELECT * FROM transactions WHERE status = 'pending' ORDER BY created_at LIMIT 1 FOR UPDATE SKIP LOCKED;
  • NOWAIT: The NOWAIT the option makes your query fail immediately if it encounters a locked row instead of waiting for the lock to be released. This can be useful in cases where you want to avoid waiting for a lock, allowing you to implement custom error handling or retry logic. For example:
START TRANSACTION;
SELECT amount FROM accounts WHERE account_id = 1 FOR UPDATE NOWAIT;
-- If the row is locked, an error will be raised, and you can handle it accordingly
COMMIT;

Conclusion

Handling real money in a database environment like MySQL requires a deep understanding of transactions, isolation levels, row locking, and stored procedures. By leveraging these concepts and techniques, you can build more robust, secure, and efficient financial applications, ensuring the

--

--