title: Spring @Transactional: Should't the second thread wait until the first thread commit/rollback?
body: <p>The issue here is that both threads are executing the first <code>SELECT</code> at the same time. Considering that <code>saveUser</code> is a <code>@Transactional</code> method, should't the second thread wait until the first thread commit/rollback?</p>
  
  <p><em>Code:</em></p>
  
  <pre><code>@SpringBootApplication
  public class TestApp
  {
      public static void main(String[] args)
      {
          ConfigurableApplicationContext app = SpringApplication.run(TestApp.class, args);
          UserService us = (UserService) app.getBean("userService");
  
          Thread t1 = new Thread(() -&gt; us.saveUser("email@email.com"));
          t1.setName("Thread #1");
          t1.start();
  
          Thread t2 = new Thread(() -&gt; us.saveUser("email@email.com"));
          t2.setName("Thread #2");
          t2.start();
      }
  }
  
  @Repository
  public interface UserRepository extends CrudRepository&lt;UserService.User, Long&gt;
  {
      public UserService.User getByEmail(String email);
  }
  
  @AllArgsConstructor
  @Service
  public class UserService
  {
      private final UserRepository userRepository;
  
      @Transactional
      public boolean saveUser(String email)
      {
          if (userRepository.getByEmail(email) != null)
          {
              System.out.println("User already exists");
              return false;
          }
  
          System.out.println(Thread.currentThread().getName() + ": User doesn't exists, sleeping..");
  
          try
          {
              Thread.sleep(5000);
          }
          catch (InterruptedException e)
          {
              e.printStackTrace();
          }
  
          User user = new User();
          user.email = email;
  
          System.out.println(Thread.currentThread().getName() + ": Saving user..");
          user = userRepository.save(user);
  
          return user.id &gt; 0;
      }
  
      @Table("user")
      public static class User
      {
          @Id
          public long id;
          public String email;
      }
  }
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>Thread #1: User doesn't exists, sleeping..
  Thread #2: User doesn't exists, sleeping..
  Thread #1: Saving user..
  Thread #2: Saving user..
  Exception in thread "Thread #2" org.springframework.data.relational.core.conversion.DbActionExecutionException: Failed to execute DbAction.InsertRoot(entity=testapp.UserService$User@3ce548a)
  [...]
  Caused by: org.springframework.dao.DuplicateKeyException: PreparedStatementCallback;
  [...]
  </code></pre>
  
  <p><em>Table:</em></p>
  
  <pre><code>create table user (`id` int primary key auto_increment, `email` varchar(50) unique);
  </code></pre>