| 1 | | = Phase P8 |
| 2 | | |
| 3 | | == Content |
| 4 | | To be defined. |
| | 1 | = P8 – Advanced Application Development (Transactions, Pooling) = |
| | 2 | |
| | 3 | == Overview == |
| | 4 | In this phase we explain two important database concepts used in real-world applications: database transactions and database connection pooling. |
| | 5 | These concepts are essential for ensuring data consistency, correctness and performance when multiple users interact with the system at the same time. |
| | 6 | |
| | 7 | In our Wedding Planner prototype (Flask REST + SQLite), the same principles apply even though we use a lightweight database. In a production system, the application would typically use PostgreSQL/MySQL and pooling would be mandatory. |
| | 8 | |
| | 9 | == Transactions in databases == |
| | 10 | |
| | 11 | === What is a transaction? === |
| | 12 | A database transaction is a group of operations that must execute as a single unit. |
| | 13 | The transaction is considered successful only if all operations succeed. |
| | 14 | |
| | 15 | In practice, transactions are needed whenever multiple inserts/updates must happen together, without leaving the database in an inconsistent state. |
| | 16 | |
| | 17 | |
| | 18 | === Why are transactions important? === |
| | 19 | Transactions ensure: |
| | 20 | |
| | 21 | Atomicity → all operations succeed or none are applied |
| | 22 | |
| | 23 | Consistency → data constraints remain valid |
| | 24 | |
| | 25 | Isolation → concurrent operations do not corrupt data |
| | 26 | |
| | 27 | Durability → once committed, changes remain stored |
| | 28 | |
| | 29 | This is commonly summarized as the ACID principles. |
| | 30 | |
| | 31 | |
| | 32 | === COMMIT and ROLLBACK === |
| | 33 | A transaction typically works like this: |
| | 34 | |
| | 35 | BEGIN → start transaction |
| | 36 | |
| | 37 | Execute multiple SQL operations |
| | 38 | |
| | 39 | COMMIT → save changes permanently if everything succeeded |
| | 40 | |
| | 41 | ROLLBACK → undo everything if an error occurs |
| | 42 | |
| | 43 | Example (SQL pseudocode): |
| | 44 | |
| | 45 | {{{ |
| | 46 | BEGIN; |
| | 47 | |
| | 48 | UPDATE venue_booking SET status='CONFIRMED' WHERE booking_id=10; |
| | 49 | UPDATE wedding SET notes='Venue confirmed' WHERE wedding_id=1; |
| | 50 | |
| | 51 | COMMIT; |
| | 52 | -- If any query fails → ROLLBACK; |
| | 53 | }}} |
| | 54 | |
| | 55 | |
| | 56 | === Transaction example connected to our project === |
| | 57 | |
| | 58 | ==== Scenario: Venue booking confirmation ==== |
| | 59 | In the Wedding Planner application, when the user makes a venue booking we must: |
| | 60 | |
| | 61 | insert the booking record |
| | 62 | |
| | 63 | update the wedding to reflect the new booking |
| | 64 | |
| | 65 | ensure no conflicting booking exists |
| | 66 | |
| | 67 | If one step fails, the database must not store partial data. |
| | 68 | |
| | 69 | Pseudocode logic: |
| | 70 | |
| | 71 | {{{ |
| | 72 | BEGIN TRANSACTION |
| | 73 | |
| | 74 | Check if venue is free at that time |
| | 75 | |
| | 76 | Insert venue_booking |
| | 77 | |
| | 78 | Update wedding record (venue selected) |
| | 79 | |
| | 80 | COMMIT |
| | 81 | If any step fails -> ROLLBACK |
| | 82 | }}} |
| | 83 | |
| | 84 | |
| | 85 | ==== Conflict detection and transaction need ==== |
| | 86 | In our prototype we check conflicts using the endpoint: |
| | 87 | |
| | 88 | {{{ |
| | 89 | /availability/venue?venue_id=1&date=2026-06-20&start=15:00&end=21:00 |
| | 90 | }}} |
| | 91 | |
| | 92 | In a real system, a conflict check MUST be done inside a transaction, because: |
| | 93 | |
| | 94 | User A checks availability (free) |
| | 95 | |
| | 96 | User B checks availability (free) |
| | 97 | |
| | 98 | Both insert booking at same time |
| | 99 | |
| | 100 | → double booking occurs |
| | 101 | |
| | 102 | Correct approach: |
| | 103 | |
| | 104 | conflict check + insert booking must be executed atomically inside a transaction. |
| | 105 | |
| | 106 | |
| | 107 | == Isolation and concurrency (basic overview) == |
| | 108 | |
| | 109 | === What is isolation? === |
| | 110 | Isolation defines how multiple users/requests interact with the database at the same time. |
| | 111 | If isolation is weak, two concurrent transactions may read or write inconsistent values. |
| | 112 | |
| | 113 | Common concurrency problems: |
| | 114 | |
| | 115 | Dirty read → reading uncommitted changes |
| | 116 | |
| | 117 | Non-repeatable read → same query returns different results in same transaction |
| | 118 | |
| | 119 | Phantom read → new rows appear in repeated query |
| | 120 | |
| | 121 | Even though SQLite is simplified, in production databases isolation level must be chosen carefully. |
| | 122 | |
| | 123 | |
| | 124 | === Example connected to our project === |
| | 125 | If two users RSVP at the same time, without proper isolation: |
| | 126 | |
| | 127 | RSVP counts can become incorrect |
| | 128 | |
| | 129 | Attendance table could end up with duplicates |
| | 130 | |
| | 131 | The final result may not reflect correct guest statuses |
| | 132 | |
| | 133 | Therefore, operations such as RSVP update and attendance update should be transactional. |
| | 134 | |
| | 135 | == Transactions inside Flask prototype == |
| | 136 | |
| | 137 | === How transactions would be handled in Flask === |
| | 138 | In Flask (with SQLAlchemy or DB sessions), the implementation is usually: |
| | 139 | |
| | 140 | start session/transaction |
| | 141 | |
| | 142 | execute queries |
| | 143 | |
| | 144 | commit |
| | 145 | |
| | 146 | on exception → rollback |
| | 147 | |
| | 148 | Pseudocode example (Flask-like): |
| | 149 | |
| | 150 | {{{ |
| | 151 | try: |
| | 152 | db.session.begin() |
| | 153 | |
| | 154 | # check availability |
| | 155 | # insert booking |
| | 156 | # update wedding |
| | 157 | |
| | 158 | db.session.commit() |
| | 159 | |
| | 160 | |
| | 161 | except Exception: |
| | 162 | db.session.rollback() |
| | 163 | }}} |
| | 164 | |
| | 165 | Even if our prototype is minimal and uses SQLite, the concept remains the same and would scale directly to PostgreSQL. |
| | 166 | |
| | 167 | == Database connection pooling == |
| | 168 | |
| | 169 | === What is connection pooling? === |
| | 170 | Connection pooling means reusing open database connections instead of creating a new connection for every request. |
| | 171 | |
| | 172 | Without pooling: |
| | 173 | |
| | 174 | each HTTP request opens a new DB connection |
| | 175 | |
| | 176 | connecting is expensive |
| | 177 | |
| | 178 | under load this becomes slow and unstable |
| | 179 | |
| | 180 | With pooling: |
| | 181 | |
| | 182 | application keeps a pool of reusable connections |
| | 183 | |
| | 184 | requests take an available connection from the pool |
| | 185 | |
| | 186 | after request finishes → connection is returned to the pool |
| | 187 | |
| | 188 | === Why pooling improves performance === |
| | 189 | Pooling gives: |
| | 190 | |
| | 191 | faster response time (no repeated connection overhead) |
| | 192 | |
| | 193 | controlled DB resource usage |
| | 194 | |
| | 195 | scalability for multiple concurrent users |
| | 196 | |
| | 197 | For example: |
| | 198 | |
| | 199 | 100 users → 100 requests |
| | 200 | |
| | 201 | without pooling → 100 new connections created |
| | 202 | |
| | 203 | with pooling → e.g. 10 reusable connections shared |
| | 204 | |
| | 205 | === Pooling in our Wedding Planner system === |
| | 206 | In the final real system, pooling would be very important for: |
| | 207 | |
| | 208 | /weddings |
| | 209 | /weddings/1/guests |
| | 210 | RSVP updates |
| | 211 | availability checks (these can be frequent) |
| | 212 | Availability check endpoints can receive many calls, so pooling prevents performance degradation. |
| | 213 | |
| | 214 | === Example pooling config (conceptual) === |
| | 215 | In SQLAlchemy a pool configuration might look like: |
| | 216 | |
| | 217 | {{{ |
| | 218 | engine = create_engine( |
| | 219 | DB_URL, |
| | 220 | pool_size=10, |
| | 221 | max_overflow=20 |
| | 222 | ) |
| | 223 | }}} |
| | 224 | |
| | 225 | This ensures controlled and reusable DB connections. |
| | 226 | |
| | 227 | |
| | 228 | == Conclusion == |
| | 229 | This phase introduced two key concepts for advanced backend applications: transactions and database connection pooling. |
| | 230 | Transactions ensure correctness and consistency, especially when multiple operations must succeed together (such as bookings + conflict checks). |
| | 231 | COMMIT and ROLLBACK ensure that the database is not left in a partial or broken state when an error occurs. |
| | 232 | |
| | 233 | Connection pooling improves performance and scalability by reusing database connections instead of creating new ones for every request. |
| | 234 | These principles directly apply to our Wedding Planner system, especially for booking, RSVP and venue availability scenarios, and they represent best practices for real production systems. |