[Git] 특정 Branch만 Clone하기

[Git] 특정 Branch만 Clone하기

Git을 사용하면서 브랜치 전체 Clone하지 않고, 특정 브랜치 하나만 사용해야할 경우가 있다.

하지만, 기본적으로 알고 있는 방법으로 git clone할 경우 Master가 바로 Clone됨으로, 특정 브랜치만 클론하는 방법을 알아보자


1
2
3
4
git clone -b <branch명> --single-branch <저장소URL>


ex) git clone -b rpi-4.12.y --single-branch https://github.com/raspberrypi/linux

[Spring Boot] 데이터베이스 격리수준: Database Isolation Level

[Spring Boot] 데이터베이스 격리수준: Database Isolation Level

트랜잭션

일이 처리되기 위한 가장 작은 단위

트랜잭션들이 모여 하나의 트랜잭션을 이룰 수 있고, 서비스가 된다.

하나의 작업을 수행하기 위해 필요한 데이터베이스의 연산들을 모아놓은 것


DB 격리수준

  • 오라클 기본 격리수준 (Read Committed)

READ COMMIT

T1: 트랜잭션 시작 → Update문 (테이블 내의 정보 수정 - 222.Busan -> 222.Jeju)

T2: T1이  Update하는 동안 그 부분을 Select를 하면 T2는 수정되기 전의 정보를 Select한다.
222.Busan (Undo영역 수정 전)

-------------------------

T1: Update한 것을 Commit  (Undo영역이 수정 됨)

T2: T1이 commit하기 전에는 수정하기 전 정보를 Select하게 되고, Commit 이후에 Select하면 수정 된 정보를 볼 수 있다.
222.Jeju (Undo영역 수정 됨)

READ COMMIT 정합성 문제

T2는 트랜잭션을 실행하지않고, Select만 한다.
Busan이 나오다가 갑자기 Jeju가 나와버렸다.

만약에, T2입장에서 T1과 비슷한 시기에 트랜잭션을 실행하고, Select를 계속 한다.
그리고 마지막에 그 Select한 결과들을 모아 Insert연산을 하고 Commit을 한다면...

중간에 데이터가 변경되어 결과가 예상과 달라져버리면 문제가 된다.

이런 문제는 금전적인 처리에서 주로 발생한다.

총 3번 각각 만원씩 Select를 할려고 했는데, 마지막 Select에서 2만원이 나오면,

예상은 3만원 Insert를 하려고 했는데, 4만원이 Insert - Commit이 되어버린다.

정합성이 깨진다 = 부정합, 똑같은 Select에서 다른 것이 나왔을 때

PHANTOM READ(데이터가 보였다 안보였다), 아에 결과가 없을 때

이를 해결하기 위해 REPEATABLE READ방식을 사용해야한다.


  • MySQL 기본 격리수준 (Repeatable Read 이상) –> 부정합 발생 X

transaction Id부여

T2가 먼저 Transaction 시작(Id=10)
222를 Select하면 Busan

T1이 Transaction 시작 (Id=12)
222.Busan --> Jeju upate
commit

하지만 T2입장에서는 아직 자신의 Transaction이 종료되지 않았기 때문에, 항상 동일한 결과를 보여준다.
그래서 시작했을 때는 Busan이 나왔으므로, 끝까지 Busan이 나온다.

자신의 Transaction Id보다 작은 Undo로그를 보고 select한다.

Spring에서는

CRUD

C(Insert), U(Update), D(Delete) --> commit이 필요하므로
@Transactional 붙인다.

R(Select)는 보통 붙이지 않는데, 정합성을 위해 꼭 @Transactional을 붙여서
트랜잭션을 타게 해준다.
[Spring Boot] Ajax 사용하는 이유

[Spring Boot] Ajax 사용하는 이유

회원가입 시 Ajax를 사용하는 이유

요청에 대한 응답을 HTML이 아닌 Data(JSON)로 받기 위해서

클라이언트 (브라우저)는 서버에 요청을 하고, 서버는 클라이언트에게 응답한다.

클라이언트가 서버에게 화면을 요청하면, 서버가 .html로 응답하여 브라우저는 그 html 파일을 읽는다.

메인화면에서 회원가입 수행을 요청하면, 서버는 DB에 회원가입을 수행하고 완료하면 다시 메인화면으로 돌아올 것이고, 결국 html로 응답해줘야하는데…

그 클라이언트가 꼭 브라우저인 것은 아니다. 앱일 경우, html를 반환해주면 이해하지 못한다.

그래서 Data만 반환해주고, 화면을 앱안에서 자체적으로 띄운다.

➡ 브라우저를 위한 서버, 앱을 위한 서버 두개를 따로 만들어야하지만, 차라리, Data를 반환해주는 서버 하나를 만들면 되지 않을까…

서버는 브라우저/앱에게 정상이라는 Data를 반환해준다.

브라우저는 다시 서버에서 request를 보내 html파일을 반환하게 한다.

