로그아웃하기

Jan 31, 2024
로그아웃하기

1. sessionID 삭제하기

이미 로그인 시도해서 sessionID가 저장되어있기 때문에 F12해서 쿠키에 삭제해야 함
notion image
 
 

2. 트랜잭션 : 디비를 변형할 때 걸리는 것

  • 일의 최소 단위 : 일은 상대적인 것
  • 현재 상태를 변경 불가능한 상태로 고정시키는 것 = 타임 아웃 같은것(시간이 멈춤)
  • write 요청 시 다른 애들이 못하고 한 명이 독립적으로 insert 사용 가능함
  • 트랜잭션은 응답하면 끝남
  • 다른 애들이 DB 변형할 때 rock이 걸림
 

3. 스프링에서는 트랜잭션을 좀 더 길게 끌고 갈 수 있음

  • 요청 > 응답하고 종료가 아니라 쥐고 있을 수 있음
  • 왜 트랜잭션을 안 끈기게 하게 할까? 한번에 안 끝나는 트랜잭션도 있기 때문!
ex) 입금은 내 금액만 수정
이체는 내 금액과 상대방의 금액을 수
둘 다 1000원씩 있는데 A가 B한테 1000원을 이체 요청함
트랜잭션을 걸어서 A만 가능하고 나머지는 wait 걸림
update 문으로 wait 요청하고 B의 금액을 수정하고 트랜잭션이 끝이 나면
A의 금액을 수정를 하지 못하고
다른 C가 이체 요청을 해서 A의 1000원 금액을 가져갈 수 있음
은행의 입장에서는 없는 A의 금액을 이체 해줄 수 없기에 A가 B에게 이체해주는 것이 안됨
  • update : 실제로 하드디스크에 기록되는 것이 아니라 메모리에만 기록된 것
  • commit : 영구히 기록하기 위해 하는 것
 
  • username을 사용하여 데이터베이스에서 사용자를 조회해당 사용자가 데이터베이스에 존재하는지 여부 확인
    • package shop.mtcoding.blog.user; import jdk.swing.interop.SwingInterOpUtils; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; import javax.persistence.Query; @Repository // 내가 new 하지 않아도 메모리에 띄울 수 있음 public class UserRepository { private EntityManager em; // 컴포지션 public UserRepository(EntityManager em) { // 생성자 this.em = em; public boolean UserRepository(String username) { // 생성자 Query query = em.createNativeQuery("select * from user_tb where username=?", User.class); query.setParameter(1, username); try { User user = (User) query.getSingleResult(); return true; // 있음 } catch (Exception e) { return false; // 없음 } } @Transactional public void save(UserRequest.joinDTO requestDTO) { // 컨트롤러는 정보를 전달하면서 때리고 위임함 Query query = em.createNativeQuery("insert into user_tb(username, password, email) values (?, ?, ?)"); query.setParameter(1, requestDTO.getUsername()); query.setParameter(2, requestDTO.getPassword()); query.setParameter(3, requestDTO.getEmail()); query.executeUpdate(); } @Transactional public void saveV2(UserRequest.joinDTO requestDTO) { User user = new User();// 통신을 통해 받은 데이터를 entity를 만들어서 담아보기 user.setUsername(requestDTO.getUsername()); user.setPassword(requestDTO.getPassword()); user.setEmail(requestDTO.getEmail()); em.persist(user); } public User findByUsernameAndPassword(UserRequest.loginDTO requestDTO) { Query query = em.createNativeQuery("select * from user_tb where username=? and password=?", User.class); query.setParameter(1, requestDTO.getUsername()); query.setParameter(2, requestDTO.getPassword()); User user = (User) query.getSingleResult(); return user; try { User user = (User) query.getSingleResult(); return user; } catch (Exception e) { return null; } } }
 
  • -1이 떨어지면 전체를 롤백해야 함
트랜잭션 안에서 했던 모든 것들은 아직 커밋이 안된 상태
메모리를 초기화하는 것 : 메모리를 원상태로 바꾸는 것
 
ex) 1000원씩 있는데 메모리에 기억하고 있음
하나를 0으로 바꾸고 다른 애를 2000원으로 바꿔야 할 때 따로 기억하는 것 : 언두(undo)=취소
트랜잭션에서 이전 상태로 롤백하는 기능
다시 요청했는데 실패할 경우
언두(에 있는 데이터를 가지고 와서 덮어 씌우는 것)해야 함 ⇒ 원자성
  • 원자성(Atomicity) : 트랜잭션이 성공적으로 완료 or 실패할 경우 롤백되어야 함
