티스토리 뷰

JDBC와 비교해보자. 과거의 JDBC 코드

import java.sql.*;

public class Main {

	public static void main(String[] args) {
	// 1) DB 연결 정보
		String url="jdbc:mysql://127.0.0.1:3306/test1";
		String username = "stdUser";
		String passwd = "wkvmtlf2";
		
        // 2) Connection 열기
		//try-with-resource라고 한다. ()예외처리 발생하는 모든 걸 계속해서 써도 된다. 여러 line
		//connection 맺었으면 
		try (Connection conn = DriverManager.getConnection(url, username, passwd)){
			//Connection conn = DriverManager.getConnection(url, username, passwd);
			System.out.println("DB연결 성공!");
		
        // 3) SELECT문 직접 입력
			//1. Select문
			String selectSql = "SELECT * FROM student";
			try(Statement stmt = conn.createStatement()){
			//selectSql 쿼리를 여기다가 넣어서 execute 실행한다.  쿼리 날려서 받아온 결과를 rs에 저장한다.
			ResultSet rs = stmt.executeQuery(selectSql);
			
			//no, dept, stdID, name, review
			while(rs.next()) {
				int no = rs.getInt("no");
				String dept = rs.getString("dept");
				String stdID = rs.getString("stdID");
				String name = rs.getString("name");
				String review = rs.getString("review");
				
				System.out.printf("No : %10d | 학과 : %10s | 학번 : %10s | 이름 : %10s | 리뷰 : %s \n", no, dept, stdID, name, review);
			}
			
			
		}
		
        // 4) INSERT문 쿼리 직접 입력
		/*
		//2. INSERT문
		String insertSql = "INSERT INTO student (no, dept, stdID, name, review) VALUES (?, ?,?,?,?)";
		//Connection conn;
		try (PreparedStatement pstmt = conn.prepareStatement(insertSql)){
			pstmt.setInt(1, 25);
			pstmt.setString(2, "컴퓨터공학과");
			pstmt.setString(3, "2176136");
			pstmt.setString(4, "박남규");
			pstmt.setString(5, "우와~~~~ jdbc 연결, 삽입 성공~~~");
			pstmt.executeUpdate();
			System.out.println("학생 정보 삽입 성공");
		}*/
		
		//3. UPDATE문
		String updateSql = "UPDATE student SET name = ?, dept = ? WHERE stdID = ?";
		try(PreparedStatement stmt = conn.prepareStatement(updateSql)){
			//바꿀 값 지정
			stmt.setString(1, "테일러");
			stmt.setString(2, "영어영문학과");
			//조건 지정
			stmt.setInt(3, 202499999);
			stmt.executeUpdate();
			System.out.println("학생 정보 업데이트 성공");
		}
		
		//4. DELETE문
		String deleteSql = "DELETE FROM student WHERE no = ?";
		try(PreparedStatement stmt = conn.prepareStatement(deleteSql)){
			stmt.setInt(1, 6);
			stmt.executeUpdate();
			System.out.println("학생 정보 삭제 성공");
		}		
		
	} catch (SQLException e) {
		e.printStackTrace();
	
	}

	}
}

 

DB 연결 정보, SQL 쿼리 직접 작성, ResultSet에서 변수 직접 꺼냈다. 

Connection, Statement, ResultSet 전부를 관리하는 코드 작성해줘야했다. 


이를 Spring Boot + JPA로 짜면 어떻게 바뀔까?

 

그 전에 JPA란?

Java Persistence API 로, 자바에서 데이터베이스와 객체(Entity)를 맵핑해주는 Object Relational Mapping 인터페이스를 의미한다.

SQL 작성 없이 Entity로 DB 다룰 수 있다.

 

1) JPA = ORM 표준(규칙)

JPA 자체가 직접 SQL 실행하는 엔진은 아니다. 

  • @Entity로 클래스 → 테이블로 매핑하는 규칙 정의
  • @Id, @Column, @OneToMany 관계 어노테이션 제공
  • 객체 저장하면 INSERT 쿼리가 나가야 한다는 규칙
  • 객체 수정하면 UPDATE가 나가야 한다는 규칙

2) Hibernate = ORM 엔진(구현체)

JPA의 규칙을 실제로 구현해서 돌아가게 하는 엔진이 Hibernate이다.

"네가 JPA로 적은 @Entity 규칙을 실제 SQL로 바꿔서 실행할게"

  • 테이블 생성 자동
  • INSERT/UPDATE/DELETE SQL 자동 생성

