분류 전체보기 954

26. 트랜잭션 템플릿

보다보면, 같은 패턴이 반복되는 것이 있다. try.. catch.. 커넥션 얻고, 상태 얻고 등 public void accountTransfer(String fromId, String toId, int money) throws SQLException { TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try{ transferLogic(fromId, toId, money); transactionManager.commit(status); }catch(Exception e){ transactionManager.rollback(status); throw new IllegalState..

25. 트랜잭션 매니저

저번 코드는 DB와 소통하는 리포지토리의 커넥터가 서비스까지 올라왔고, 그로 인해 서비스가 특정 기술에 영향을 받게 되었다. 서비스는 특정 기술에 의존 하면 안된다. 그러므로 트랜잭션 추상화에 대해 생각해 보았다. 편리하게도, 이미 스프링이 트랜잭션에 대한 인터페이스를 제공해 주고, 각 회사들이 구현체를 만들어 놨다. 이제 실제로 코드로 사용 해 볼 것이다. @Slf4j public class MemberRepositoryV3 { private final DataSource dataSource; public MemberRepositoryV3(DataSource dataSource) { this.dataSource = dataSource; } public Member save(Member member) t..

24. 트랜잭션 동기화

스프링이 제공하는 트랜잭션 매니저( PlatformTransactionManager )는 크게 2가지 역할을 한다. 트랜잭션 추상화 리소스 동기화 트랜잭션 추상화는 직전에 말 했고, 리소스 동기화 트랜잭션을 유지하려면 트랜잭션의 시작부터 끝까지 같은 커넥션(DB세션)을 유지해야 한다. 이전에는 그걸 파라미터로 줬다. 하지만 스프링이 제공하는 트랜잭션 매니저는 이런 식이다. 트랜잭션 매니저 내부에는 트랜잭션 동기화 매니저가 있다. 트랜잭션 할 때는 커넥션을 쓰레드 로컬에 저장해 놓는데, 쓰레드 로컬이란 그 쓰레드만 접근할 수 있는 저장소이다. 트랜잭션 동기화 매니저가 쓰레드 로컬에 저장해 놓는 것이다. 그래서 커넥션이 필요하면 저 로컬쓰레드에 있는 커넥션을 획득하면 되서, 이전처럼 파라미터로 커넥션을 전달..

23. 트랜잭션 추상화

스프링은 서비스 계층을 순수하게 유지하면서, 앞서 말했던 문제들을 해결 할 수 있는 다양한 방법과 기술들을 제공한다. 먼저, 앞서 Service는 Jdbc 기술에 의존하고 있었다. 만약 Jpa로 바꾸게 된다면, Jpa의 트랜잭션 구현은 비슷한 면도 있지만 다르다. 만약 기술을 바꿀 때 마다.. 리포지토리는 사실 DB와의 소통을 위한 것 이라 적어도 명분은 되지만, 비즈니스 로직은 아니다.. 정말 순수해야 한다. DB 접근 기술에 따라 서비스 로직도 바꿔야 한다면, 리포지토리의 단일책임 원칙에 맞지 않는 것이다. 해결법 중에 이제, 트랜잭션 인터페이스를 만들고, 트랜잭션은 외부에서 주입받거나, 어댑터 패턴으로 처리하고 하면 되긴 할 듯 싶다.(확실히 이번 경우는 서버사이드에서 바뀌는 거니 어댑터 패턴은 아..

22. 기존 트랜잭션의 문제

먼저, 스프링의 애플리케이션 구조 Controller에서 사용자와 상호작용 하고 Controller에서 사용자의 요청에 따라 알맞은 서비스를 호출하고 서비스에서는 필요에 따라 리포지토리(DB)에 접근한다. Controller UI 관련 처리 웹 요청, 응답 사용자 요청 검증 Service 비즈니스 로직 가급적 특정 기술에 의존하지 않고 순수 자바 코드로 작성 Repository DB와 소통하는 코드 여기서 Service는, 특정 기술에 종속적이지 않아야 한다. 웹, REST API 등 여러 통신 방법에도 같아야 한다. 그래서 거의 순수 자바 코드로 작성되어야 한다. Controller에서는 웹, REST API 등 다양한 요청 및 응답은 이 친구가 처리를 해 주고, 그래서 요청마다 약간 다를 수 있고, ..

21. 이체 트랜잭션 적용

우선, 커밋모드에 대한 적용은 세션마다 이므로, 커넥션을 얻는 것은 한 섹션을 생성한 다음 그 섹션과의 소통을 위한 객체를 얻는 것이니 우리가 커넥션을 지정해서 줄 필요가 있다. @Slf4j public class MemberRepositoryV2 { private final DataSource dataSource; public Member findById(Connection con, String memberId) throws SQLException { String sql = "select * from member where member_id = ?"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = con.prepareStateme..

19. 조회할 때 락 가져오기

cud 뿐만 아니라 조회하는 순간에 락을 가져갈 수 있다. select 문 + for update 하면 된다. set autocommit false; select * from member where member_id='memberA' for update; 물론 이 순간에도 후에 commit이나 rollback 하면 락을 반납한다. 뭔가 내가 계산이 끝나기 전 까지 다른 세션에서 update 하지 못하도록 하고 싶을 때 쓴다고 한다. 내가 뭔가 복잡한 처리를 끝마칠 때 까지 다른 세션이 건들지 못하도록 하고 싶을 때.

18. DB 락

세션 1이 아직 commit을 안했는데 세션 2에서 (혹은 세션 1에서도) 같은 데이터를 접근 시 수정하면 뭔가 문제가 될 수도 있다. 그래서, 세션 1이 그 데이터들을 commit 혹은 rollback 하기 전 까지 lock 해 버린다. 아마 bool isAutoCommitMode = false; static ArrayList temps; 이런 식으로 각 세션마다 되어 있고, 실제 데이터 등록하는 그런 거는 cud(Data data) foreach( Data tempData : temps){ if(tempData.equals(data)){ throw new Error("data is Locked"); } } ~~~~ temps.add(data); if(isAutoCommitMode){ data.comm..

17. 트랜잭션 실습

참고로, DB 로그인을 한번 더 하면 그거는 다른 세션으로 여는 거다. 그리고 무슨 타임아웃 lock 같은 게 걸릴 수 있는데, (자동 커밋 실험하다가) 그럼 그냥 DB 연결 끊었다가 다시 실행하면 된다. commit 안한상태로 primary key인걸 똑같이 insert 하려고 했더니 그렇게 됨(다른 세션에서 insert 하려고 해도 그럼.) 세션 1이 신규 데이터 추가 후 커밋 전. 아직 세션2는 확인할 수 없음. 세션 1이 commit 후 DB에 임시로 등록되었던 데이터가 제대로 완전히 등록됨. 이제 세션2도 볼 수 있음. commit 해서 등록되기 전까지 자기 세션에서만 나타남 어떤 느낌이냐면, 한줄 읽고 데이터 반영하는 것은 같지만, (그래서 1번 줄 성공하고 2번 줄 실패하면 1번줄은 임시로 ..

카테고리 없음 2023.09.29