haliliceylan 27 minutes ago

Thats not postgresql problem, thats your code

IMHO you should never write code like that, you can either do UPDATE employees SET salary = salary + 500 WHERE employee_id = 101;

Or if its more complex just use STORED PROCEDURE, there is no point of using database if you gonna do all transactional things in js

  • lirbank 10 minutes ago

    Here's a real-world example where atomic updates aren't an option - an order status transition that reads the current status from one table, validates the transition, and inserts into another:

    await db().transaction(async (tx) => { await hooks?.onTxBegin?.();

      const [order] = await tx.select().from(orders)
        .where(eq(orders.id, input.id))
        .for("update");
    
      const [status] = await tx.select().from(orderStatuses)
        .where(eq(orderStatuses.orderId, input.id))
        .orderBy(desc(orderStatuses.createdAt))
        .limit(1);
    
      if (input.status === status.code)
        throw new Error("Status already set");
    
      await tx.insert(orderStatuses).values({ ... });
    });

    You need the transaction + SELECT FOR UPDATE because the validation depends on current state, and two concurrent requests could both pass the duplicate check. The hooks parameter is the barrier injection point from the article - that's how you test that the lock actually prevents the race.

  • lirbank 20 minutes ago

    Fair point - atomic updates like SET salary = salary + 500 sidestep the race condition entirely for simple cases. The examples are intentionally simplified to isolate the concurrency behavior. The barrier pattern is more relevant when you have read-modify-write operations that involve application logic between the read and the write - those can't always collapse into a single UPDATE.