Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot catch DataIntegrityViolationException

I am using Spring Boot 2 with spring-boot-starter-data-jpa with an underlying MariaDB.

I have table with a unique key "username". I want to catch DataIntegrityViolationException if this constraint is violated, but it seems like Spring is logging DataIntegrityViolationException and does not rethrow the after logging(my best guess). MySQLIntegrityConstraintViolationException is thrown instead.

I would like to catch DataIntegrityViolationException in UserService.createUser(..).

Here are a couple of code snippets:

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public class UserRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public void save(User user) {
        entityManager.persist(user);
    }
}

@Service
@Transactional(value = Transactional.TxType.REQUIRED)
public class UserService {

@Autowired
private UserRepository userRepository;

private void createUser(User user){
    userRepository.save(user);
}

Stacktrace:

2018-09-22 14:20:33.163  WARN 10700 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1062, SQLState: 23000
2018-09-22 14:20:33.163 ERROR 10700 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : Duplicate entry 'kkflf' for key 'user_username_uindex'
2018-09-22 14:20:33.163 ERROR 10700 --- [nio-8080-exec-1] o.h.i.ExceptionMapperStandardImpl        : HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
2018-09-22 14:20:33.177 ERROR 10700 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [user_username_uindex]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'kkflf' for key 'user_username_uindex'
...
like image 619
kkflf Avatar asked Mar 21 '26 14:03

kkflf


2 Answers

I solved the problem.

The exception does not occur until the transaction commits, which makes perfect sense.

I was able to catch the exception outside the transaction scope in a controller class.

like image 171
kkflf Avatar answered Mar 23 '26 06:03

kkflf


As kkflf said, the exception won't normally throw until the txn commits. If you need it to throw, you can call flush() right after the line.

However, I have learned the hard way not to rely on that as conditional logic for anything. For example, I wanted to attempt a delete and if that didn't work, do something else. But if there's any further database activity that would involve that object (even by reference), the system (spring/hibernate/whathaveyou) will not like the state is in.

The correct flow is to check the condition yourself in code before you attempt the operation. In other words, don't use the database as an IF statement :-)

// Just say 'no' to this:
if (DB doesn't like it) {
    // do this
} else {
   // do that
}
like image 27
Jeff Avatar answered Mar 23 '26 05:03

Jeff