title: Identify constraint name that trigger DataIntegrityViolationException
body: <p>I am stuck with a issue of identify which constraint triggers DataIntegrityViolationException. I have two unique constraints: username and email but I have no luck trying to figure it out.</p>
  
  <p>I have tried to get the root cause exception but I got this message </p>
  
  <p><code>Unique index or primary key violation: "UK_6DOTKOTT2KJSP8VW4D0M25FB7_INDEX_4 ON PUBLIC.USERS(EMAIL) VALUES ('copeland@yahoo.com', 21)"; SQL statement:
  insert into users (id, created_at, updated_at, country, email, last_name, name, password, phone, sex, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [23505-193]</code></p>
  
  <p>Reading the error I know email constraint triggers the validation but I want to return to the user something like:
  <code>{type: ERROR, message: "The email already exist"}</code></p>
  
  <p>I have read in other post and people handle it looking for a constraint name into the exception(eg, <code>users_unique_username_idx</code>) and display a proper message to the user. But I couldn't get that type of constraint name</p>
  
  <p>Maybe I am missing a configuration. I am using:</p>
  
  <p><code>Spring Boot 1.5.1.RELEASE, JPA, Hibernate and H2</code></p>
  
  <p>My <strong>application.properties</strong></p>
  
  <p><code>spring.jpa.generate-ddl=true</code></p>
  
  <p><strong>User.class</strong>:</p>
  
  <pre><code>@Entity(name = "users")
  public class User extends BaseEntity {
      private static final Logger LOGGER = LoggerFactory.getLogger(User.class);
  
      public enum Sex { MALE, FEMALE }
  
      @Id
      @GeneratedValue
      private Long id;
  
      @Column(name = "name", length = 100)
      @NotNull(message = "error.name.notnull")
      private String name;
  
      @Column(name = "lastName", length = 100)
      @NotNull(message = "error.lastName.notnull")
      private String lastName;
  
      @Column(name = "email", unique = true, length = 100)
      @NotNull(message = "error.email.notnull")
      private String email;
  
      @Column(name = "username", unique = true, length = 100)
      @NotNull(message = "error.username.notnull")
      private String username;
  
      @Column(name = "password", length = 100)
      @NotNull(message = "error.password.notnull")
      @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
      private String password;
  
      @Enumerated(EnumType.STRING)
      private Sex sex;
  
      @Column(name = "phone", length = 50)
      private String phone;
  
      @Column(name = "country", length = 100)
      @NotNull(message = "error.country.notnull")
      private String country;
  
      public User() {}
  
      // Getters and setters
  
  }
  </code></pre>
  
  <p><strong>ControllerValidationHandler.class</strong></p>
  
  <pre><code>@ControllerAdvice
  public class ControllerValidationHandler {
      private final Logger LOGGER = LoggerFactory.getLogger(ControllerValidationHandler.class);
  
      @Autowired
      private MessageSource msgSource;
  
      private static Map&lt;String, String&gt; constraintCodeMap = new HashMap&lt;String, String&gt;() {
          {
              put("users_unique_username_idx", "exception.users.duplicate_username");
              put("users_unique_email_idx", "exception.users.duplicate_email");
          }
      };
  
      // This solution I see in another stackoverflow answer but not work
      // for me. This is the closest solution to solve my problem that I found
      @ResponseStatus(value = HttpStatus.CONFLICT)  // 409
      @ExceptionHandler(DataIntegrityViolationException.class)
      @ResponseBody
      public ErrorInfo conflict(HttpServletRequest req, DataIntegrityViolationException e) {
          String rootMsg = ValidationUtil.getRootCause(e).getMessage();
          LOGGER.info("rootMessage" + rootMsg);
          if (rootMsg != null) {
              Optional&lt;Map.Entry&lt;String, String&gt;&gt; entry = constraintCodeMap.entrySet().stream()
                      .filter((it) -&gt; rootMsg.contains(it.getKey()))
                      .findAny();
              LOGGER.info("Has entries: " + entry.isPresent()); // false
              if (entry.isPresent()) {
                  LOGGER.info("Value: " + entry.get().getValue());
                  e=new DataIntegrityViolationException(
                          msgSource.getMessage(entry.get().getValue(), null, LocaleContextHolder.getLocale()));
              }
          }
          return new ErrorInfo(req, e);
      }
  </code></pre>
  
  <p>The response at this moment is:</p>
  
  <p><code>{"timestamp":1488063801557,"status":500,"error":"Internal Server Error","exception":"org.springframework.dao.DataIntegrityViolationException","message":"could not execute statement; SQL [n/a]; constraint [\"UK_6DOTKOTT2KJSP8VW4D0M25FB7_INDEX_4 ON PUBLIC.USERS(EMAIL) VALUES ('copeland@yahoo.com', 21)\"; SQL statement:\ninsert into users (id, created_at, updated_at, country, email, last_name, name, password, phone, sex, username) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [23505-193]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement","path":"/users"}</code></p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>This is my service layer that handle my persistence operations</p>
  
  <p><strong>MysqlService.class</strong></p>
  
  <pre><code>@Service
  @Qualifier("mysql")
  class MysqlUserService implements UserService {
      private UserRepository userRepository;
  
      @Autowired
      public MysqlUserService(UserRepository userRepository) {
          this.userRepository = userRepository;
      }
  
      @Override
      public List&lt;User&gt; findAll() {
          return userRepository.findAll();
      }
  
      @Override
      public Page&lt;User&gt; findAll(Pageable pageable) {
          return userRepository.findAll(pageable);
      }
  
      @Override
      public User findOne(Long id) {
          return userRepository.findOne(id);
      }
  
      @Override
      public User store(User user) {
          return userRepository.save(user);
      }
  
      @Override
      public User update(User usr) {
          User user = this.validateUser(usr);
  
          return userRepository.save(user);
      }
  
      @Override
      public void destroy(Long id) {
          this.validateUser(id);
  
          userRepository.delete(id);
      }
  
      private User validateUser(User usr) {
          return validateUser(usr.getId());
      }
  
      /**
       * Validate that an user exists
       *
       * @param id of the user
       * @return an existing User
       */
      private User validateUser(Long id) {
          User user = userRepository.findOne(id);
          if (user == null) {
              throw new UserNotFoundException();
          }
          return user;
      }
  }
  </code></pre>
  
  <p><strong>Update #2</strong></p>
  
  <p>Repo to reproduce the issue <a href="https://github.com/LTroya/boot-users" rel="nofollow noreferrer">https://github.com/LTroya/boot-users</a>. I commented my handler on <code>ValidationExceptionHandler.class</code> in order to see the exception. </p>
  
  <p>Send twice json at <strong>Json to test</strong> on Readme.md to <code>POST /users/</code></p>