Cannot catch DataIntegrityViolationException

青春壹個敷衍的年華 提交于 2021-02-11 06:49:28

问题


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'
...

回答1:


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.




回答2:


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
}


来源:https://stackoverflow.com/questions/52456783/cannot-catch-dataintegrityviolationexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!