공부함

Java의 DB 접근 방법 본문

데이터베이스

Java의 DB 접근 방법

찌땀 2023. 12. 11. 15:02

Java의 여러 DB 접근 방법에 대해 간단하게 알아보자

https://ittrue.tistory.com/250

 

[Java] JDBC란 무엇인가? - Java Database Connectivity

JDBC란? JDBC(Java Database Connectivity)는 Java 기반 애플리케이션의 데이터를 데이터베이스에 저장 및 업데이트하거나, 데이터베이스에 저장된 데이터를 Java에서 사용할 수 있도록 하는 자바 API이다. JDB

ittrue.tistory.com

 

JDBC

JDBC는 Java Database Connectivity이다.  Java 기반 애플리케이션과 DB간의 API이다. 즉 Java 애플리케이션이 JDBC를 사용해 DB에 연동할 수 있다. Java 프로그램 내에서 SQL문을 실행하기 위한 API이다. 

  • java.sql.Connection - 연결
  • java.sql.Statement - SQL을 담은 내용
  • java.sql.Resultset - SQL 요청 응답

JDBC는 위 3가지 기능을 표준 인터페이스로 제공한다. 

JDBC API를 사용하기 위해서는 JDBC 드라이버를 먼저 로딩해야 한다.

JDBC 장점

JDBC를 사용하지 않으면 각 DB 별로 다른 라이브러리에 맞춰 애플리케이션을 개발해야 한다. 개발자는 각 DB에 종속적인 라이브러리를 숙지해야 한다. 하지만 JDBC를 사용하면 애플리케이션에서 DB 종류에 상관없이 단일화된 API를 통해 DB에 접근할 수 있다. 즉 각 DB 별로 애플리케이션을 따로 개발할 필요 없이 JDBC 드라이버만 교체해주면 된다. 

JDBC 드라이버

JDBC 드라이버는 DB와 통신을 담당하는 인터페이스다. DB 벤더들은 JDBC API에 대한 구현을 각자 제공해야 한다. 이것을 JDBC 드라이버라고 한다. 즉 개발자가 사용하는 JDBC API의 실제 객체(즉 인터페이스의 구현체)가  드라이버에 있는 클래스들의 객체가 된다.  

 

JDBC API 동작 흐름

출처: https://ittrue.tistory.com/250

1. JDBC 드라이버 로딩 

사용하고자 하는 JDBC 드라이버를 DriverManager 클래스를 통해 로딩한다.

2. Connection 객체 생성 

JDBC 드라이버가 로딩되면 DriverManager를 통해 DB와 연결되는 세션인 Connection 객체를 생성한다.

3. Statement 객체 생성 

Statement 객체는 작성된 SQL 쿼리문을 실행하기 위한 객체다. SQL 쿼리 문자열을 입력으로 받는다.

4. Query 실행 

Statement 객체로 입력된 쿼리문을 실행한다. 

5. ResultSet 객체로부터 데이터 조회 

실행된 쿼리문에 대한 결과를 얻는다.

6. 사용한 객체들 close 

ResultSet, Statement, Connection 객체들을 close해준다. (사용된 역순)

            // JDBC 드라이버 로드
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 데이터베이스 연결
            Connection connection = DriverManager.getConnection(jdbcUrl, username, password);

            // Statement 객체 생성
            Statement statement = connection.createStatement();

            // SQL 쿼리 작성 및 실행
            String sqlQuery = "SELECT * FROM your_table";
            ResultSet resultSet = statement.executeQuery(sqlQuery);
            // select문 : executeQuery() - 추출한 값들을 ResultSet으로 리턴
            // insert, update, delete문 : executeUpdate() - 영향을 끼친 row 수 리턴
            // 모든 종류의 sql문 : execute() - 첫번째 결과가 ResultSet이면 true, 결과가 select문이 아니면 false

            // 결과 처리
            while (resultSet.next()) {
                // 결과에서 필요한 작업 수행
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                System.out.println("ID: " + id + ", Name: " + name);
            }

            // 리소스 정리
            resultSet.close();
            statement.close();
            connection.close();

커넥션 풀 

