title: Why does @Transactional isolation level have no effect when updating entities with Spring Data JPA?
body: <p>For this experimental project based on the <code>spring-boot-starter-data-jpa</code> dependency and <code>H2</code> in-memory database, I defined a <code>User</code> entity with two fields (<code>id</code> and <code>firstName</code>) and declared a <code>UsersRepository</code> by extending the <code>CrudRepository</code> interface.</p>
  <p>Now, consider a simple controller which provides two endpoints: <code>/print-user</code> reads the same user twice with some interval printing out its first name, and <code>/update-user</code> is used to change the user's first name in between those two reads. Notice that I deliberately set <code>Isolation.READ_COMMITTED</code> level and expected that during the course of the first transaction, a user which is retrieved twice by the same id will have different names. But instead, the first transaction prints out the same value twice. To make it more clear, this is the complete sequence of actions:</p>
  <ol>
  <li>Initially, <code>jeremy</code>'s first name is set to <code>Jeremy</code>.</li>
  <li>Then I call <code>/print-user</code> which prints out <code>Jeremy</code> and goes to sleep.</li>
  <li>Next, I call <code>/update-user</code> from another session and it changes <code>jeremy</code>'s first name to <code>Bob</code>.</li>
  <li>Finally, when the first transaction gets awakened after sleep and re-reads the <code>jeremy</code> user, it prints out <code>Jeremy</code> again as his first name even though the first name has already been changed to <code>Bob</code> (and if we open the database console, it's now indeed stored as <code>Bob</code>, not <code>Jeremy</code>).</li>
  </ol>
  <p>It seems like setting isolation level has no effect here and I'm curious why this is so.</p>
  <pre class="lang-java prettyprint-override"><code>@RestController
  @RequestMapping
  public class UsersController {
  
      private final UsersRepository usersRepository;
  
      @Autowired
      public UsersController(UsersRepository usersRepository) {
          this.usersRepository = usersRepository;
      }
  
      @GetMapping(&quot;/print-user&quot;)
      @ResponseStatus(HttpStatus.OK)
      @Transactional (isolation = Isolation.READ_COMMITTED)
      public void printName() throws InterruptedException {
          User user1 = usersRepository.findById(&quot;jeremy&quot;); 
          System.out.println(user1.getFirstName());
          
          // allow changing user's name from another 
          // session by calling /update-user endpoint
          Thread.sleep(5000);
          
          User user2 = usersRepository.findById(&quot;jeremy&quot;);
          System.out.println(user2.getFirstName());
      }
  
  
      @GetMapping(&quot;/update-user&quot;)
      @ResponseStatus(HttpStatus.OK)
      @Transactional(isolation = Isolation.READ_COMMITTED)
      public User changeName() {
          User user = usersRepository.findById(&quot;jeremy&quot;); 
          user.setFirstName(&quot;Bob&quot;);
          return user;
      }
      
  }
  </code></pre>