앱은 자체적으로 화면이동을 한다.

그래서 Data를 Ajax를 사용한다.


비동기 통신을 하기 위해서

보통 일을 수행할 때 1, 2, 3, 4, 5, … 순서대로 실행-종료,실행-종료… 절차적으로 수행한다.

그리고 1: 화면에 그림(내장), 2: 연산, 3: 그림 다운로드(외장), 4: 그림을 그림, 5: 화면에 그림(내장) 이라는 상황일 때, 1,2번이 수행되고, 3번 다운로드하는 10초 pending동안 앱은 멈춰있을 것이다.. 10초 다운로드가 끝나면 4,5번이 수행된다. 이 결과 UX가 나빠진다. 프로그램을 사용하고 싶지 않을 듯

비동기 통신은 절차적으로 일을 수행하는데, 일의 순서에 상관없이 수행한다.

1,2 수행하고, 3번을 비동기 처리하고 4번은 3번이 수행되어야 동작할 수 있기때문에, 5번을 수행하고 있는다.

3번 다운로드하는 동안 4번은 3번을 기다리고, 5번 그림 그리기 수행

  • 5번 수행중 3번이 완료되면 4번으로 콜백한다. 4번이 완료되면 5번 멈췄던 지점부터 다시 시작한다.
  • 5번이 끝난 후에 3번이 완료되면 4번으로 돌아간다.

➡ 비동기라고 한다.

[Git] git status 한글 깨짐 해결하기

[Git] git status 한글 깨짐 해결하기

git status나 commit 할 때, 한글이름을 가지는 파일일 경우에 \352\271\200\ 이런식으로 파일명이 깨지는 경우가 있다.


위 사진처럼 한글이 깨진다면, 아래 코드 한줄을 입력한다.

1
git config --global core.quotepath false

다시 확인해보면, 아래 사진과 같이 파일명이 잘 나오는 것을 볼 수 잇다.

[Spring Boot] JAVA 오버로딩과 오버라이딩

[Spring Boot] JAVA 오버로딩과 오버라이딩

자바의 Overloading & Overriding

자바에서 다형성을 지원하는 방법으로 메서드를 오버로딩, 오버라이딩을 할 수 있다.

  • 오버로딩(Overloading): 같은 이름의 메서드 여러개를 가지면서 매개변수의 유형과 개수가 다르도록 하는 것을 의미한다.
    • 리턴값만을 다르게 갖게 작성할 수 없다.

=> 오버로딩은 기존에 없던 새로운 메서드를 정의하는 것

  • 오버라이딩(Overriding): 상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의해서 사용 하는 것을 의미한다.
    • 상위클래스의 메서드를 하위 클래스에서 재정의하는 것이다.
    • 메서드의 이름, 파라미터의 갯수, 타입이 동일해야 하며, 주로 상위 클래스의 동작을 상속받은 하위 클래스에서 변경하기 위해 사용된다.

=> 오버라이딩은 상속 받은 메서드의 내용만 변경하는 것

[Spring Boot] 데이터베이스 Update 하는 법

[Spring Boot] 데이터베이스 Update 하는 법

데이터베이스 Update하기

웹 브라우저에서 회원 수정을 하는 경우를 생각하며,

@PutMapping을 이용해서 주소를 만들어줬다. 이때 적은 주소는 @GetMapping의 주소와 동일한데, 스프링부트에서는 알아서 Get, Put을 구별해준다.

첫 번째 방법 (Save함수 사용)

주소에서 id를 받아온다. 이 id는 데이터베이스에 저장 된 id값을 불러오기 위함이다.

그리고 @ReqeustBody를 이용하여 Json 데이터를 요청하여, 이를 JavaObject로 변환한다.

SpringBoot에서는 MessageConverter가 Jackson 라이브러리를 사용하여 자동적으로 변환해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// email, password
@PutMapping("/dummy/user/{id}")
public User upadteUser(@PathVariable int id, @RequestBody User requestUser) { // Json 데이터를 요청 => Java Object(MessageConverter의 Jackson라이브러리로 변환해서 받음

User user = userRepository.findById(id).orElseThrow(() -> {
return new IllegalArgumentException("수정에 실패하였습니다.");
});
user.setPassword(requestUser.getPassword());
user.setEmail(requestUser.getEmail());
// save함수는 id를 전달하지 않으면 insert를 해주고,
// save함수는 id를 전달하면 해당 id에 대한 데이터가 있으면 update를 해주고
// save함수는 id를 전달하면 해당 id에 대한 데이터가 없으면 insert를 한다.

userRepository.save(user);
return null;
}

Select 때와 마찬가지로, 잘못 된 (없는) id값을 받았을 때를 방지하기 위해 IllegalArgumentException을 throw 할 수 있도록 한다.

정상적인 user객체에 수정하고자 했던 데이터(password와 email)을 set으로 수정해준다.

그리고 save함수를 이용하여 update해준다.


Save 함수, save 함수를 사용할 때

