Aditya Chandla
Aditya Chandla

Reputation: 77

Unique Constraint error thrown at the end of @Transactional block

Suppose I have a user class:

@Entity
@Data
@Builder
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long userKey;

    @Column(unique = true)
    String someId;

    String name;
}

And it's corresponding service

@Component
@Slf4j
public class UserService {

    @Autowired
    UserRepository repository;

    @Transactional
    public User createUserWithId(String name, String id) {
        User userToAdd = User.builder()
                .name(name)
                .someId(id)
                .build();
        repository.save(userToAdd);
        log.info("No issue in saving");
        //some more code
        return userToAdd;
    }

}

As you can see that I have a unique constraint on someId field in User class but when I execute the method createUserWithId with a value in someId which is already present in DB, I'd expect to get an error on the line containing repository.save() and the code after it to not be executed. But the code after it is getting executed and I'm getting an exception at the end of the transactional block. My question is why this is happening and what are the exceptions which I would generally get when interacting with the repository object ( like in this case repository.save ) and which type of exceptions will I get at the end of transactional block ?

PS I am calling the UserService from inside a simple controller and I have created an empty UserRepository which just extends CrudRepository. Both of which I have left out from the question for brevity but let me know if adding them here would make sense.

EDIT 1: Adding user repository as per request in comments

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}

Upvotes: 0

Views: 4387

Answers (3)

rhl mngl
rhl mngl

Reputation: 63

When we call

repository.save(obj); 

hibernate kept this entity in memory, the Entity will persist at the of the method in the Transaction.

One more way to do such kind of operation, first you should try to fetch result on id

repository.findById(id)

And check whether it is null or not and accordingly perform save operation.

Upvotes: 0

Christian Beikov
Christian Beikov

Reputation: 16452

The error happens in the interceptor because right before committing the transaction, Hibernate needs to flush pending changes to the database. During that flush, the database exception happens. You can flush manually by calling saveAndFlush on the repository.

Upvotes: 2

Ali.Mojtahed
Ali.Mojtahed

Reputation: 2587

Uniqe error happens when duplicate . spring has database error helper class that you can catch db exceptions on controller layer passed by @transactional to controller.

  } catch (DataAccessException ex) {

or

 } catch (DataIntegrityViolationException ex) {

in case the database connector has standard exception throw support.

in your case I think you missed

@Transactional(readOnly = false)

Upvotes: 0

Related Questions