본격적으로 Spring Boot + JPA 로 어떻게 코드를 짰나 복기해보자.

1. heidi SQL에서 테이블을 만든다.

 

2. 이클립스에서 Spring Starter Project를 만들고, JDBC API, MariaDB Driver, Spring Data JPA, Spring Web 사용한다고 선택. 아래 사진대로 패키지를 나눈다.

 

 

3. application.properties에 DB 연결정보 추가한다.

spring.application.name=SpringBootDB-1

spring.datasource.hikari.jdbc-url=jdbc:mariadb://localhost:3306/데이터베이스 이름(test1)
//디비에서 유저네임
spring.datasource.hikari.username=stdUser
//디비에서 설정한 비밀번호
spring.datasource.hikari.password=wkvmtlf2
//MariaDB에 접속하기 위해 필요한 JDBC 드라이버 클래스 지정
spring.datasource.hikari.driver-class-name=org.mariadb.jdbc.Driver
//JPA가 실행하는 SQL쿼리 콘솔에 보이도록
spring.jpa.show-sql=true

 

4. User 클래스(테이블 이름과 똑같이 쓰는 게 좋다.)에 @Entity, @Id 어노테이션 붙여서 코드 작성

package kr.ac.ewha.java2.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String name;
	private int age;
	public User() {}  //기본생성자 반드시 넣어줌
	// ID 없이 생성자 (INSERT 시 사용)
	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}
	// 전체 필드 생성자 (UPDATE, SELECT 시 사용)
	public User(int id, String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
	// Getters and Setters
	public int getId() { return id; }
	public void setId(int id) { this.id = id; }
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	public int getAge() { return age; }
	public void setAge(int age) { this.age = age; }
}

 

5. UserRepository 인터페이스 만들고 JpaRepository 상속받기만 하자. 그러면 CRUD 자동 생성해준다!!!!!

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

}

 

6. UserService에서 UserRepository 필드로 주입받은 후 CRUD 로직 메소드 이용해서 구현

package kr.ac.ewha.java2.service;


import java.util.List;

import org.springframework.stereotype.Service;

import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.repository.UserRepository;

@Service
public class UserService {
	private final UserRepository repository;
	public UserService(UserRepository repository) {
		this.repository = repository;}
	
    // CREATE
	public User create(User user) {
		return repository.save(user);
	}
	
    // READ
	public List<User> read(){
		return repository.findAll();
	}
	
    // UPDATE: ID로 사용자 조회 후 이름과 나이를 수정
    public User update(int id, User updatedUser) {
        User user = readById(id); // 기존 사용자 조회
        if (user == null) {
            return null; // 사용자가 없으면 null 반환
        }

        // 사용자 정보 업데이트
        user.setName(updatedUser.getName());
        user.setAge(updatedUser.getAge());
        return repository.save(user); // 수정된 사용자 저장
    }
    
    // DELETE
	public void delete(int id) {
		repository.deleteById(id);
	}
}

 

7. 기존의 SpringDBController (update, delete는 생략) 서비스 호출

package kr.ac.ewha.java2.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;

@RestController
@RequestMapping("/user")
public class SpringDBController {

	private final UserService service;
	@GetMapping("/list")
	public List<User> read(){
		return service.read();
	}
	@PostMapping()
	public User create(@RequestBody User user) {
		return service.create(user);
	}
	
	// 생성자가 하나일 때 @Autowired는 생략 가능
	public SpringDBController(UserService service) {
		this.service = service;
	}
	@PostMapping("/submitForm")  //입력폼과 연결
	public User submit(@RequestParam(name="name") String name, @RequestParam(name="age") int age) {
		System.out.println(name+ ":" + age);
		return service.create(new User(name, age));
	}
}

 

8. DBConfiguration 생성 : @Configuration 설정 파일 생성

package kr.ac.ewha.java2.config;
import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
//설정 파일입니다.
@Configuration
//application.properties에 작성해놓은 DB에 대한 설정값 읽어라
@PropertySource("classpath:/application.properties")
public class DBConfiguration {
	
    //HikariConfig 라는 Bean(객체) 만든다.
	@Bean
    //application.properties 중에서 spring.datasource.hikari로 시작하는 모든 설정을 빈에 넣자.
	@ConfigurationProperties(prefix="spring.datasource.hikari")
	public HikariConfig hikariConfig() {
		return new HikariConfig();
	}
	