id를 전달하지 않으면 insert를 해주고,

id를 전달하고, 해당 id에 대한 데이터가 있으면 update를 해준다.

id를 전달하지만, 해당 id에 대한 데이터가 없으면 insert를 해준다.


두 번째 방법

@Transactional라는 annotaion을 사용해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// email, password
@Transactional
@PutMapping("/dummy/user/{id}")
public User upadteUser(@PathVariable int id, @RequestBody User requestUser) { // Json 데이터를 요청 => Java Object(MessageConverter의 Jackson라이브러리로) 변환해서 받음

User user = userRepository.findById(id).orElseThrow(() -> {
return new IllegalArgumentException("수정에 실패하였습니다.");
});
user.setPassword(requestUser.getPassword());
user.setEmail(requestUser.getEmail());

// 더티체킹
return user;
}

첫 번째 방법과 크게 다른 것은 없지만, @Transactional을 이용하면, Save함수를 사용하지 않아도 된다.

이를 Dirty Checking (더티체킹) 이라고 한다.

updateUser라는 함수가 실행될 때, Transaction이 실행되고, return이 될때 Transaction이 자동으로 종료되며, 자동 commit이 된다.


영속성 컨텍스트와 더티체킹에 대해서 공부해보자!

영속성 컨텍스트

[Spring Boot] 데이터베이스 Select 하는 법과 에러체크

[Spring Boot] 데이터베이스 Select 하는 법과 에러체크

데이터베이스의 데이터를 Select할 때 잘못 된 인수가 들어가면 어떻게 해야할까


데이터베이스 Select하기

User table을 select하기에 앞서,

UserRepository라는 인터페이스 파일을 새로 만들고, 그 UserRepository는 JpaRepository를 상속하고 있다.

1
2
3
// 자동으로 bean등록이 된다. --> @Repository 생략가능
public interface UserRepository extends JpaRepository<User, Integer> {
}

그리고 select 기능을 넣어줄 클래스파일에 DI를 해주고,

User의 객체를 return 받을 수 있게, 메소드를 받들어주고, 주소를 넣어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class DummyControllerTest {

@Autowired // 의존성주입(DI)
private UserRepository userRepository;

// {id} 주소로 파라미터를 전달 받을 수 있음.
// http://localhost:8000/blog/dummy/user/3
@GetMapping("/dummy/user/{id}")
public User detail(@PathVariable int id) {
User user = userRepository.findById(id)
...
return user;
}

이 때, 만약 id부분에 DB에 없는 값이 들어가면 어떻게 해야할까… 라는 생각이 들 수 있다.

이 경우, user가 null이 되고, 결국 null값을 반환해주므로 프로그램에 문제가 생길 수 있다.

그래서 findById() 는 Optional로 User객체를 감싸서 반환해준다. 이후 우리가 null인지 아닌지 판단해서 사용하면 된다.

findById().orElseGet()

id값이 유효하면 그대로 user를 반환해주면 되지만, 유효하지 않을 경우 orElseGet을 타서 user에 User()빈 객체를 넣어줄 것이다. 이건 그냥 null과 다르다

orElseGet()에 넣을 수 있는 파라미터는 Supplier의 타입(인터페이스)이고, 이 타입의 Generic부분에 ?가 되어있는데 익명 객체를 넣어준다. 그리고 함수 get을 Override 해준다.

(인터페이스는 new할 수 없기 때문에, 익명 클래스를 만들어줘야한다. )

1
2
3
4
5
6
7
User user = userRepository.findById(id).orElseGet(new Supplier<User>() {
// 데이터베이스에 값이 없는 경우 orElseGet을 타서 user에서 User()...빈 객체를 넣어줌,null이 아님
@Override
public User get() {
return new User();
}
});

findById().orElseThrow()

하지만 findByID()에서 만약 id가 null일 경우 IllegalArgumentException 를 throw하라고 적혀있다.

1
2
3
4
5
6
User user = userRepository.findById(id).orElseThrow(new Supplier<IllegalArgumentException>() {
@Override
public IllegalArgumentException get() {
return new IllegalArgumentException("해당 유저는 없습니다. id: " + id);
}
});

or 람다식을 이용해서…

1
2
3
User user = userRepository.findById(id).orElseThrow(()->{
return new IllegalArgumentException("해당 유저는 없습니다. id: " + id);
});

결과

Spring에는 AOP라는 기능이 있다.

만약 Illegal이 있을경우, 에러를 가로채서 에러페이지로 넘어갈 수 있게 만들 수 있을 것이다.

추가

요청: 웹브라우저

user 객체: 자바 오브젝트

@RestController: html파일이 아닌 data를 리턴해주는 controller

이 경우 웹브라우저가 이해할 수 있는 데이터 (Json)으로 변환해줘야하는데, SpringBoot는 MessageConter가 자바 오브젝트가 리턴될 시 자동으로 Jackson라이브러리를 호출해서 user 오브젝트를 Json으로 변환해서 브라우저에게 전달한다.