Firebase Flutter中runTransaction与set()的区别及使用原因问询
runTransaction() vs set() for Counter Increment Great question! Let's break down exactly why the example uses runTransaction() instead of set() for incrementing a counter, and how these two methods differ.
Core Differences Between runTransaction() and set()
1. set(): Direct, Stateless Write
The set() method is a straightforward way to write or overwrite data at a Firebase reference. It doesn't care about the current value of the data—you tell it what to set, and it does it immediately. For example:
_counterRef.set(5);
This will set the counter to 5, no matter what value was there before (3, 10, null, etc.).
The problem with using this for incrementing is that you'd have to first read the current value, add 1, then call set(). But if multiple users do this at the same time, you get a race condition:
- User A reads the counter as 3
- User B reads the counter as 3 at the same time
- Both add 1 to get 4
- Both call
set(4) - The final value is 4 instead of the expected 5
2. runTransaction(): Atomic, Stateful Update
runTransaction() is designed for situations where you need to modify existing data safely, even with concurrent updates. Here's how it works:
- Firebase fetches the current value of the reference.
- Your transaction function runs, modifying the
MutableData(in your example, adding 1 to the current value). - Firebase checks if the data has changed since it fetched it. If it hasn't, the updated value is written. If it has changed (because another user modified it), Firebase automatically retries the entire transaction process with the new value.
This means your increment logic (mutableData.value ?? 0) + 1 will always operate on the latest version of the data, no matter how many users are trying to increment at the same time. The final count will be accurate every time.
Why the Example Uses runTransaction()
Counters are a classic use case for transactions because they're almost always accessed by multiple users simultaneously. If the example used set() instead of runTransaction(), concurrent increments would lead to lost updates and incorrect counts.
With the transaction approach, Firebase handles all the concurrency behind the scenes—you don't have to write any extra code to detect or resolve conflicts. It ensures the increment operation is atomic (it either completes fully or doesn't happen at all) and consistent.
Quick Recap
- Use
set()when you need to write a fixed value and don't care about the current state of the data (e.g., setting a user's profile info). - Use
runTransaction()when you need to modify existing data based on its current value, especially in scenarios with concurrent updates (e.g., counters, likes, stock levels).
内容的提问来源于stack exchange,提问作者Paul

