[Spring] 스프링 DB 접근(JDBC,JdbcTemplate,JPA,스프링 데이터 JPA)

2025. 1. 12. 23:48·Spring

H2 데이터베이스


개발이나 테스트 용도로 가볍고 편리한 DB, 웹 화면 제공 (실무에선 MySQL, Oracle 많이씀)

설치


> https://www.h2database.com

 

H2 Database Engine (redirect)

H2 Database Engine Welcome to H2, the free SQL database. The main feature of H2 are: It is free to use for everybody, source code is included Written in Java, but also available as native executable JDBC and (partial) ODBC API Embedded and client/server mo

www.h2database.com

1. 설치 후 "설치폴더>bin"경로로 터미널 열기

 

2. 권한 주기(Mac)

chmod 755 h2.sh

3. 실행

./h2.sh   //(Mac)
h2.bat    //(Window)

 

4. H2콘솔창 뜨면 끝

데이터베이스 파일 생성


1. 위사진대로 연결(JDBC URL:jdbc:h2:~/test 최초 한번)

2. 터미널로 홈에 파일 '~/test.mv.db' 생성됐는지 확인

3. 이후 부턴 JDBC URL: jdbc:h2:tcp://localhost/~/test 로 접속 (파일 직접 접근아닌 소켓통한 접근) 이래야 여러곳에서 접근가능

 

테이블 생성


create table member(
    id   bigint generated by default as identity,
    name varchar(255),
    primary key (id)
)

 

Long = bigint

generated by default as identity : 값없이 insert하면 디비 자동 증가번호 할당

GENERATED ALWAYS AS IDENTITY: 오직 자동 증가 값만 사용 가능 (사용자값입력x)

 

*따로 최상위에 sql폴더,ddl.sql파일만들어 관리하면 좋음

 

순수 JDBC


고전에 쓰던 서버와 DB 연결 방식으로, 직접 SQL을 작성하고 수동으로 리소스를 관리해야 하는 방식

(가볍게 보자...)

-build.gradle에 라이브러리 추가

implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2' // H2 데이터베이스 (테스트용 내장 DB)

 

-resources/application.properties 에 스프링 부트 데이터베이스 연결 설정 추가 (밑에 자세히 설명)

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver //빨간색이뜬다면build.gradle 새로고침
spring.datasource.username=sa

 

-Jdbc 리포지토리 구현(JdbcMemberRepository) --생략

-스프링 설정 변경

import hello.hello_spring.repository.JdbcMemberRepository;
import hello.hello_spring.repository.MemberRepository;
import hello.hello_spring.repository.MemoryMemberRepository;
import hello.hello_spring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class SpringConfig {

    private final DataSource dataSource;

    public SpringConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
//        return new MemoryMemberRepository();
        return new JdbcMemberRepository(dataSource);
    }
}

 

 

JdbcTemplate


순수JDBC로 만들기 힘들어 jdbc템플릿 또는 MyBatis 이용

이를 통해 반복 코드를 대부분 제거 but, SQL은 직접 작성

 

 

-build.gradle에 라이브러리 추가

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

 

-resources/application.properties 에 스프링 부트 데이터베이스 연결 설정 추가

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

application.properties에 DB 정보를 입력하면 자동으로 DataSource를 빈등록생성
@Autowired 또는 생성자 주입으로 사용

 

-JdbcTemplateMemberRepository

public class JdbcTemplateMemberRepository implements MemberRepository {

    private final JdbcTemplate jdbcTemplate; // JdbcTemplate 객체

    //@Autowired 생략가능
    public JdbcTemplateMemberRepository(DataSource dataSource) { //DataSource(DB와 연결 관리 객체) 주입
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public Member save(Member member) {
        //걍 가볍게 보기
        //SimpleJdbcInsert: JDBC에서 쿼리작성없이 INSERT 문을 쉽게 실행하게 해주는 클래스
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        //insert할 테이블 지정, 자동 생성되는 키 컬럼 지정
        jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
        //INSERT할 값 설정
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", member.getName());
        //INSERT 실행 + 자동 생성된 키 값 가져오기
        Number key = jdbcInsert.executeAndReturnKey(new
                MapSqlParameterSource(parameters));
        member.setId(key.longValue());

        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        //jdbcTemplate.query(SQL, RowMapper: 쿼리결과데이터를 자바객체에 매핑, ?에 들어갈 파라미터) <-List 반환
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(),id);
        return result.stream().findAny();

    }

    @Override
    public List<Member> findAll() {
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    }

    private RowMapper<Member> memberRowMapper() {
        return new RowMapper<Member>() { //opt엔터로 람다 바꿀수 있음
            @Override
            public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
                //rs → 쿼리 결과 행(row)의 데이터, rowNum → 행의 인덱스
                Member member = new Member();
                member.setId(rs.getLong("id"));// 현재 row에서 "id" 값을 Long 타입으로 가져옴
                member.setName(rs.getString("name"));// 현재 row에서 "name" 값을 String 타입으로 가져옴
                return member;
            }
        };
    }