Connection 객체를 생성하는 작업은 비용이 많이 든다. 필요할 때마다 커넥션을 만들고 삭제하는 것은 시스템 부하를 늘린다. 따라서 커넥션 풀을 사용한다. 커넥션 풀은 Connection 객체를 미리 생성해서 보관하고 애플리케이션이 필요할 때 꺼내서 사용할 수 있도록 하는 것이다. 

스프링부트 2.0이후부터는 성능이 좋은 HikariCP 커넥션 풀 프레임워크를 사용한다. 

 

JDBC에서 트랜잭션 

JDBC에서 Connection 객체는 기본적으로 AutoCommit 모드가 on이다. 

AutoCommit 모드에서는 각 sql문이 트랜잭션으로 간주되며, 각 트랜잭션은 실행된 후 바로 커밋된다. 

2개 이상의 sql문을 하나의 트랜잭션으로 묶기 위해서는 아래와 같이 해준다.

Connection conn = DriverManager.getConnection();
// AutoCommit을 꺼준다
conn.setAutomCommit(false);

... sql문 실행

if (성공적) conn.commit();
else conn.rollback();

 PreparedStatement

반복되는 sql문에 대해 매번 sql문 문자열 컴파일, 명령문 실행, 결과 리턴의 과정을 반복하면 비효율적이다. 따라서 sql문을 재사용하기 위해 도입한 것이 PreparedStatement이다. PreparedStatement를 사용하면 미리 sql 질의 계획을 생성하고 실행할 때 준비해놓은 질의를 실행할 수 있다. 또한 프로그램 가독성이 좋아진다. 

Connection conn = DriverManager.getConnection();

// 생성 
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM emp WHERE id=? AND name=?");

// 파라미터 값 지정  
stmt.setString(1,"123");
stmt.setString(2,"dbman");

파라미터를 나중에 세팅하기 위한 ?가 쿼리에 있다. 1부터 시작하는 인덱스를 사용한다. 모든 파라미터를 세팅해줘야 한다. 한번 세팅한 값은 execute() 이후에도 값이 유지된다. 

CallableStatement

CallableStatement로 JDBC에서 db에 저장되어 있는 프로시저를  호출할 수 있다. 개발자는 프로시저의 이름, 입출력만 알면 된다. Connection의 prepareCall()을 통해 원하는 프로시저나 함수를 CallableStatement 객체로 생성할 수 있다.

CallabeStatement cstmt = conn.prepareCall("{call InsertEnroll(?,?,?)}");

cstmt.setString(1,s_id);
cstmt.setInt(2,c_id);
cstmt.registerOutputParameter(3,java.sql.Types.VARCHAR);
cstmt.execute();
String result = cstmt.getString(3);

https://innovation123.tistory.com/69

 

[Jdbc] JdbcTemplate 사용법 및 적용예제

JdbcTemplate이란? JdbcTemplate은 SQL을 직접 사용하여 JDBC를 다루는 편리한 방법 중 하나이다. JdbcTemplate은 JDBC를 직접 사용할 때 발생하던 여러 가지 반복 문제를 해결해 주고, 트랜잭션을 위한 커넥션

innovation123.tistory.com

JDBC template

스프링에서 JDBC 접근을 위해 쓰이는 가장 기본적인 방법 중 하나이다. 

JDBC template 장점

  1. JDBC를 사용할 때 자동으로 포함되는 spring-jdbc 라이브러리에 속해 있어서 별도의 복잡한 설정 없이 사용 가능
  2. JDBC에서 발생하는 대부분의 반복 작업 대신 처리 
  3. 개발자는 SQL을 작성하고 전달할 파라미터만 정해주면 됨
  4. 트랜잭션을 위한 커넥션 동기화, 스프링 예외 변환기 자동 실행

다만, 동적 sql을 작성하기 어렵다. 동적 sql이 아닌 간단한 sql은 JDBC template을 사용하는 것이 괜찮은 선택이다.

JDBC template 설정

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'

라이브러리 추가, DB 추가 

 application.properties

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.username=sa
spring.datasource.password=

 

datasource를 가져오기 위한 DB 접근 url, username, password 설정

의존관계 설정 

JdbcTemplate은 DataSource가 필요하다.

JdbcTemplate을 스프링 빈으로 등록한 후 주입받아도 된다.

