Browse Source

Prevent dead locks by locking all rows at once

Lari Hotari 11 years ago
parent
commit
976cccfbb3
1 changed files with 19 additions and 5 deletions
  1. 19 5
      grails/hello/grails-app/controllers/hello/HelloController.groovy

+ 19 - 5
grails/hello/grails-app/controllers/hello/HelloController.groovy

@@ -3,6 +3,8 @@ package hello
 import grails.converters.JSON
 import grails.converters.JSON
 import grails.transaction.Transactional
 import grails.transaction.Transactional
 import groovy.transform.CompileStatic
 import groovy.transform.CompileStatic
+import groovy.transform.TypeCheckingMode;
+
 import java.util.concurrent.ThreadLocalRandom
 import java.util.concurrent.ThreadLocalRandom
 
 
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Isolation;
@@ -43,20 +45,32 @@ class HelloController {
     private List<World> fetchRandomWorlds(int queries, boolean updateAlso) {
     private List<World> fetchRandomWorlds(int queries, boolean updateAlso) {
         if(queries < 1) queries=1
         if(queries < 1) queries=1
         if(queries > 500) queries=500
         if(queries > 500) queries=500
-        List<World> worlds = new ArrayList<World>(queries)
         def random = ThreadLocalRandom.current()
         def random = ThreadLocalRandom.current()
 
 
+        List<Integer> worldIds = new ArrayList<Integer>(queries)
         for (int i = 0; i < queries; i++) {
         for (int i = 0; i < queries; i++) {
-            int randomId = random.nextInt(10000) + 1
-            def world = updateAlso ? World.lock(randomId) : World.read(randomId)
-            if(updateAlso) {
+            worldIds.add(random.nextInt(10000) + 1)
+        }
+        List<World> worlds
+        if (updateAlso) {
+            worlds = getAllLocked(worldIds as Serializable[])
+            for (World world : worlds) {
                 world.randomNumber = random.nextInt(10000) + 1
                 world.randomNumber = random.nextInt(10000) + 1
             }
             }
-            worlds.add(world)
+        } else {
+            worlds = World.getAll(worldIds as Serializable[])
         }
         }
         return worlds
         return worlds
     }
     }
     
     
+    @CompileStatic(TypeCheckingMode.SKIP)
+    private List<World> getAllLocked(Serializable[] worldIds) {
+        World.withCriteria {
+            'in'('id', worldIds as Serializable[])
+            lock true
+        }
+    }
+    
     // Test type 4: Fortunes
     // Test type 4: Fortunes
     @Transactional(readOnly=true)
     @Transactional(readOnly=true)
     def fortunes() {
     def fortunes() {