//    private RowMapper<Member> memberRowMapper() {
//        return (rs, rowNum) -> {
//            Member member = new Member();
//            member.setId(rs.getLong("id"));
//            member.setName(rs.getString("name"));
//            return member;
//        }
//    }

}

 

-스프링 설정 변경

@Bean
public MemberRepository memberRepository() {
    //return new MemoryMemberRepository();
    //return new JdbcMemberRepository(dataSource);
    return new JdbcTemplateMemberRepository(dataSource);
}

MyBatis 참고

더보기

1. pom.xml에 MyBatis-Spring Boot Starter 추가 (SqlSessionFactory, SqlSessionTemplate을 생성) <- MyBatis는 이를통해 DataSource 주입함

-Maven

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.3.0</version> <!-- 최신 버전 확인 필요 -->
</dependency>
<!-- MySQL -->
//<dependency>
//    <groupId>mysql</groupId>
//    <artifactId>mysql-connector-java</artifactId>
//    <scope>runtime</scope>
//</dependency>
<!-- Oracle -->
//<dependency>
//    <groupId>com.oracle.database.jdbc</groupId>
//    <artifactId>ojdbc8</artifactId>
//    <version>19.8.0.0</version> <!-- 버전 확인 필요 -->
//</dependency>

 

-gradle

implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0'
runtimeOnly 'mysql:mysql-connector-java:8.0.25'
#implementation 'mysql:mysql-connector-java:8.0.25' // MySQL사용할 경우.최신 버전 확인 필요
#implementation 'com.oracle.database.jdbc:ojdbc8:19.8.0.0' //Oracle. 버전 확인 필요

 

2. DB 설정 (application.properties) 

# Oracle 사용 시
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=root
spring.datasource.password=1234

# MySQL 사용 시
# spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# spring.datasource.url=jdbc:mysql://localhost:3306/dbname
# spring.datasource.username=root
# spring.datasource.password=1234

