在从一个线程检索实体以及在另一个线程中对其进行修改时,我看到了JPA的“奇怪”行为。下面是我的示例代码来解释这个问题。典型情景:
data
据我所知,JPA具有与每个线程相关联的持久性上下文(PC),因此在其中存储实体。线程不能看到对方的电脑。我认为如果相应的线程在实体上创建/更新操作,PC会得到更新。我认为JPA的这种行为违反了数据库隔离原则。难道不应该把更新的数据从盒子里拿出来吗?还是我在这漏掉了什么?
日志
2021-05-28 07:13:03.503 INFO 7425 --- [nio-8080-exec-2] com.example.demo.StudentController : Created student... Student{id=1, name='Omkar', score=50}
2021-05-28 07:14:22.272 INFO 7425 --- [nio-8080-exec-4] com.example.demo.StudentController : Get student Student{id=1, name='Omkar', score=50}
2021-05-28 07:14:27.280 INFO 7425 --- [nio-8080-exec-4] com.example.demo.StudentController : Get student Student{id=1, name='Omkar', score=50}
2021-05-28 07:14:32.282 INFO 7425 --- [nio-8080-exec-4] com.example.demo.StudentController : Get student Student{id=1, name='Omkar', score=50}
2021-05-28 07:14:33.748 INFO 7425 --- [nio-8080-exec-5] com.example.demo.StudentController : Updating student... Student{id=1, name='Omkar', score=75}
2021-05-28 07:14:37.284 INFO 7425 --- [nio-8080-exec-4] com.example.demo.StudentController : Get student Student{id=1, name='Omkar', score=50}
2021-05-28 07:14:42.288 INFO 7425 --- [nio-8080-exec-4] com.example.demo.StudentController : Get student Student{id=1, name='Omkar', score=50}实体
@Entity
public class Student {
@Id
private int id;
private String name;
private int score;
...存储库
public interface StudentRepository extends JpaRepository<Student, Integer> {
}控制器
@RestController
@RequestMapping("/api/student")
public class StudentController {
@Autowired
private StudentRepository studentRepository;
private final static Logger LOGGER = LoggerFactory.getLogger(StudentController.class);
@GetMapping
public void getStudent() {
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Student student = studentRepository.findById(1).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
LOGGER.info("Get student {}",student.toString());
}
}
@PostMapping
public ResponseEntity<Student> updateStudent(@RequestParam("score") int score) {
Student student = studentRepository.findById(1).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
student.setScore(score);
Student updated = studentRepository.save(student);
LOGGER.info("Updating student... {}", updated);
return ResponseEntity.ok(updated);
}
@PutMapping
public ResponseEntity<Student> createStudent(Student student) {
Student saved = studentRepository.save(student);
LOGGER.info("Created student... {}", saved);
return ResponseEntity.created(URI.create("/api/student/" + saved.getId())).body(saved);
}
}发布于 2021-05-28 04:38:55
将循环更改为
@GetMapping
public void getStudent() {
while (true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
entityManager.clear();
Student student = studentRepository.findById(1).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
LOGGER.info("Get student {}",student.toString());
}
}基本上,findById的结果会附加到当前事务中,并且查询只会被调用一次(即使是在循环中)。要再次访问数据库,您应该分离该实体。可以通过调用entityManager.clear()来分离实体
https://stackoverflow.com/questions/67731984
复制相似问题