또는 리포지토리의 생성자에서 DataSource를 주입받고 주입받은 dataSource로 생성자 내부에서 JdbcTemplate을 생성해도 된다. 관례적으로 두번째 방법을 많이 사용한다.

@Repository
public class ClubRepository{
	// 직접 JdbcTemplate 주입받기
	@Autowired
    JdbcTemplate jdbcTemplate;
    ...이하생략
}

@Repository
public class JdbcPostRepository implements PostRepository {

    private final NamedParameterJdbcTemplate template;
    
    // 생성자에서 Datasource 주입받은 후 JdbcTemplate 생성하기
    public JdbcPostRepository(DataSource dataSource){
        this.template = new NamedParameterJdbcTemplate(dataSource);
    }
    //Repository 로직 생략
}

https://ksh-coding.tistory.com/88

 

[Spring] JdbcTemplate 스프링 빈은 어떻게 자동으로 등록될까?(feat.DataSource)

❓ 해당 주제를 찾아본 이유 JdbcTemplate을 쓸 때 여러 구글링을 통해 사용 방법을 알아보게 되었다. 대부분의 사람들이 JdbcTemplate 을 주입받아서 사용하는 것이 아니라, DataSource 를 주입받아서 JdbcT

ksh-coding.tistory.com

DataSource는 DB와 관련된 커넥션 정보를 담고 있는 객체다. DB 서버와의 연결을 담당한다. 스프링이 자체적으로 생성할 수 없고, 매번 별도로 생성해 줘야 한다. 스프링 부트의 Auto Configuration 기능을 통해 application.properties에서 설정한 대로 DataSource가 스프링 빈으로 자동 등록된다. (application.properties 같은 외부 설정 파일은 스프링이 아닌 스프링 부트의 기능이다.)

DataSource가 빈으로 등록되었다고 해서 JdbcTemplate이 자동 등록되는 것은 아니다. 

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
}

spring-boot-starter-jdbc 의존성을 추가해줘야 스프링이 자동 등록된 DataSource로 JdbcTemplate을 스프링 빈으로 등록한다. 

JdbcTemplate 사용법

  • template.update()
    • INSERT, UPDATE, DELETE 문에 사용 
  • template.queryForObject()
    • 단건 데이터 조회에 사용 
    • 조회 결과가 없으면 EmptyResultDataAccessException 예외 발생 
    • 조회 결과가 둘 이상이면 IncorrectResultSizeDataAccessException 예외 발생 
  • template.query()
    • 하나 이상의 데이터 조회에 사용 
    • List<>로 반환
    • 결과가 없을 시 빈 컬렉션 반환 
  • RowMapper()
    • 데이터 조회 결과를 객체로 반환할 때 사용
    • 조회 메서드의 두번째 인자에 전달한다
    • 람다식으로 작성하기도 하고 메서드를 따로 선언해서 전달하기도 한다

활용 예시

@Repository
public class MemberRepository {
    @Autowired
    JdbcTemplate jdbcTemplate;

    public List<Member> getMembers() {
        return jdbcTemplate.query("select id, name from member", memberRowMapper());
    }

    private RowMapper<Member> memberRowMapper() {
        return (rs, rowNum) -> {
            return Member.builder()
                    .id(rs.getLong("id"))
                    .name(rs.getString("name"))
                    .build();
        };
    }
}

 

JdbcTemplate을 바로 주입받는 방식이다. RowMapper를 사용해 ResultSet을 Member 객체 형태로 변환한다. 

NameParameterJdbcTemplate 등 더 편리한 기능도 있다. 이에 관해서는 위에 첨부한 링크를 참고하자.

JPQL

https://velog.io/@jidam03/JPQL-1#%ED%8E%98%EC%9D%B4%EC%A7%95

 

JPQL-1

출처 JPA는 다양한 쿼리 방법을 지원한다. JPA를 사용하면 엔티티 객체를 중심으로 개발할 수 있다. JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리 언어 제공 SQL을 추상화했기 때문에 특정 DB SQL에

velog.io

JPQL은 Java Persistent Query Language이다. JPA에서 제공하는 SQL을 추상화한 객체지향 쿼리 언어이다. 

