Search code examples
javaspringspring-boothibernatejpa

Jpa is not flushing Transactional changes


I use two-step registration. In the first step, I only require a username, password, and email. In the second step, I require a full name, bio, gender, etc. I have a registerDetails method for that. Inside registerDetails, there is updateAppUser method that updates the user with given information(full name, bio, gender, etc. ). The registerDetails method is transactional because in the first step, I call for updateAppUser and in the second step I call for the setDetailsRegistered method. The setDetailsRegistered method only sets isDetailsRegistered boolean to true. I do that because I require the user to fill remaining information(full name, bio, gender, etc. ). Anyway, my problem is that when I return AppUserResponse after those two processes, I still get isDetailsRegistered as false, however, I used setDetailsRegistered method to set it as true. I understand that, because my method is transactional, it is still false when I call for the AppUser object because the transaction is not completed, yet. I want to close the transaction and after that retrieve the AppUser object from the database. I think I will get isDetailsRegistered as true. How can I achieve that? Those are my methods.

registerDetails

  @Transactional
    public AppUserResponse registerDetails(RegisterRequest registerRequest, UUID appUserId) {
        //fixme:first registerDetails returned false
        AppUser appUser = userDetailsService.findAppUserById(appUserId);

        if (appUser.isDetailsRegistered()) {
            throw new InvalidRequestException("Bu kullanıcının bilgileri zaten kayıtlı.");
        }

        AppUser mapped = appUserMapper.registerDetailsToAppUser(appUser,registerRequest);
        updateAppUser(mapped);
        setDetailsRegistered(appUserId);
        
        appUserRepository.flush(); //after updating and setting isdetailsRegistered flag as true, then flush changes.
        
        AppUser newAppUser = userDetailsService.findAppUserById(appUserId);
        return appUserMapper.appUserToResponse(newAppUser);
    } 

updateAppUser

    public AppUser updateAppUser(AppUser appUser) {
        return appUserRepository.save(appUser);
    }

setDetailsRegistered

    public void setDetailsRegistered(UUID userId) {
        appUserRepository.setDetailsRegistered(userId);
        appUserRepository.flush();
    }

jpa query for setDetailsRegistered

    @Modifying
    @Transactional
    @Query("UPDATE AppUser a " +
            "SET a.isDetailsRegistered = TRUE WHERE a.appUserId = ?1")
    void setDetailsRegistered(UUID userId);

Solution

  • Try next code:

    @Transactional
    public AppUserResponse registerDetails(RegisterRequest registerRequest, UUID appUserId) {
        AppUser appUser = userDetailsService.findAppUserById(appUserId);
    
        if (appUser.isDetailsRegistered()) {
            throw new InvalidRequestException("Bu kullanıcının bilgileri zaten kayıtlı.");
        }
        appUser = appUserMapper.registerDetailsToAppUser(appUser,registerRequest);
        appUser = appUserRepository.save(appUser);
        //setDetailsRegistered(appUserId);
        appUser.setDetailsRegistered(true);//if you don't have this setter you can create it in the class AppUser
        appUser = appUserRepository.save(appUser);
        return appUserMapper.appUserToResponse(appUser);
    }