개발이군고구마

DB connection 변화의 역사 본문

SERVER/Spring

DB connection 변화의 역사

김구황 2024. 9. 9. 00:04
728x90

1. 이유와 목적

- 고민없이 SQL을 작성하고, 의례 요청이 오면 그에 맞는 비즈니스 로직을 거쳐 DB 서버에 접속해 내용을 반환하겠거니 생각하며 코드를 작성하고 있다.

 

- 한 요청 별로 다양한 SQL 문이 실행될텐데

-> 예를 들면 로그인을 한다고 가정하면, 회원 테이블에 정보를 입력되고

-> 인증 테이블에도 정보가 입력이 되고 

-> 이력 테이블에 내용이 입력되거나 업데이트 되는 등 

 

  • 이렇게나 많은 요청이 어떻게 DB 서버와 연결되는 것이며
    • (계속해서 연결하면 자원이 심하게 쓰일텐데, 속도는?)
  • 만약 비즈니스 상황에 어떤 오류가 생길 때는 요청에 어느 부분까지가 데이터에 완전 반영되는 것이며,
    • (중간에 취소가 되면 어떤 정보는 반영이 안되어서, 정보의 불일치가 나타날 수도 있지 않을까?) 
  • 만약 이를 방지하기 위해서 어느 부분에 방지 코드를 넣어주어야 하는지에 대한 궁금함을 해결해보고 싶었다.
    • (ORM 부분에서 처리해주는 것이 있을까? 이것도 코드의 중복을 야기시키지 않을까? 간단하게 처리하는 방법은?)

 

2. DB connection의 발전 양상 

[간단한 요약]


라이브러리 읽음 > DB manager - url, password> DB driver > DB 서버 > 비즈니스 로직

비즈니스 로직> get connection - repository 주입> DB driver > DB 서버 > 비즈니스 로직 > repository

=> 여전히 비즈니스가 datasource와 연결

비즈니스 로직> (datasource 인터페이스) - repository 주입> Hikaripool > DB driver > DB 서버 > repository

트랜잭션 추상화

호출 > “트랜잭션 동기화 매니저 -커넥션 보관” > (transactionmanager 인터페이스) > (datasource 인터페이스) - repository 주입 **> Hikaripool > DB driver > DB 서버 > 비즈니스 로직 > repository

호출 > 프록시 (“트랜잭션 동기화 매니저 -커넥션 보관” > (transactionmanager 인터페이스) > (datasource 인터페이스) - repository 주입 **> Hikaripool > DB driver > DB 서버) > 비즈니스 로직 > repository

 

1) JDBC

  • 자바에서 데이터베이스에 접속할 수 있도록 도와주는 자바 API
    • 종류가 다른 서버의 드라이브들이 상속받아 사용함 => 변경할 부분이 줄어듦
  • SQL Mapper(SQL전달) / JPA Hibernate(객체전달) 를 통해서 JDBC와 연결하는 방식으로 쓰이고 있음 
  • DB서버 커넥션을 얻는 방법
    • 라이브러리에 DB서버를 등록함 
    • DriverManager (JDBC 제공) 가 설정에서 등록된 url, password 등의 정보를 가지고 드라이버 목록을 인식함 
    • 라이브러리에 등록된 Driver들이 connection 규격을 확인한 후 DB 에 접속해서 커넥션을 반환함 

Connection connection = DriverManager.getConnection(URL, USERNAME,PASSWORD);

 

https://precious-value.tistory.com/52?pidx=0



 

2) Connection Pool

 

[커넥션 발생 과정]

  • DB driver와 DB 는 TCP/IP 커넥션을 하는데, 그때 id, password 등이 전달된다 
  • DB는 내부 인증이 완료되면, 내부에 DB 세션을 생성한 후 응답하고
  • DB driver는 그 응답을 받아 커넥션 객체를 생성해 반환한다
    • 새로 커넥션을 만드는 일은 복잡하고 시간이 많이 생성되는 일
    • "커넥션을 한번에 생성해두고 사용하는 방법" 을 떠올림

 

  • "어플리케이션을 시작" 하는 시점에 커넥션 풀에 필요한 세션 (보통 10개)를 확보해둠
    • Driver가 이미 DB에서 커넥션을 확보해둔 상태
    • 의존관계가 DriverManager 에서 Conenction Pool (HikariPool)로 변경됨

 


