Я работаю над примером 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 |
Дайте мне знать, если потребуется какая-либо другая информация, даже я могу поделиться своим примером кода.
select for update
в SQL или эквивалента в JPA API), считывайте ее значение и увеличивайте его. Строка будет разблокирована в конце транзакции. - person JB Nizet   schedule 27.08.2019rollbackFor
не действует ?? - person Pra_A   schedule 27.08.2019