SQL을 추상화한 것이므로 특정 DB에 종속되지 않는다. 즉 DB에 상관없이 개발 가능하다.

SQL이 테이블을 대상으로 한다면, JPQL은 엔티티를 대상으로 한다. 

 

@Repository
public class MemberRepository {

    @Autowired
    EntityManager em;

    public List<Member> getMembers() {
        return em.createQuery("select m.id, m.name from Member m").getResultList();
    }
}

EntityManager를 통해 사용한다. Spring Data Jpa에서 메서드 위에 @Query 애노테이션을 통해 사용할 수도 있다. 

자세한 내용은 전에 김영한님 강의를 들으며 정리했던 내용(위 링크)를 참고하자. 

ORM

https://dbjh.tistory.com/77

 

[Spring JPA] JPA 란?

이번 글에서는 JPA(Java Persistence API)가 무엇인지 알아보려고한다. JPA는 자바 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용되는 인터페이스의 모음이다. 그 말은 즉, 실제적으로 구현된것이

dbjh.tistory.com

JPA전에 ORM이 뭔지 알아보자. ORM은 Object Relational Mapping이다. 애플리케이션 Class와 RDB(관계형 데이터베이스)를 매핑한다는 것이다. 

  • sql이 아닌 java 메소드로 DB를 조작할 수 있다. 개발자는 비즈니스 로직에만 신경쓰면 된다.
  • 코드 가독성이 높아진다.
  • 객체지향적인 코드 작성이 가능하다. 
  • DB 종류에 독립적이다.

JPA

JPQL이 JPA에서 제공하는 객체지향 쿼리 언어라고 했다. 그렇다면 JPA는 무엇일까?

JPA는 Java Persistence API이다. JPA는 Java에서 ORM의 기술 표준으로 사용되는 인터페이스의 모음이다. 

즉 Java 애플리케이션에서 관계형 데이터베이를 사용하는 방식을 정의한 인터페이스다.

출처 : 구글

인터페이스이므로 Hibernate, OpenJPA같은 각 기업에서 JPA를 구현한다.

JPA 장점

  • 반복적인 CRUD sql을 처리해준다. 
    • 개발자는 어떤 sql이 실행될 지 생각하고 사용하면 된다.
    • 원하면 native sql 기능으로 직접 sql을 작성할 수 있다.
  • 객체 중심으로 개발할 수 있다.
    • 생산성이 좋아지고 유지보수가 수월하다.
반복적인 CRUD SQL을 작성하고 객체를 SQL에 매핑하는데 시간을 보내기에는 우리의 시간이 너무아깝다. 이미 많은 자바 개발자들이 오랫동안 비슷한 고민을 해왔고 문제를 해결하려고 많은 노력을 기울여왔다. 그리고 그 노력의 결정체가 바로 JPA다. JPA는 표준 명세만 570페이지에 달하고, JPA를 구현한 하이버네이트는 이미 10년 이상 지속해서 개발되고 있으며, 핵심 모듈의 코드 수가 이미 십만 라인을 넘어섰다. 귀찮은 문제들은 이제 JPA에게 맡기고 더 좋은 객체 모델링과 더 많은 테스트를 작성하는데 우리의 시간을 보내자. 개발자는 SQL Mapper가 아니다.

-출처: 자바 ORM 표준 JPA 프로그래밍 / 저자: 김영한 -

참고로 Spring Data Jpa는 Jpa를 이용하는 프레임워크고 Jpa 그 자체는 아니다. 

Querydsl

Querydsl은 동적 쿼리 작성에 유용하다. 또한 컴파일 시점에 문법 오류를 확인할 수 있어 편리하다.

https://velog.io/@jidam03/series/%EC%8B%A4%EC%A0%84querydsl

 

시리즈 | 실전querydsl - 123

출처 Querydsl 설정, 검증 build.gradle에 위와 같이 추가해준다. querydsl은 qtype을 뽑아내고 그걸 가지고 쿼리를 한다 gradle > tasks > other > compileQuerydsl 더블클릭해서 qtype을 만든다. `de 2023년 8월 10일

velog.io

자세한 내용은 김영한 님 강의를 듣고 정리한 시리즈를 참고하자..ㅎㅎ