Concurrent deletes don't collide and lock the database (#9479).
(self)
| 56 | self.addCleanup(self.conn2.rollback) |
| 57 | |
| 58 | def test_concurrent_delete(self): |
| 59 | """Concurrent deletes don't collide and lock the database (#9479).""" |
| 60 | with transaction.atomic(): |
| 61 | Book.objects.create(pagecount=100) |
| 62 | book = Book.objects.create(pagecount=200) |
| 63 | Book.objects.create(pagecount=300) |
| 64 | |
| 65 | with transaction.atomic(): |
| 66 | # Start a transaction on the main connection. |
| 67 | self.assertEqual(3, Book.objects.count()) |
| 68 | |
| 69 | # Delete something using another database connection. |
| 70 | with self.conn2.cursor() as cursor2: |
| 71 | cursor2.execute( |
| 72 | "DELETE from delete_regress_book WHERE id = %s", [book.pk] |
| 73 | ) |
| 74 | self.conn2.commit() |
| 75 | |
| 76 | # In the same transaction on the main connection, perform a |
| 77 | # queryset delete that covers the object deleted with the other |
| 78 | # connection. This causes an infinite loop under MySQL InnoDB |
| 79 | # unless we keep track of already deleted objects. |
| 80 | Book.objects.filter(pagecount__lt=250).delete() |
| 81 | |
| 82 | self.assertEqual(1, Book.objects.count()) |
| 83 | |
| 84 | |
| 85 | class DeleteCascadeTests(TestCase): |