diff --git a/registrasion/controllers/batch.py b/registrasion/controllers/batch.py
index 2e5e0241..00001a86 100644
--- a/registrasion/controllers/batch.py
+++ b/registrasion/controllers/batch.py
@@ -19,14 +19,37 @@ class BatchController(object):
     '''
 
     _user_caches = {}
+    _NESTING_KEY = "nesting_count"
 
     @classmethod
     @contextlib.contextmanager
     def batch(cls, user):
         ''' Marks the entry point for a batch for the given user. '''
-        pass
-        # TODO: store nesting count *inside* the cache object. You know it
-        # makes sense.
+
+        cls._enter_batch_context(user)
+        try:
+            yield
+        finally:
+            # Make sure we clean up in case of errors.
+            cls._exit_batch_context(user)
+
+    @classmethod
+    def _enter_batch_context(cls, user):
+        if user not in cls._user_caches:
+            cls._user_caches[user] = cls._new_cache()
+
+        cache = cls._user_caches[user]
+        cache[cls._NESTING_KEY] += 1
+
+    @classmethod
+    def _exit_batch_context(cls, user):
+        cache = cls._user_caches[user]
+        cache[cls._NESTING_KEY] -= 1
+
+        if cache[cls._NESTING_KEY] == 0:
+            # TODO: Handle batch end cases
+
+            del cls._user_caches[user]
 
     @classmethod
     def memoise(cls, func):
@@ -57,10 +80,17 @@ class BatchController(object):
     @classmethod
     def get_cache(cls, user):
         if user not in cls._user_caches:
-            return {}  # Return blank cache here, we'll just discard :)
+            # Return blank cache here, we'll just discard :)
+            return cls._new_cache()
 
         return cls._user_caches[user]
 
+    @classmethod
+    def _new_cache(cls):
+        ''' Returns a new cache dictionary. '''
+        cache = {}
+        cache[cls._NESTING_KEY] = 0
+        return cache
 
 '''
 TODO: memoise CartController.for_user
@@ -70,13 +100,6 @@ TODO: memoise FlagCounter.count() (doesn't take user, but it'll do for now)
 TODO: memoise _filtered_discounts
 
 Tests:
-- Correct nesting behaviour
- - do we get different cache objects every time we get a cache in non-batched
-   contexts?
- - do we get the same cache object for nested caches?
-  - do we get different cache objects when we back out of a batch and enter a
-   new one
-- are cache clears independent for different users?
 - ``end_batch`` behaviour for CartController (use for_user *A LOT*)
   - discounts not calculated until outermost batch point exits.
   - Revision number shouldn't change until outermost batch point exits.