mybatis.mapper-locations=classpath:database/mappers/*Mapper.xml
mybatis.config-location=classpath:database/config/MybatisConfig.xml

DataSource가 자동 주입됨

 

3. Mapper 인터페이스 사용 (자동으로 MyBatis 연동됨)

@Mapper
public interface UserMapper {
     ArrayList<HashMap<String, Object>> findAll();
}

 

4.  Mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.app.mapper.UserMapper"> //Mapper 인터페이스 지정
    <select id="findAll" resultType="HashMap"> //Mapper 인터페이스의 메서드명과 id 동일
        select * from member
	</select>
</mapper>
    parameterType="Pagination"
    #{code}

 

JPA


SQL도 JPA가 직접 만들어 실행해 객체를 바로 DB에 저장하고 관리할 수 있도록 도와주는 기술로, 개발 생산성을 높이고 객체 중심 설계를 가능

-build.gradle에 라이브러리 추가

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

추가 시 자동 EntityManagerFactory 빈 등록됨 이를통해 EntityManager생성되고

@Autowired private EntityManager em;통해 자동주입됨

 

-resources/application.properties 스프링부트에 JPA 설정 추가

spring.jpa.show-sql=true  //JPA가 실행하는 SQL 쿼리를 콘솔에 출력
spring.jpa.hibernate.ddl-auto=none //테이블 자동으로 생성 기능
//create하면 테이블도 자동으로 만들어줌

 

- domain/Member

import jakarta.persistence.*;

@Entity //JPA가 관리하는 엔티티 표현
public class Member {

    @id //기본 키(PK) 지정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // DB가 자동으로 ID 생성
    private Long id;

    //@Column(name = "username") //컬럼명 (테이블의 "username"이라는 컬럼과 매핑)
    private String name;
    ...

 

*@GeneratedValue

기본 키 값을 자동으로 생성 방법 지정, @Id와 함께 사용

GenerationType.AUTO 사용 중인 DB에 맞게 자동 선택
GenerationType.IDENTITY MySQL, MariaDB 등에서 사용하는 AUTO_INCREMENT 방식
GenerationType.SEQUENCE Oracle, PostgreSQL 등에서 사용하는 시퀀스(Sequence) 기반 자동 증가
GenerationType.TABLE 별도의 키 생성용 테이블을 만들어 ID 관리 (잘 사용되지 않음)

 -JpaMemberRepository

public class JpaMemberRepository implements MemberRepository{

    private final EntityManager em; //jpa EntityManager를 통해 동작

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    }

    @Override
    public Member save(Member member) {
        em.persist(member); //INSERT
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        //= SELECT * FROM Member WHERE id = ?;
        //pk통한 단일 조회,(조회할 타입,식별자pk)
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    @Override
    public Optional<Member> findByName(String name) {
        //나머지 조회. JPA Query Language 객체제한 쿼리언어
        // 테이블아닌 객체(엔티티)대상 쿼리날림 이걸 sql로 번역됨. select *이 아닌 엔티티자체(m) 셀렉트
        List<Member> result = em.createQuery("select m from  Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList(); //SELECT결과 여러 개일 때 리스트로 반환

        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        return em.createQuery("select m from member m",Member.class)
                .getResultList(); //여러개 결과 받을 때
    }
}

 

더보기
INSERT em.persist(member)
INSERT INTO Member (name) VALUES ('홍길동');
SELECT
(pk로 하나만 조회)
em.find(Member.class(), id) //(조회할 타입, 식별자pk)
SELECT * FROM Member WHERE id = ?;
SELECT
(나머지)
createQuery("SELECT m FROM Member m WHERE m.name = :name")
em.createQuery("select m from member m",Member.class) .getResultList();​
SELECT id, name FROM Member WHERE name = '홍길동';
UPDATE (변경 감지) member.setName("이순신")
UPDATE Member SET name = '이순신' WHERE id = ?;
UPDATE (JPQL 직접 실행) createQuery("UPDATE Member m SET m.name = :name WHERE m.id = :id")
UPDATE Member SET name = '이순신' WHERE id = ?;
DELETE em.remove(member)
DELETE FROM Member WHERE id = ?;
DELETE (JPQL 직접 실행) createQuery("DELETE FROM Member m WHERE m.id = :id")
DELETE FROM Member WHERE id = ?;

 

- 서비스 계층에 트랜잭션 추가

import org.springframework.transaction.annotation.Transactional

@Transactional
public class MemberService {}

해당 클래스 메서드를 실행할 때 트랜잭션 시작, 메서드가 정상 종료되면 트랜잭션 커밋, 런타임 예외가 발생하면 롤백

 

JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야함.

  

-스프링 설정 변경

private final EntityManager em;
@Autowired
public SpringConfig(EntityManager em) {
    this.em = em;
}

@Bean
public MemberRepository memberRepository() {
//        return new MemoryMemberRepository();
//        return new JdbcMemberRepository(dataSource);
//        return new JdbcTemplateMemberRepository(dataSource);
    return new JpaMemberRepository(em);
}

 

스프링 데이터 JPA


JPA를 더 편리하게 쓸수 있도록 한번 감싼 기술(그래서 JPA를 잘알아야함)

레포지토리에 구현 클래스 없이 인터페이스 만으로 개발가능

 

-JPA 설정을 그대로

 

-SpringDataJpaMemberRepository(인터페이스)

public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
    //JpaRepository는 JPA에서 기본적인 CRUD 기능(findByIde등 메서드)을 제공하는 인터페이스, <엔티티 클래스, pk타입>
    //이를 상속한 인터페이스는 Spring Data JPA가 자동으로 구현체를 생성하고, 이를 Spring Bean으로 등록

    @Override
    Optional<Member> findByName(String name);
}

-스프링 설정 변경

@Configuration
public class SpringConfig {

    private final MemberRepository memberRepository;
    
    @Autowired // 스프링 컨테이너에서 멤버 레포지터리 찾음
    public SpringConfig(MemberRepository memberRepository) {
    	this.memberRepository = memberRepository;
    }
    
    @Bean
    public MemberService memberService() {
    return new MemberService(memberRepository);
    }
}

 

*스프링 데이터 JPA 제공 기능

  • 인터페이스를 통한 기본적인 CRUD
  • findByName(), findByEmail() 처럼 메서드 이름 만으로 조회 기능 제공
  • 페이징 기능 자동 제공

참고: 복잡한 동적 쿼리는 Querydsl이라는 라이브러리 사용함

 

'Spring' 카테고리의 다른 글

[Spring] 스프링 개요, SOLID, DI 컨테이너 💡  (0) 2025.01.31
[Spring] AOP(Aspect-Oriented Programming)  (0) 2025.01.22
[Spring] From 입력, 조회  (0) 2024.12.22
[Spring] 스프링 빈 등록과 의존관계  (0) 2024.12.19
[Spring] 웹 계층 구조, Test  (0) 2024.12.17
'Spring' 카테고리의 다른 글
  • [Spring] 스프링 개요, SOLID, DI 컨테이너 💡
  • [Spring] AOP(Aspect-Oriented Programming)
  • [Spring] From 입력, 조회
  • [Spring] 스프링 빈 등록과 의존관계
Naah
Naah
  • Naah
    blueprint
    Naah
  • 전체
    오늘
    어제
    • 분류 전체보기 (106)
      • Java (28)
      • Kotlin (0)
      • TypeScript (7)
      • React (22)
      • Next.js (1)
      • Spring (22)
      • JPA (12)
      • Spring Data JPA (6)
      • Querydsl (1)
      • Error (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
    • manage
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Naah
[Spring] 스프링 DB 접근(JDBC,JdbcTemplate,JPA,스프링 데이터 JPA)
상단으로

티스토리툴바