	@Bean
	public DataSource dataSource() throws Exception{
		System.out.println("시작!");
        //DataSource = DB 연결 관리 객체
        //hikariConfig() 설정 기반으로 DataSource를 스프링이 사용할 수 있도록 Bean 등록
		DataSource dataSource = new HikariDataSource(hikariConfig());
		//System.out.println(dataSource);
		return dataSource;
	}
}

HikariConfig 설정하고 DataSource 생성하는 걸로 설정하는 코드.

 

9. input.html 입력폼 생성

resource-static 패키지에 input.html 파일 생성(.html 꼭 붙여야한다.)

<html>
<body>
	<meta charset="UTF-8">
	<form method="post" action="http://127.0.0.1:8080/user/submitForm" accept-charset="UTF-8">
	  <input type="text" name="name" value="이름" />
	  <input type="number" name="age" value="5" />
	  <button type="submit" >보내기</button>
	</form>
</body>
</html>

 

10. SpringBootDBApplication 실행

package kr.ac.ewha.java2;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;

@SpringBootApplication
public class SpringBootDb1Application implements CommandLineRunner {

	@Autowired
	private UserService userService;
	public static void main(String[] args) {
		System.out.println("Project : Spring Boot DB start!");
		SpringApplication.run(SpringBootDb1Application.class, args);		

	}

	@Override
	public void run(String... args) throws Exception {
		System.out.println("Spring DB is running");
		List <User> users = userService.read();
		
		for (User u : users) {
			System.out.println(u.getId() + u.getName());
		}
	}
}

 

실행 결과

 

JDBC랑 SpringBoot+JPA(Java Persistence API)와 비교해보자.

기존의 JDBC

- 커넥션 직접 열고, Driver 가져오고, Statement, ResultSet 다 선언했었다.

- try-catch, try-with-resource 써서 자원 관리도 했었다.

- SQL 쿼리도 직접 작성했었다.

- 한마디로, JDBC는 모든 걸 직접 코드를 짜야 한다.

 

SpringBoot+JPA

- UserRepository 인터페이스만 만들면 자동으로 CRUD 가능하다.

- DB 연결 설정은 application.properties에만 쓰면 된다.

- Spring Boot가 DataSource 생성해주고, HikariCP 적용해주고, 연결 유지/반납 자동으로 관리해준다.

- SQL 작성 없이 Hibernate가 자동으로 SQL 생성해서 실행해준다.

- 한마디로, JDBC에선 직접 해야 할 일들을 Spring Boot에선 자동으로 해준다.

  JDBC Spring Boot + JPA
DB 연결 방식 코드에 직접 URL 세팅, username, passwd, 드라이버 설정, 커넥션 열고 닫기 DB 연결 설정 application.properties에 쓰기만 하면 Spring Boot가 DataSource 생성, HikariCP 적용해주고, 연결 관련 자원 자동 관리해준다.
SQL 작성 여부 CRUD 모두 직접 SQL 쿼리 작성해야 했다. 오타에도 취약하다. SQL 작성 안해도 Hibernate가 자동으로 SQL 생성해서 실행해준다. 오타에 덜 취약하다.
객체 맵핑 과정 ResultSet 이용해서 직접 꺼내고 객체로 변환했었다.  JPA가 자동으로 테이블을 엔티티에 매핑한다.
커넥션 관리/자원 정리 try-with-resource 로 직접 닫아야 한다. HikariCP가 자동으로 관리해준다.
구조 차이   Controller, Service(비즈니스 로직), Repository(DB CRUD), Entity(DB 매핑)

 

HikariCP란?

DB 커넥션 풀 라이브러리.

DB 연결을 미리 여러 개 만들어두고, 필요할 때 빌려 쓰고, 다시 돌려보내는 시스템 제공한다.

 

커넥션 풀이란?

db 연결은 JDBC에서도 봤던 것처럼 열고 닫으려면 자원 확보해야 하고, 커넥션, 드라이버 확보 등을 필수로 해야하는 무거운 작업이다. 요청 들어올 때마다 새로 연결 만들면 서버 터질수도... 그래서 매번 DB 연결 새로 만드는 대신, 미리 여러 개 만들어두는 개념이다.

 

HikariCP는 그중에서도 빠르고 안정적이어서 스프링 부트에서 기본으로 사용된다고 한다. 


자동화해주니 코드로 직접 짤 때 오류 날 일도 적고 신경 쓸 것들이 적어진다는 게 놀라웠다.

익숙해지면 확실히 편하다고 느낄 것 같다. 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함