될거면 다되고 안되면 처음으로 돌아가는 것
 
insert(회원가입)하기 전에 터지면 다른 애들이 wait가 걸리니까
select 요청해서 확인하고 insert 하는 것이 안전함
💡
실패하는 트랜잭션을 만들지 말라는 것!
 
  • read할 때부터 트랜잭션을 걸면 절대 아무도 못 건드림!
write할 때만 걸면 확인하고 insert하러 갔더니 누가 했을 수도 있음 / 팬텀 데이터 문제
  • read, write를 트랜잭션으로 묶을 수 있음 → 유령 데이터(팬텀 데이터)이 안보임
트랜잭션 내에서 데이터의 일관성을 유지할 수 있음
작업이 완료되기전에 다른 작업에 의해 변경되지 않음
  • 스프링에 서비스를 관리하는 레이어(Service)가 더 필요함
트랜잭션을 걸어야 함
나머지가 wait 걸리니까 트랜잭션 시간을 줄여야함
@Transactional
 
  • 유효성 검사 전에 save 메서드 안에서 트랜잭션을 걸면 좋지 않음
독립적으로 두 번 걸리는 것이기 때문
→ read와 write가 따로 돌게 되고 틈이 생기게 됨
하나로 묶을 서비스 레이어가 필요함
  • 최소한의 단위를 트랜잭션으로 묶을 수 있음
username 체크 위임을 다른 클래스로 옮겨서 트랜젝션을 걸 수 있음
 

4. UserController에 로그아웃에서 session 날리기

  • 현재 사용자의 세션을 무효화하여 로그아웃하는 역할
  • 사용자의 세션을 제거하고 모든 세션 속성을 삭제
package shop.mtcoding.blog.user; import jakarta.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @Controller public class UserController { private UserRepository userRepository; // null 이기에 생성자 만들기 private final HttpSession session; public UserController(UserRepository userRepository, HttpSession session) { //IOC 컨테이너에서 써치해서 찾아서 넣어줌 this.userRepository = userRepository; this.session = session; } // 생성자를 만들어서 디폴트 생성자를 없애버림 @GetMapping("/joinForm") public String joinForm() { return "user/joinForm"; } @PostMapping("/join") public String join(UserRequest.JoinDTO requestDTO) { System.out.println("requestDTO: " + requestDTO); // 1. 유효성 검사 if (requestDTO.getUsername().length() < 3) { return "error/400"; } // 모델에 위임하기 // insert into user_tb(username, password, email) values (?, ?, ?) try { // 터트린 것을 잡겠다? userRepository.save(requestDTO); //경우의 수가 너무 다양함 : 에러를 명확하게 판단하기 힘듦 } catch (Exception e) { } return "redirect:/loginForm"; //리다이렉션불러놓은게 있어서 다시부른거 } @GetMapping("/loginForm") public String loginForm() { return "user/loginForm"; } // 원래는 get요청이나 예외 post요청하면 됨 // 민감한 정보는 쿼리 스트링에 담아보낼 수 없음 @PostMapping("/login") public String login(UserRequest.LoginDTO requestDTO) { System.out.println(requestDTO); // 유효성 검사 if (requestDTO.getUsername().length() < 3) { return "error/400"; } // select * from user_tb where username=? and password=? User user = userRepository.findByUsernameAndPassword(requestDTO); // DB에 조회할때 필요하니까 데이터를 받음 System.out.println(requestDTO); // 인증 검사 if (user == null) { // 인증 안됨 return "error/401"; } else { // 인증됨 session.setAttribute("sessionUser", user); return "redirect:/"; } } @GetMapping("/user/updateForm") public String updateForm() { return "user/updateForm"; } @GetMapping("/logout") public String logout() { session.invalidate(); // 현재 사용자의 세션을 무효화하여 로그아웃하는 역할 return "redirect:/"; } }
notion image

로그아웃

notion image
로그아웃은 키 자체의 값이 없어져야 한다. session.invalidate()로 서랍을 날린다.
notion image
 
 
Share article

vosw1