Откат первичного ключа Spring Data Jpa не работает

Я работаю над примером Spring Boot (2.1.7.RELEASE) + Spring Data JPA + postgres и хочу откатить идентификатор первичного ключа в случае возникновения какого-либо исключения. Я прошел через https://www.logicbig.com/tutorials/spring-framework/spring-data-access-with-jdbc/transactional-roll-back.html и Как откатить транзакцию в JPA? и много других полезных ссылок, но у меня ничего не получилось.

В моем проекте я всегда стараюсь хранить уникальную комбинацию firstName и LastName.

Студент.java

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="STUDENT", uniqueConstraints = {
        @UniqueConstraint(name="STU_KEY",columnNames = {"FIRSTNAME", "LASTNAME"})
})
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="STUDENT_ID")
    private Long studentId;

    @Column(name="FIRSTNAME")
    private String firstName;

    @Column(name="LASTNAME")
    private String lastName;

    @Column(name="EMAIL")
    private String email;
}

Я разработал конечную точку REST

StudentController.java

@RestController
public class StudentController {

    @Autowired
    private StudentService studentService;

    @ApiOperation(value = "Save Student", nickname = "Save Student")
    @ApiResponses(value = { @ApiResponse(code = 201, message = "Save Student Successful"),
            @ApiResponse(code = 500, message = "Internal Server Error"),
            @ApiResponse(code = 400, response = ErrorResource.class, message = "Program Type details are required ") })
    @PostMapping("/student")
    public ResponseEntity<HttpStatus> saveStudent(@ApiParam(value="Accepts a Student") @Valid @RequestBody StudentDto dto){
        studentService.saveStudent(dto);
        return new ResponseEntity<>(HttpStatus.CREATED);
    }
}

StudentServiceImpl.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import com.example.demo.dto.StudentDto;
import com.example.demo.entity.Student;
import com.example.demo.exceptions.InternalServerException;
import com.example.demo.repository.StudentRepository;

import lombok.extern.slf4j.Slf4j;


@Service
@Slf4j
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentRepository studentRepository;
    @Autowired
    private Environment e;

    @org.springframework.transaction.annotation.Transactional(rollbackFor= {DataIntegrityViolationException.class, Exception.class})
    @Override
    public void saveStudent(StudentDto dto) {
        Student studentEntity = convertToEntity(dto);
        try {
            studentRepository.save(studentEntity);
        } catch (DataIntegrityViolationException e) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ConstraintViolationException", e.getCause());
        } catch (Exception ex) {
            log.error(e.getProperty("error.errors"), e.getProperty("DB Exception"));
            throw new InternalServerException(HttpStatus.INTERNAL_SERVER_ERROR, e.getProperty("DB Exception"), ex);
        }
    }

    private Student convertToEntity(StudentDto dto) {
        return Student.builder().firstName(dto.getFirstName()).lastName(dto.getLastName()).email(dto.getEmail())
                .build();
    }
}

Ниже приведен запрос полезной нагрузки: в первый раз он будет успешно сохранен в БД. В следующий раз я нажму запрос с той же полезной нагрузкой. UniqueConstraints не удалось, снова я попал в то же самое.

{
  "email": "[email protected]",
  "firstName": "John",
  "lastName": "Doe"
}

Теперь, на этот раз я изменил полезную нагрузку на приведенную ниже, и она сохранена в БД.

{
  "email": "[email protected]",
  "firstName": "John1",
  "lastName": "Doe1"
}

Но я вижу, что последовательности первичного ключа № 2 и 3 уже использованы. Есть ли способ сбросить первичный ключ 2 и 3, и когда запрос будет успешным, я хотел сохранить запись в первичном ключе 2.

student_id |email                |firstname |lastname |
-----------|---------------------|----------|---------|
1          |[email protected]   |John      |Doe      |
4          |[email protected] |John1     |Doe1     |

Дайте мне знать, если потребуется какая-либо другая информация, даже я могу поделиться своим примером кода.


person Pra_A    schedule 27.08.2019    source источник
comment
Это совершенно нормально, ожидаемо и желательно. Если бы генератору идентификаторов пришлось блокировать последовательность до тех пор, пока транзакция не будет зафиксирована, все параллельные транзакции были бы заблокированы в ожидании получения следующего значения, что сделало бы пропускную способность ужасной. Идентификатор просто должен быть уникальным. Вы не должны заботиться о дырах в последовательности идентификаторов.   -  person JB Nizet    schedule 27.08.2019
comment
Согласитесь и, учитывая все эти факты, я все же пытаюсь как-то добиться этого, так как в моем приложении save() не является частыми операциями, и потребитель очень заботится о возрастающей последовательности идентификаторов. Любое обходное решение?   -  person Pra_A    schedule 27.08.2019
comment
Используйте таблицу со строкой, содержащей целое число. Каждый раз, когда вам нужен идентификатор, блокируйте строку (с помощью select for update в SQL или эквивалента в JPA API), считывайте ее значение и увеличивайте его. Строка будет разблокирована в конце транзакции.   -  person JB Nizet    schedule 27.08.2019
comment
Не могли бы вы показать код? Почему rollbackFor не действует ??   -  person Pra_A    schedule 27.08.2019
comment
Поскольку увеличение столбца идентификаторов не является частью транзакции, по причине, которую я объяснил в своем первом комментарии: это был бы лучший способ получить фантастическую производительность и взаимоблокировки. И нет, я не могу показать какой-то пример. Почему бы вам не попробовать сделать это самостоятельно?   -  person JB Nizet    schedule 27.08.2019
comment
любое решение? @Pra_A   -  person Hem M    schedule 24.09.2020