읽기 전용 작업을 위해 Hibernate에서 트랜잭션이 필요한 이유는 무엇입니까?
다음 트랜잭션은 DB에 잠금을 설정합니까?
DB에서 가져 오는 예제 코드 :
Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here
tx.commit() // why tx.commit? I don't want to write anything
session.close()
대신 사용할 수 있습니까 tx.commit()
?
답변
실제로 트랜잭션을 읽기 전용으로 표시 할 이유가있을 수 있습니다.
- 읽기를위한 트랜잭션은 실제로 이상하게 보일 수 있으며 종종 사람들은이 경우 트랜잭션에 대한 메서드를 표시하지 않습니다. 그러나 JDBC는 어쨌든 트랜잭션을 생성합니다.
autocommit=true
다른 옵션이 명시 적으로 설정되지 않은 경우 작동 합니다. - 그러나 메서드가 데이터베이스에 쓰지 않는다는 보장은 없습니다. 메소드를으로 표시하면
@Transactional(readonly=true)
Spring은 JDBC 트랜잭션을 읽기 전용 모드로 설정하므로이 트랜잭션의 범위 에서 실제로 DB에 쓸 수 있는지 여부를 지시합니다 . 아키텍처가 번거롭고 일부 팀 구성원이 예상치 못한 위치에 수정 쿼리를 넣도록 선택할 수있는 경우이 플래그는 문제가있는 위치를 가리 킵니다. - 또한 읽기 전용 트랜잭션은 DB에 의해 최적화 될 수 있지만 이것은 물론 DB에 따라 다릅니다. 예를 들어 MySQL은 5.6.4 버전부터 InnoDB에서만 이에 대한 지원을 추가했습니다.
- JDBC를 직접 사용하지 않고 ORM을 사용하는 경우 문제가 될 수 있습니다. 예를 들어 Hibernate 커뮤니티는 트랜잭션 외부에서 작업하면 예측할 수없는 동작이 발생할 수 있다고 말합니다. Hibernate는 트랜잭션을 열지 만 스스로 닫지는 않을 것이기 때문에 트랜잭션이 커밋되지 않은 상태에서 Connection Pool로 연결이 반환됩니다. 그러면 어떻게됩니까? JDBC는 침묵을 유지하므로 구현에 따라 다릅니다 (MySQL은 트랜잭션을 롤백하고 Oracle은이를 커밋합니다). 이는 또한 연결 풀 수준에서 구성 할 수 있습니다 (예 : C3P0은 이러한 옵션을 제공하며 기본적으로 롤백 됨).
- Hibernate와 관련하여 또 다른 점은 Spring은 읽기 전용 트랜잭션의 경우 FlushMode를 MANUAL로 설정하여 더티 검사가 필요없는 다른 최적화로 이어집니다.
- 트랜잭션 격리 수준을 재정의하거나 명시 적으로 설정할 수 있습니다. 커밋되지 않은 변경 사항을 읽거나 원하지 않기 때문에 읽기 트랜잭션에도 영향을 미치며 팬텀 읽기 등에 노출됩니다.
요약하자면 두 가지 방법을 모두 사용할 수 있지만 결과를 이해해야합니다.
답변
모든 데이터베이스 문은 트랜잭션 경계 (BEGIN / COMMIT / ROLLBACK)를 명시 적으로 선언하지 않은 경우에도 물리적 트랜잭션의 컨텍스트 내에서 실행됩니다 .
트랜잭션 경계를 명시 적으로 선언하지 않으면 각 문을 별도의 트랜잭션 ( autocommit
모드) 에서 실행해야합니다 . 환경이 스레드 당 연결 바인딩을 처리 할 수없는 경우 문당 하나의 연결을 열고 닫을 수도 있습니다.
서비스를 선언 @Transactional
하면 전체 트랜잭션 기간 동안 하나의 연결이 제공되며 모든 문은 해당 단일 격리 연결을 사용합니다. 이것은 애초에 명시 적 트랜잭션을 사용하지 않는 것보다 낫습니다.
대규모 애플리케이션에서는 동시 요청이 많을 수 있으며 데이터베이스 연결 획득 요청 속도를 줄이면 전체 애플리케이션 성능이 확실히 향상됩니다.
JPA는 읽기 작업에 트랜잭션을 적용하지 않습니다. 트랜잭션 컨텍스트를 시작하는 것을 잊은 경우 쓰기 만 트랜잭션 필수 예외를 throw합니다. 그럼에도 불구하고 읽기 전용 트랜잭션의 경우에도 트랜잭션 경계를 선언하는 것이 항상 더 좋습니다 (Spring @Transactional
에서는 성능상의 이점이있는 읽기 전용 트랜잭션을 표시 할 수 있음).
답변
트랜잭션은 실제로 데이터베이스에 잠금을 설정합니다. 좋은 데이터베이스 엔진은 현명한 방식으로 동시 잠금을 처리하며, 다른 트랜잭션이 뷰를 일관성있게 만드는 데이터를 추가 하지 않도록하기 위해 읽기 전용 사용에 유용합니다 . 당신은 항상 트랜잭션을 원합니다 (때로는 격리 수준을 조정하는 것이 합리적이지만 처음에는 그렇게하지 않는 것이 가장 좋습니다). 트랜잭션 중에 DB에 쓰지 않으면 트랜잭션 커밋과 롤백 모두 동일하게 작동합니다 (매우 저렴합니다).
이제 운이 좋으며 DB에 대한 쿼리가 ORM이 항상 단일 SQL 쿼리에 매핑하는 경우 DB의 내장 자동 커밋 동작에 의존하여 명시 적 트랜잭션 없이 벗어날 수 있지만 ORM은 비교적 복잡한 시스템입니다. 따라서 구현이 실제로 수행하는 작업을 확인하는 더 많은 작업을 수행하지 않는 한 이러한 동작에 의존하는 것은 전혀 안전하지 않습니다. 명시적인 트랜잭션 경계를 작성하는 것이 훨씬 더 쉽습니다 (특히 AOP 또는 유사한 ORM 기반 기술로 수행 할 수있는 경우; Java 7부터 try-with-resources도 사용할 수 있다고 생각합니다).
답변
다른 데이터베이스 클라이언트가 결과 집합을 변경하는 데이터를 쓰려고 할 수 있으므로 데이터베이스는 여전히 결과 집합을 추적해야합니다.
나는 거대한 데이터베이스 시스템을 죽이는 결함이있는 프로그램을 보았다. 왜냐하면 그들은 데이터를 읽기만하고 커밋하지 않기 때문에 트랜잭션 로그가 커지도록하기 때문이다. DB가 COMMIT 또는 ROLLBACK 전에 트랜잭션 데이터를 해제 할 수 없기 때문이다. 클라이언트가 아무것도하지 않았더라도 몇 시간 동안.