-
여러개의 작업을 하나로 묶은 것
-
롤백 = 묶은 작업 중 하나라도 잘못되면, 작업이 실행되기 이전의 상태로 돌립니다.
-
데이터베이스를 수정하는 작업에서는 반드시 사용해야 합니다.
b) 왜냐하면 데이터 베이스를 수정하다가 오류가 나면 데이터 베이스에 잘 못된 데이터가 들어갈 수 있습니다. 이 때 롤백기능을 사용해서 잘못된 데이터가 추가되지 않도록 만들어야 합니다. -
한번에 이루어져야 하는 작업들을 관리할 때 사용합니다.
예시
@Transactional
public void Service(){
minusPoint();
sendPoint();
plusPoint();
}
위 작업에서 포인트를 주고받습니다. 만약 포인트를 다른 사람엑 전송하기 위해 minuPoint()를 실행한 후 오류가 난다면, 포인트는 전송되지 않고 사라집니다.
따라서 포인트를 주고 받는 행위에 포함되는 모든 작업을 트랜잭션으로 묶어서 작업 도중에 오류가 난다면 롤백이 일어날 수 있도록 해야합니다.
- 원자성
- 한 트랜잭션 내에서의 작업은 모두 하나로 간주합니다.
- 따라서 트랜잭션에 속하는 작업들의 실행 결과는 모두 성공하거나 모두 실패하거나 둘 중 하나입니다.
- 일관성
- 트랜잭션은 일관성있는 데이터베이스 상태를 유지합니다.
(data integrity 만족)
- 격리성
- 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리해야 합니다.
- 지속성
- 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 합니다.
-
스프링에서는 트랜잭션 처리를 다양한 방법으로 지원합니다.
- xml 방식
- JavaConfig 방식
- 어노테이션(annotaion) 방식
-
그중 어노테이션 방식으로
@Transactional
을 선언하여 사용하는 방법이 일반적이며, 이 방식으로 생성된 트랜잭션을 선언적 트랜잭션이라고 부릅니다.
-
클래스, 메서드 코드 위에
@Transactional
어노테이션이 추가되면 해당 클래스에 프록시 기능이 적용된 프록시 객체가 생성됩니다. -
이 프록시 객체는
@Transacitonal
이 포함된 메서드가 호출되었을 때,PlatformTransactionalManager
를 사용하여 트랜잭션을 시작하고, 정상 여부에 따라서 Commit 또는 Rollback을 합니다.
- Dirty Read
-
트랜잭션 A가 어떤 값을 1에서 2로 변경하고 아직 커밋하지 않은 상황에서 트랜잭션 B가 같은 값을 읽는다면, 트랜잭션 B는 해당 값을 2로 받아옵니다.
-
하지만 트랜잭션 B가 값을 읽어간 후, 트랜잭션 A가 롤백된다면 트랜잭션 B는 잘못된 값을 가져가게 된 것입니다.
-
트랜잭션이 완료(commit)되지 않은 상황에서 데이터에 접근을 허용할 때 발생할 수 있는 데이터 불일치입니다.
- Non-Repeatable Read
-
트랜잭션 A가 어떤 값을 읽은 후, 한번 더 읽는 작업을 한다고 가정합니다.
-
만약 첫번째 읽기 작업에서 해당 값을 1로 읽어온 후, 트랜잭션 B가 해당 값을 1에서 2로 바꾼 후 커밋해버린다면, A는 첫번째 읽기 작업을 통해서 얻어온 값과 두번재 읽기 작업을 통해서 얻어 온 값이 달라집니다.
-
한 트랙잭션에서 똑같은 쿼리를 두번 실행했을 때 발생할 수 있는 데이터 불일치입니다.
-
Dirty Read 보다는 일어날 확률이 적습니다.
- Phantom Read
-
트랜잭션 A가 어떤 쿼리를 사용하여 특정 범위의 값[0, 1, 2, 3, 4] 를 읽었다고 가정합니다.
-
이후 A는 똑같은 쿼리를 한번더 실행할 것인데, 그 사이에 트랜잭션 B가 앞서 [0, 1, 2, 3, 4] 가 들어있던 테이블에 값 [5, 6, 7]을 추가한다면, A가 이후 똑같은 쿼리를 실행했는데도 쿼리의 결과로 반환되는 값이 달라집니다.
-
한 트랜잭션에서 일정 범위의 레코드를 두번이상 읽을 때 나타나는 데이터 불일치입니다.
- 스프링에서는 위와 같은 트랙재션 경쟁을 방지할 수 있는 속성을 지원합니다.
- isonlation(격리수준)
-
트랜잭션에서 일관성이 없는 데이터를 허용하는 수준을 말합니다.
- DEFAULT = 기본 격리 수준(기본 설정, DB의 isolation level을 따릅니다.)
- READ_UNCOMMITED (level 0) = 커밋되지 않은(트랜잭션이 처리중인) 데이터에 대해서 읽기 허용
- Dirty Read 발생 가능
- READ_COMMITED ( level 1) = 트랜잭션이 커밋한 확정 데이터만 읽기 허용
- Dirty Read 발생하지 않습니다.
- REPEATABLE_READ( level 2) = 트랜잭션이 완료될 때까지 해당 트랜잭션의 SELECT 문장에서 사용하는 모든 데이터에 shared lock 이 걸리기 때문에, 다른 사용자는 해당 데이터에 대한 수정이 불가능합니다.
- 한 트랜잭션이 읽은 데이터는 다른 트랜잭션이 수정, 삭제가 불가능하기 때문에 같은 쿼리를 두번 하더라도 똑같은 결과를 얻을 수 있습니다.
- Non-Repeatable Read 발생하지 않습니다.
- SERIALIABLE( level 3) = 데이터의 일관성 및 동시성을 위해서 MVCC(Multi Vision Concurrency Control) 을 사용하지 않습니다.
- 트랜잭션이 완료될 때까지, 해당 트랜잭션의 SElECT 문에서 사용하는 모든 데이터에 대해 shared lock 이 걸립니다. 따라서 다른 사용자는 해당 영역에 대항하는 데이터에 대해 수정, 입력이 불가능합니다.
- Phantom Read 발생하지 않습니다.
-
격리 수준이 올라갈 수록 성능 저하의 우려가 있습니다.
-
예시
@Transactional(isolation = Isolation.DEFAULT)
public void somthing(int a){
...
}
- propagation (전파 옵션)
-
한 트랜잭션에서 다른 트랜잭션을 호출하는 상황에서 선택할 수 있는 옵션
- REQUIRED = 디폴트
- 부모 트랜잭션 내에서 실행하며, 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 생성합니다.
- SUPPORTS
- 이미 시작된 트랜잭션이 있으면 참여하고 그렇지 않으면 트랜잭션없이 진행되게 합니다.
- REQUIRES_NEW
- 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성됩니다.
- 이미 진행중인 트랜잭션이 있으면, 트랜잭션 생성을 잠시 보류시킵니다.
- MANDATORY
- REQUIRED 와 비슷하게, 이미 시작된 트랜잭션이 있으면 참여합니다.
- 이미 시작된 트랜잭션이 없으면, 새로 시작하는 대신 예외를 발생시킵니다.
- 혼자서 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용합니다.
- NOT_SUPPORTED
- 트랜잭션을 사용하지 않도록 강제합니다.
- 이미 실행중인 트랜잭션이 존재하면 예외를 보류시킨다.
- NEVER
- 트랜잭션을 사용하지 않게 한다.
- 이미 진행 중인 트랜잭션이 있으면 예외를 발생시킨다.
- NESTED
-
이미 진행중인 트랜잭션이 있으면, 중첩 트랜잭션을 시작합니다.
-
중첩 트랜잭션 = 트랜잭션안에 트랜잭션을 만드는 것
-
중첩 트랜잭션은 먼저 시작된 트랜잭션(부모 트랜잭션)의 커밋과 롤백에는 영향을 받지만 자신의 커밋, 롤백은 부모 트랜잭션에 영향을 주지 않습니다.
-
EX. 쇼핑몰에서 주문트랜잭션에 로그를 남기는 작업이 있는 경우
-
이 로그를 남기는 작업이 실패한다고 해서 메인 작업까지 롤백되면 안됩니다.
-
하지만 주문작업이 실패했을 때는 로그를 남기지 않는 것이 맞습니다.
-
이 때 중첩 트랜잭션을 사용하면 됩니다.
- readOnly 속성
-
트랜잭션을 읽기전용 속성으로 지정할 수 있습니다.
-
성능 최적화를 위해서 or 특정 트랜잭션 작업안에서 쓰기 작업이 일어나는 것을 막기 위해서 사용할 수 있습니다.
-
일부 트랜잭션의 경우 일기전용 속성을 무시하고 쓰기 작업을 허용할 수도 있습니다.
-
readOnly 속성이 지정된 트랜잭션에서 INSERT, DELETE, UPDATE 작업과 같이 쓰기 작업이 일어나면 예외가 발생합니다.
-
aop/tx 스키마로 트랜잭션 선언할 때는 이름 패턴을 이용해서 읽기 전용 속성으로 만드는 경우가 많다. 보통 get이나 find같은 이름의 메소드를 읽기 전용 메소드로 만들어서 사용하면 편합니다.
-
@Transactional
을 사용하여 트랜잭션을 만드는 경우는 일일이 읽기 전용 속성을 지정해줘야 합니다.read-only
속성 또는readOnly
속성을 true로 지정하면 읽기 전용으로 지정됩니다. -
true인 경우에는 INSERT, UPDATE, DELETE 발생시 예외 발생하며, 디폴트는 false로 되어 있습니다.
-
예시
@Transaction(readOnly = true)
- 트랜잭션 롤백 예외 (rollback-for, rollbackFor, rollbackForClassName)
-
선언적 트랜잭션에서는 런타임에서 예외(오류)가 발생하면 롤백합니다.
-
반면에 예외가 전여 발생하지 않거나 체크 예외가 발생하면 커밋합니다.
-
체크 예외가 커밋 대상인 이유 = 체크 예외가 예외적인 상황일 때 발생하기 보다는 리턴 값을 대신해서 비즈니스적인 의미를 담은 결과를 반환하는 용도로 사용되기 때문입니다.
-
스프링에서는 데이터 액세스 때 발생하는 예외는 런타임 예외로 발생하기 때문에, 런타임 예외가 일어났을 때에만 롤백이 일어납니다.
-
하지만 롤백이 일어나는 대상을 바꿀 수 있습니다.
ex. 체크 예외이지만 롤백이 일어나야하는 경우가 있다면, XML의 roolback-for 애트리뷰트나 어노테이션@rollback
혹은 rollbackForClassName 속성을 사용해서 예외를 지정하면 됩니다.
rollback-for 애트리뷰트 나 rollbackForClassName 속성에는 예외 이름을 지정하면되고,@rollbackFor
는 예외 대상 클래스에 넣어주면됩니다. -
@Transaction
어노테이션에서rollbackFor
속성을 이용하여 지정하는 경우에는 클래스 이름 대신 클래스를 직접 사용해도 됩니다.
ex.
@Transactional(readOnly = true, rallbackFor = NoSuchMemberException.class)
@Transactional
어노테이션에서 롤백 관련 속성- rollbackFor: 특정 예외가 발생했을 때 강제로 Rollback
예: @Transactional(rollbackFor = Exception.class) - noRollbackFor: 특정 예외 발생시 Rollback 하지 않음 예: @Transaction(noRollbackFor = Exception.class)
- timeout 속성
-
timeout 속성으로 지정한 시간내에 해당 트랜잭션이 완료되지 않은 경우 rollback 수행합니다.
-
-1이일 경우 timeout 속성을 지정하지 않은 것이며, default에 해당합니다.
-
ex) Transactional(timeout = 10)
-
스프링 기반의 어플리케이션의 보안(인증, 인가, 권한 등)을 담당하는 프레임워크
-
스프링 시큐리티를 사용하지 않으면, 자체적으로 보안을 위한 로직을 구현해야한다.
하지만 스프링 시큐리티를 사용하면 보안과 관련한 옵션을 제공하기 때문에, 우리는 이 옵션만 사용하면 쉽게 보안을 구현할 수 있다. -
스프링 시큐리티는 filter 기반으로 동작하기 때문에 spring MVC 와 분리되어 동작한다.
-
접근 주체(Principal): 보호된 리소스에 접근하려는 유저
-
인증(Authenticate): 보호된 리소스에 접근하려는 유저에 대해서 이 유저가 누구인지 확인하는 작업, 해당 작업을 수행해도 되는 유저인지를 확인하는 작업(ex. Form 기반 로그인)
-
인가(Authorize): 해당 리소스에 대해 접근가능한 권한을 가지고 있는지 검사하는 것, 인증 이후에 이루어집니다.
-
권한: 인증된 주체가 애플리케이션의 동작을 수행할 수 있도록 허락되었는지를 결정
- 권한 승인이 필요한 부분으로 접근하려면, 먼저 인증 과정을 통해서 주체가 인증되어야 한다.
- 즉, 인가 과정에서 해당 리소스에 대한 권한을 가지고 있는지를 확인한다.
- 위 그림 = Form 기반 로그인에 대한 흐름을 보여줍니다.
-
사용자가 Form 을 이용하여 로그인하기 위한 정보를 입력하고 인증 요청을 보냅니다.(Http Request)
-
AuthenticationFilter가 HttpServletRequest에서 사용자가 보낸 아이디와 패스워드를 꺼냅니다.
- 보안을 위해서 아이디와 패스워드의 유효성 검사를 해줍니다.(아이디 혹은 패스워드가 null 인지 등).
- 인증을 담당하는 AuthentiacationManager 인터페이스 구현체에게, HttpServeletRequest 에서 꺼낸 사용자 아이디와 패스워드를 인증용 객체(UsernamePasswordAuthenticationToken) 로만들어서 전달합니다.
-
AuthenticationFilter에게 Authentiaction 객체(인증용 객체, UsernamePasswordAuthenticationToken)을 전달받습니다.
-
실제 인증을 할 AuthenticationProvider에게 Autication 객체를 다시 전달합니다.
-
DB에서 사용자 인증정보를 가져올 UserDetailsSercice 객체에게 사용자 아이디를 넘겨주고, DB에서 인증에 사용할 정보(아이디, 암호화된 패스워드, 권한 등)를 UserDetails라는 객체로 전달받습니다.
-
AuthenticationProvider는 UserDetails객체를 전달 받은 후, 실제 사용자의 입력정보와 UserDetails 객체를 가지고 인증합니다. 7, 8, 9, 10. 인증이 ㅅ완료되면 사용자 정보를 가진 Authentication 객체를 SecurityContextHolder 에 담은 후 AuthenticationSuccessHandle를 실행합니다.(실패시 AuthenticationFailHandle을 실행합니다.)
-
SecurityContextPersistenceFilter : SEcurityContextRespository에서 SecurityContext를 가져오가너 저장하는 역할을 합니다.
-
LogoutFilter : 설정된 로그아웃 URL로 오는 요청을 감시하며, 해당 유저를 로그아웃 처리를 합니다. (UsernamePassword)
-
AuthenticationFilter : (아이디와 비밀번호를 사용하는 form 기반 인증) 설정된 로그인 URL로 오는 요청을 감시하며, 유저 인증 처리를 합니다.
- AuthenticationManager를 통한 인증을 실행합니다.
- 인증 성공 시, 얻은 Authentication 객체를 SecurityContext에 저장 후 AuthenticationSuccessHandler 실행합니다.
- 인증 실패 시, AuthenticationFailureHandler 실행합니다.
- DefaultLoginPageGeneratingFilter : 인증을 위한 로그인폼 URL을 감시합니다.
- BasicAuthenticationFilter : HTTP 기본 인증 헤더를 감시하여 처리합니다.
- RequestCacheAwareFilter : 로그인 성공 후, 원래 요청 정보를 재구성하기 위해 사용됩니다.
- SecurityContextHolderAwareRequestFilter : HttpServletRequestWrapper를 상속한 SecurityContextHolderAwareRequestWapper 클래스로 HttpServletRequest 정보를 감쌉니다.
- SecurityContextHolderAwareRequestWrapper 클래스는 필터 체인상의 다음 필터들에게 부가정보를 제공합니다.
- AnonymousAuthenticationFilter : 이 필터가 호출되는 시점까지 사용자 정보가 인증되지 않았다면 인증토큰에 사용자가 익명 사용자로 나타납니다.
- SessionManagementFilter : 이 필터는 인증된 사용자와 관련된 모든 세션을 추적합니다.
- ExceptionTranslationFilter : 이 필터는 보호된 요청을 처리하는 중에 발생할 수 있는 예외를 위임하거나 전달하는 역할을 합니다.
- FilterSecurityInterceptor : 이 필터는 AccessDecisionManager 로 권한부여 처리를 위임함으로써 접근 제어 결정을 쉽게해줍니다.
https://sjh836.tistory.com/165 [빨간색코딩]