933

I understand the differences between optimistic and pessimistic locking. Now, could someone explain to me when I would use either one in general?

And does the answer to this question change depending on whether or not I'm using a stored procedure to perform the query?

But just to check, optimistic means "don't lock the table while reading" and pessimistic means "lock the table while reading."

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • 2
    http://blog.couchbase.com/optimistic-or-pessimistic-locking-which-one-should-you-pick – Frank Myat Thu Jan 13 '16 at 10:15
  • 3
    That is a good question particularly because in [serializability](https://en.wikipedia.org/wiki/Serializability#Optimistic_versus_pessimistic_techniques) I read `At any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts`. – Little Alien Dec 05 '16 at 15:08
  • 4
    Here you can find a good explanation, here on SO, about what is the [root concept of Optimistic Locking](https://stackoverflow.com/questions/17431338/optimistic-locking-in-mysql). – Diego Mazzaro Dec 21 '19 at 09:38
  • 2
    I would recommend to read Martin Fowler's great book on patterns: https://martinfowler.com/books/eaa.html – koppor Oct 11 '20 at 10:54
  • I think concurrency control is more accurate than locking. – Jason Law Oct 19 '21 at 09:58

13 Answers13

1227

Optimistic Locking is a strategy where you read a record, take note of a version number (other methods to do this involve dates, timestamps or checksums/hashes) and check that the version hasn't changed before you write the record back. When you write the record back you filter the update on the version to make sure it's atomic. (i.e. hasn't been updated between when you check the version and write the record to the disk) and update the version in one hit.

If the record is dirty (i.e. different version to yours) you abort the transaction and the user can re-start it.

This strategy is most applicable to high-volume systems and three-tier architectures where you do not necessarily maintain a connection to the database for your session. In this situation the client cannot actually maintain database locks as the connections are taken from a pool and you may not be using the same connection from one access to the next.

Pessimistic Locking is when you lock the record for your exclusive use until you have finished with it. It has much better integrity than optimistic locking but requires you to be careful with your application design to avoid Deadlocks. To use pessimistic locking you need either a direct connection to the database (as would typically be the case in a two tier client server application) or an externally available transaction ID that can be used independently of the connection.

In the latter case you open the transaction with the TxID and then reconnect using that ID. The DBMS maintains the locks and allows you to pick the session back up through the TxID. This is how distributed transactions using two-phase commit protocols (such as XA or COM+ Transactions) work.

nc.
  • 7,179
  • 5
  • 28
  • 38
ConcernedOfTunbridgeWells
  • 64,444
  • 15
  • 143
  • 197
  • 186
    Optimistic locking doesn't necessarily use a version number. Other strategies include using (a) a timestamp or (b) the entire state of the row itself. The latter strategy is ugly but avoids the need for a dedicated version column, in cases where you aren't able to modify the schema. – Andrew Swan Dec 08 '09 at 22:33
  • 3
    The concept of optimistic locking doesn't necessarily require having a 100% reliable way of knowing whether or not something has been altered; undetectable alterations aren't acceptable, but occasional false reports of alteration may not be too bad, especially if code which receives such a report rereads the data and checks whether it has actually changed. – supercat Jul 08 '13 at 21:43
  • @ConcernedOfTunbridgeWells I have a follow-up question on the third paragraph of your answer. You wrote "In this situation the client cannot actually maintain database locks as the connections are taken from a pool and you may not be using the same connection from one access to the next.". Why do I need to have the same connection between two different calls in order to use database locks? – Geek Jul 01 '14 at 08:09
  • @ConcernedOfTunbridgeWells Just to expand on my previous comment, so in case of optimistic locking we need to do a *select* which is followed by the *update*. So in a three tier architecture, where the application server(lets say JPA provider) is doing all the work for us. How does the persistence provider perform this then? It may be given two different instance of cached connections from the pool. – Geek Jul 01 '14 at 08:28
  • 2
    @geek - your persistence provider would have to have some explicit support for optimistic concurrency. If you're using an ORM you may need to do some homework as to how (or if) it does this. In practice the DB layer should query the timestamp and then (on updates) update with a predicate that includes ts=@timestamp or something similar. Then you check the number of rows updated. If zero then you had a stale version of the record and would have to re-load from that and return a concurrency error to the user. – ConcernedOfTunbridgeWells Jul 01 '14 at 09:23
  • @ConcernedOfTunbridgeWells Can you please explain the reasoning for the question I have put in the first comment? – Geek Jul 01 '14 at 09:37
  • 1
    @geek - database locks are typically tied to a session. In the case of a two-tier client-server application then the session is 1:1 with a connection. If you have pooled connections then you lose this relationship and you can't use this relationship. – ConcernedOfTunbridgeWells Jul 01 '14 at 09:42
  • 2
    @geek - Distributed transaction protocols such as XA allow a separate transaction identifier to be reticulated around one or more systems. This type of protocol does allow locks to be used through pooled connections as the transaction identifier is de-coupled from the sessions and supplied explicitly. However, this does incur some overhead and is prone to leak locks and transaction identifiers if your application isn't scrupulous about keeping track of them. It is a much more heavyweight solution. – ConcernedOfTunbridgeWells Jul 01 '14 at 09:46
  • 44
    @supercat - Don't agree that optimistic locking is less than 100% accurate - as long as it checks all the input records for transaction that should stay unmodified for the duration, it's as accurate as pessimistic locking (select for update style) on those same records. The main difference is that optimistic locking incurs overhead only if there's a conflict, whereas pessimistic locking has reduced overhead on conflict. So optimistic is best in case where most transactions don't conflict - which I hope is usually the case for most apps. – RichVel Aug 05 '14 at 11:33
  • Does it mean, that in web applications we have to use optimistic locking, because it's a disconnected scenario? A user might fetch data, but update it 20 min later, possibly.. – Legends Apr 02 '15 at 00:11
  • 4
    @Legends - Using optimsitic locking would certainly be an appropriate strategy for a web application. – ConcernedOfTunbridgeWells Apr 02 '15 at 07:19
  • 4
    You should mention that the choice depend also on the ratio read vs. write: if your application is mainly a read-only application by a lot of users, and sometimes you write data, than go for optimistic locking. StackOverflow, for example, have a lot of people reading pages, and sometimes someone edit one: in pessimistic locking, who would get the lock? the first one? In optimistic locking, the person who wish to edit the page can do it as long as he have the last version of it. – jehon May 05 '15 at 08:28
  • In optimistic locking you don't need to rollback if the read is dirty given than nothing was updated (due to the update version filtering) – idelvall Jul 27 '20 at 16:34
  • @idelvall - If you're just writing a single record that's true but if you have a more complex transaction involving multiple writes than one obsolete record could be reason to roll back the entire transaction. – ConcernedOfTunbridgeWells Jul 30 '20 at 10:00
  • Makes sense then, but your response could be improved to reflect this – idelvall Jul 31 '20 at 10:47
  • @RichVel, supercat was saying that it *can* work in situations where the mechanism for detecting change is not 100% accurate, not that it *only* works in situations where the mechanism is less than 100% accurate. Obviously, this depends on the design of the application and the locking mechanism, but optimistic locking gives you that flexibility. – Fr Jeremy Krieg Apr 27 '21 at 00:29
  • Well put@RichVel, just wondering if there is high latency when read from DB, then is it possible during a update action, a record version could be updated by other transaction when version verification read has been executed in DB side, but the response still on the way back to client. In this case, client won't notice the difference in version? – NathanC Aug 11 '22 at 18:52
370

When dealing with conflicts, you have two options:

  • You can try to avoid the conflict, and that's what Pessimistic Locking does.
  • Or, you could allow the conflict to occur, but you need to detect it upon committing your transactions, and that's what Optimistic Locking does.

Now, let's consider the following Lost Update anomaly:

Lost Update

The Lost Update anomaly can happen in the Read Committed isolation level.

In the diagram above we can see that Alice believes she can withdraw 40 from her account but does not realize that Bob has just changed the account balance, and now there are only 20 left in this account.

Pessimistic Locking

Pessimistic locking achieves this goal by taking a shared or read lock on the account so Bob is prevented from changing the account.

Lost Update Pessimistic Locking

In the diagram above, both Alice and Bob will acquire a read lock on the account table row that both users have read. The database acquires these locks on SQL Server when using Repeatable Read or Serializable.

Because both Alice and Bob have read the account with the PK value of 1, neither of them can change it until one user releases the read lock. This is because a write operation requires a write/exclusive lock acquisition, and shared/read locks prevent write/exclusive locks.

Only after Alice has committed her transaction and the read lock was released on the account row, Bob UPDATE will resume and apply the change. Until Alice releases the read lock, Bob's UPDATE blocks.

Optimistic Locking

Optimistic Locking allows the conflict to occur but detects it upon applying Alice's UPDATE as the version has changed.

Application-level transactions

This time, we have an additional version column. The version column is incremented every time an UPDATE or DELETE is executed, and it is also used in the WHERE clause of the UPDATE and DELETE statements. For this to work, we need to issue the SELECT and read the current version prior to executing the UPDATE or DELETE, as otherwise, we would not know what version value to pass to the WHERE clause or to increment.

Application-level transactions

Relational database systems have emerged in the late 70's early 80's when a client would, typically, connect to a mainframe via a terminal. That's why we still see database systems define terms such as SESSION setting.

Nowadays, over the Internet, we no longer execute reads and writes in the context of the same database transaction, and ACID is no longer sufficient.

For instance, consider the following use case:

Application-level transactions and Optimistic Locking

Without optimistic locking, there is no way this Lost Update would have been caught even if the database transactions used Serializable. This is because reads and writes are executed in separate HTTP requests, hence on different database transactions.

So, optimistic locking can help you prevent Lost Updates even when using application-level transactions that incorporate the user-think time as well.

Conclusion

Optimistic locking is a very useful technique, and it works just fine even when using less-strict isolation levels, like Read Committed, or when reads and writes are executed in subsequent database transactions.

The downside of optimistic locking is that a rollback will be triggered by the data access framework upon catching an OptimisticLockException, therefore losing all the work we've done previously by the currently executing transaction.

The more contention, the more conflicts, and the greater the chance of aborting transactions. Rollbacks can be costly for the database system as it needs to revert all current pending changes which might involve both table rows and index records.

For this reason, pessimistic locking might be more suitable when conflicts happen frequently, as it reduces the chance of rolling back transactions.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • 3
    For what scenarios would you suggest to choose OptimisticLocking and PessimisticLocking? Does it depend on how often a OptimisticLockException occurs? – Stimpson Cat Jun 03 '20 at 10:34
  • 3
    @StimpsonCat from what I read from his conclusion, yes, if u get exception often then it is better to go pessimistic locking. Like in my case, the chance of exception occur is very small so i will go for Optimistic locking. – Dave Cruise Oct 15 '20 at 11:58
  • Once Bob withdraws an amount, DB record is changed. Hence, ideally it should reflect for Alice. That means, when Alice queries for amount it should be updated amount not from persistence context. Am I missing anything here ? Thanks. – Omkar Shetkar May 27 '21 at 13:01
  • 2
    Upvoted. Although the material isn't novel, well-explained answers are becoming a rarity in SO as more and more one-off homework questions flood the system. – Abhijit Sarkar Sep 25 '21 at 01:46
  • I paused your youtube video to search for sth online, bumped into your answer.. I know this is against the comment guidelines but nevertheless very helpful contribution! – EralpB Dec 23 '21 at 08:39
  • 3
    @EralpB Google, StackOverflow, YoutTube, GitHub, Twitter, LinkedIn, you'll find me everywhere – Vlad Mihalcea Dec 23 '21 at 10:36
258

Optimistic locking is used when you don't expect many collisions. It costs less to do a normal operation but if the collision DOES occur you would pay a higher price to resolve it as the transaction is aborted.

Pessimistic locking is used when a collision is anticipated. The transactions which would violate synchronization are simply blocked.

To select proper locking mechanism you have to estimate the amount of reads and writes and plan accordingly.

Hearen
  • 7,420
  • 4
  • 53
  • 63
Ilya Kochetov
  • 17,988
  • 6
  • 44
  • 60
  • In normal case, the statement is perfect but in special cases where you could manage the **CAS** operation allowing inaccuracy as @skaffman mentioned in the answer, I would say that really depends. – Hearen May 05 '19 at 11:33
105

Optimistic assumes that nothing's going to change while you're reading it.

Pessimistic assumes that something will and so locks it.

If it's not essential that the data is perfectly read use optimistic. You might get the odd 'dirty' read - but it's far less likely to result in deadlocks and the like.

Most web applications are fine with dirty reads - on the rare occasion the data doesn't exactly tally the next reload does.

For exact data operations (like in many financial transactions) use pessimistic. It's essential that the data is accurately read, with no un-shown changes - the extra locking overhead is worth it.

Oh, and Microsoft SQL server defaults to page locking - basically the row you're reading and a few either side. Row locking is more accurate but much slower. It's often worth setting your transactions to read-committed or no-lock to avoid deadlocks while reading.

Keith
  • 150,284
  • 78
  • 298
  • 434
  • JPA Optimistic Locking allows you to guarantee read-consistency. – Gili Sep 24 '08 at 19:43
  • 5
    Read-consistency is a separate concern - with PostgreSQL, Oracle and many other databases, you get a consistent view of data regardless of any updates not yet committed, and aren't affected even by exclusive row locks. – RichVel Aug 01 '14 at 13:52
  • 1
    I have to agree with @RichVel. On the one hand, I can see how pessimistic locking could prevent dirty reads if your transaction isolation level is READ UNCOMMITTED. But it is misleading to say that optimistic locking is susceptible to dirty reads without mentioning out that most databases (including apparently MS SQL Server) have a default isolation level of "READ COMMITTED", which prevents dirty reads and makes optimistic locking just as accurate as pessimistic. – antinome Oct 07 '14 at 20:17
  • Eric Brower says that bankers, unlike others, prefer dirty operations. Your gurus seem absolutely out of trolleys. – Little Alien Dec 05 '16 at 15:18
  • @LittleAlien who's 'Eric Brower'? Are you citing him and if so please provide links. – Keith Dec 05 '16 at 16:10
  • 2
    Eric Brewer is the guru who gave the the CAP theorem [says about consistency in banking](http://highscalability.com/blog/2013/5/1/myth-eric-brewer-on-why-banks-are-base-not-acid-availability.html). It is opposite to what you honor it for. – Little Alien Dec 05 '16 at 22:05
  • @LittleAlien fascinating, cheers. That's ATMs though - small individual transactions that cost the bank little against lost business when the ATM is down. My experience is in payroll - huge transactions that cost millions. In the latter you definitely go down ACID route. Banks obviously use the pattern that works in the context - it's a balance of reliability and availability. – Keith Dec 05 '16 at 23:23
29

I would think of one more case when pessimistic locking would be a better choice.

For optimistic locking every participant in data modification must agree in using this kind of locking. But if someone modifies the data without taking care about the version column, this will spoil the whole idea of the optimistic locking.

Nikolay
  • 1,111
  • 2
  • 12
  • 16
  • 1
    People attempting to use optimistic and pessimistic locking can also step on each others' feet, so to speak. Imagine a scenario where an optimistic session reads a record and is doing some calculations while a pessimistic session updates the record, then the optimistic session comes back and updates that same record without noting any changes made. Select ... for update only works if every session is using that same syntax. – lusional Aug 04 '16 at 22:09
25

There are basically two most popular answers. The first one basically says

Optimistic needs a three-tier architectures where you do not necessarily maintain a connection to the database for your session whereas Pessimistic Locking is when you lock the record for your exclusive use until you have finished with it. It has much better integrity than optimistic locking you need either a direct connection to the database.

Another answer is

optimistic (versioning) is faster because of no locking but (pessimistic) locking performs better when contention is high and it is better to prevent the work rather than discard it and start over.

or

Optimistic locking works best when you have rare collisions

As it is put on this page.

I created my answer to explain how "keep connection" is related to "low collisions".

To understand which strategy is best for you, think not about the Transactions Per Second your DB has but the duration of a single transaction. Normally, you open trasnaction, performa operation and close the transaction. This is a short, classical transaction ANSI had in mind and fine to get away with locking. But, how do you implement a ticket reservation system where many clients reserve the same rooms/seats at the same time?

You browse the offers, fill in the form with lots of available options and current prices. It takes a lot of time and options can become obsolete, all the prices invalid between you started to fill the form and press "I agree" button because there was no lock on the data you have accessed and somebody else, more agile, has intefered changing all the prices and you need to restart with new prices.

You could lock all the options as you read them, instead. This is pessimistic scenario. You see why it sucks. Your system can be brought down by a single clown who simply starts a reservation and goes smoking. Nobody can reserve anything before he finishes. Your cash flow drops to zero. That is why, optimistic reservations are used in reality. Those who dawdle too long have to restart their reservation at higher prices.

In this optimistic approach you have to record all the data that you read (as in mine Repeated Read) and come to the commit point with your version of data (I want to buy shares at the price you displayed in this quote, not current price). At this point, ANSI transaction is created, which locks the DB, checks if nothing is changed and commits/aborts your operation. IMO, this is effective emulation of MVCC, which is also associated with Optimistic CC and also assumes that your transaction restarts in case of abort, that is you will make a new reservation. A transaction here involves a human user decisions.

I am far from understanding how to implement the MVCC manually but I think that long-running transactions with option of restart is the key to understanding the subject. Correct me if I am wrong anywhere. My answer was motivated by this Alex Kuznecov chapter.

Community
  • 1
  • 1
Little Alien
  • 1
  • 8
  • 22
17

In most cases, optimistic locking is more efficient and offers higher performance. When choosing between pessimistic and optimistic locking, consider the following:

  • Pessimistic locking is useful if there are a lot of updates and relatively high chances of users trying to update data at the same time. For example, if each operation can update a large number of records at a time (the bank might add interest earnings to every account at the end of each month), and two applications are running such operations at the same time, they will have conflicts.

  • Pessimistic locking is also more appropriate in applications that contain small tables that are frequently updated. In the case of these so-called hotspots, conflicts are so probable that optimistic locking wastes effort in rolling back conflicting transactions.

  • Optimistic locking is useful if the possibility for conflicts is very low – there are many records but relatively few users, or very few updates and mostly read-type operations.

Koenigsegg
  • 575
  • 1
  • 9
  • 23
8

One use case for optimistic locking is to have your application use the database to allow one of your threads / hosts to 'claim' a task. This is a technique that has come in handy for me on a regular basis.

The best example I can think of is for a task queue implemented using a database, with multiple threads claiming tasks concurrently. If a task has status 'Available', 'Claimed', 'Completed', a db query can say something like "Set status='Claimed' where status='Available'. If multiple threads try to change the status in this way, all but the first thread will fail because of dirty data.

Note that this is a use case involving only optimistic locking. So as an alternative to saying "Optimistic locking is used when you don't expect many collisions", it can also be used where you expect collisions but want exactly one transaction to succeed.

Charlie Camp
  • 136
  • 1
  • 2
8

Let's say in an ecommerce app, a user wants to place an order. This code will get executed by multiple threads. In pessimistic locking, when we get the data from the DB, we lock it so no other thread can modify it. We process the data, update the data, and then commit the data. After that, we release the lock. Locking duration is long here, we have locked the database record from the beginning till committing.

In optimistic locking, we get the data and process the data without locking. So multiple threads can execute the code so far concurrently. This will speed up. While we update, we lock the data. We have to verify that no other thread updated that record. For example, If we had 100 items in inventory and we have to update it to 99 (because your code might be quantity=queantity-1) but if another thread already used 1 it should be 98. We had race condition here. In this case, we restart the thread so we execute the same code from the beginning. But this is an expensive operation, you already came to end but then restart. if we had a few race conditions, that would not be a big deal, If the race condition was high, there would be a lot of threads to restart. We might run in a loop. In the race condition is high, we should be using `pessimistic locking

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
7

Lot of good things have been said above about optimistic and pessimistic locking. One important point to consider is as follows:

When using optimistic locking, we need to cautious of the fact that how will application recover from these failures.

Specially in asynchronous message driven architectures, this can lead of out of order message processing or lost updates.

Failures scenarios need to be thought through.

Abhishek Shinde
  • 101
  • 1
  • 3
5

Optimistic locking means exclusive lock is not used when reading a row so lost update or write skew is not prevented. So, use optimistic locking:

  • If lost update or write skew doesn't occur.
  • Or, if there are no problems even if lost update or write skew occurs.

Pessimistic locking means exclusive lock is used when reading a row so lost update or write skew is prevented. So, use pessimistic locking:

  • If lost update or write skew occurs.
  • Or if there are some problems if lost update or write skew occurs.

In MySQL and PostgreSQL, you can use exclusive lock with SELECT FOR UPDATE.

You can check my answer of the lost update and write skew examples with optimistic locking(without SELECT FOR UPDATE) and pessimistic locking(with SELECT FOR UPDATE) in MySQL.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
3

On a more practical note, when updating a distributed system, optimistic locking in the DB may be inadequate to provide the consistency needed across all parts of the distributed system.

For example, in applications built on AWS, it is common to have data in both a DB (e.g. DynamoDB) and a storage (e.g. S3). If an update touches both DynamoDB and S3, an optimistic locking in DynamoDB could still leave the data in S3 inconsistent. In this type of cases, it is probably safer to use a pessimistic lock that is held in DynamoDB until the S3 update is finished. In fact, AWS provides a locking library for this purpose.

Big Pumpkin
  • 3,907
  • 1
  • 27
  • 18
  • 1
    FWIW, AWS DynamoDB also supports optimistic locking. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html – Big Pumpkin Aug 22 '21 at 22:55
1

Optimistic locking and Pessimistic locking are two models for locking data in a database.

Optimistic locking : where a record is locked only when changes are committed to the database.

Pessimistic locking : where a record is locked while it is edited.

Note : In both data-locking models, the lock is released after the changes are committed to the database.

Amit kumar
  • 2,169
  • 10
  • 25
  • 36