-> JDBC API 안에 DataSource와 Driver가 속해있음
-> DriverManager/Hikari가 구현하는 JDBC는 같음
-> JDBC 인터페이스는 많은 기능을 가지고 있다


💥 의문점
- 그렇다면 JPA 와 같은 ORM 기술을 사용할 땐 HikariPool 사용하지 않는 것? 
- 여기엔 Datasource와 같은 것도 없을 텐데 

 

 

https://jiwondev.tistory.com/291

 

JDBC Connection 에 대한 이해, HikariCP 설정 팁

JDBC가 무엇인지 아예 모른다면 [10분 테코톡] 코코닥의 JDBC 영상을 한번 보고 오시면 좋습니다. 🍀 데이터베이스의 시작은 결국 JDBC 더보기 JVM을 사용한다면 스프링이건 JPA를 쓰건 결국 마지막

jiwondev.tistory.com

 

 

 

3) DataSource

  • DriverManager가 아니라 HikaripPool에서 connection을 얻고 싶은 경우에 관련 코드를 변경해야 하므로
  • DataSource라는 인터페이스를 구현하고, 이를 구현하여 Connection을 연결하도록 함 

DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
useDataSource(dataSource);

HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10);
dataSource.setPoolName("MyPool");
useDataSource(dataSource);

 

 



 

 

3. Transaction의 개념과 적용

 

[트랜잭션]

  • 데이터베이스와 Connection을 요청하면 "세션"을 DB 내부에 만듦
  • 한 세션 내에서 데이터가 변경되는 시점에는, 다른 세션에게는 변경사항이 조회되지 않아야함
  • 요청과 데이터 변화가 완료되는 연산의 묶음(거래) 을 transaction이라고 함 
  • 먼저 트랜잭션이 시작된 세션이  Lock을 획득하게 되면서 다른 세션에서 데이터를 변경하지 못하도록 함 

 

[트랜잭션의 위치]

  • 만약, 로직에 문제가 있을시 한꺼번에 취소가 되어야하므로, "비즈니스" 로직이 있는 서비스 계층에 위치해야함
public void accountTransfer(String fromId, String toId, int money) throws SQLException {
	Connection con = dataSource.getConnection(); > 커넥션 필요 
	try {
		con.setAutoCommit(false); //트랜잭션 시작
		//비즈니스 로직
		bizLogic(con, fromId, toId, money);
		con.commit(); //성공시 커밋
	} catch (Exception e) {
		con.rollback(); //실패시 롤백 << exception 뱉으면 이쪽에서 rollback
		throw new IllegalStateException(e);
	} finally {
		release(con);
	}
}


private void validation(Member toMember) {
	if (toMember.getMemberId().equals("ex")) {
		throw new IllegalStateException("이체중 예외 발생"); ** 예외가 상위로 전파 **
	}
}

 

 

[트랜잭션 추상화]

  • 만약 JDBC 기술을 더이상 사용하지 않고, JPA 기술을 사용할 경우, 코드의 변경이 많아짐 
  • 이를 위해 트랜잭션 기능을 추상화하는 TransactionManager 사용

서비스 계층에서 트랜잭션이 시작되면 트랜잭션 동기화 매니저에 보관된 커넥션을 사용하게 됨

 

💥 의문점
- JPA 도 JDBC를 구현하여 쓰는 것으로 알고 있는데 
- 여기서 JPA TransactionManager는 JDBC 구현하는 것과 별개의 일일까? 
- JDBC를 구현한 JPA는 또 다른 transactionManager 를 필요로 하는 건가? 

* JDBC의 단점을 개선하기 위해서 등장한 개념이 ORM
* ORM의 종류로는 JPA와 SQL Mapper가 있음 

지금까지 계속해서 오류가 있었던 것 같다. 
JDBC와 ORM은 엄연히 데이터를 엑세스 하는데 다른 기술이었다. 

 

https://velog.io/@murphytklee/Spring-ORM-JPA-Hibernate-JDBC-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

 

[@Transactional]

  • 서비스 계층 (비즈니스 로직) 이전에 트랜잭션 커넥션을 얻어주는 중간 객체 프록시를 도입
  • 서비스 코드에 트랜잭션 코드를 완전히 제거할 수 있음 

@Transactional
public void accountTransfer(String fromId, String toId, int money) throws SQLException {
	bizLogic(fromId, toId, money);
}