컴공댕이 공부일지

[JPA] 1장 - JPA 소개 본문

study/웹개발 스터디 백엔드 EFUB 💻

[JPA] 1장 - JPA 소개

은솜솜솜 2025. 3. 16. 21:17
728x90

본 글은 도서 '자바 ORM 표준 JPA 프로그래밍'의 1장 요약 정리본입니다.

 

 

 


 

 

 

📖 SQL을 직접 다룰 때 발생하는 문제점

객체 지향 프로그래밍과 관계형 데이터베이스의 차이로 인해 발생하는 문제

 

- JDBC API

자바에서 데이터베이스와 연결하는 표준 API
MySQL, Oracle, PostgreSQL 같은 데이터베이스와 대화할 수 있도록 해줌

 

- SQL

데이터베이스에 명령을 내리는 언어

 

쉽게 말해,

JDBC API : 자바-DB 연결
SQL : JDBC API가 연결한 DB에 명령

 

 

 

JDBC API + SQL을 사용하면?

DB는 객체 구조와 다른 데이터 중심의 구조를 가지므로, 객체를 DB에 직접 저장하거나 조회할 수 없다. 개발자가 객체지향 애플리케이션과 데이터베이스 중간에서 sql, jdbc api를 사용해서 변환 작업을 직접 해주어야 한다

 이렇게 되면, SQL을 반복적으로 직접 작성해야 해서 코드가 길어지고 유지보수가 어려움

 

또한 SQL을 직접 다루면,

1. 진정한 의미의 *계층 분할이 어렵다.

  • 애플리케이션의 서비스 계층과 DAO(데이터 접근 계층)의 경계가 모호해짐 -> 비즈니스 로직과 sql이 뒤섞인다..!! (아래 예시)
* 계층 분할 구조


1️⃣ Controller (컨트롤러 계층)
클라이언트 요청 처리, 적절한 서비스를 호출

2️⃣ Service (서비스 계층)
비즈니스 로직 처리 (SQL을 직접 작성하지 않음)

3️⃣ DAO (데이터 접근 계층)
SQL을 사용하여 데이터베이스와 직접 통신

 

///// 비즈니스 로직과 SQL이 섞인 ver /////

public class UserService {
    public List<User> getAdultUsers() throws SQLException {
        // DB 연결
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "user", "password");

        // SQL
        String sql = "SELECT * FROM users WHERE age >= 18";
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);

        // 비즈니스 로직 - 결과 가공
        List<User> users = new ArrayList<>();
        while (rs.next()) {
            User user = new User(rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
            users.add(user);
        }

        // 연결 종료
        rs.close();
        stmt.close();
        conn.close();

        return users;
    }
}
///// 비즈니스 로직과 SQL을 분리한 ver /////
// DAO 패턴 적용 -> DAO : SQL 처리만 / Service : 비즈니스 로직만

public class UserDao {
    public List<User> findAdultUsers() throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "user", "password");
        String sql = "SELECT * FROM users WHERE age >= 18";
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);

        List<User> users = new ArrayList<>();
        while (rs.next()) {
            users.add(new User(rs.getInt("id"), rs.getString("name"), rs.getInt("age")));
        }

        rs.close();
        stmt.close();
        conn.close();

        return users;
    }
}

public class UserService {
    private UserDao userDao = new UserDao();

    public List<User> getAdultUsers() {
        return userDao.findAdultUsers();  // SQL이 없는 깔끔한 비즈니스 로직
    }
}

 

2. 엔티티를 신뢰할 수 없다.

  • 엔티티가 항상 최신 상태라고 보장할 수 없음
  • 데이터 변경 사항이 반영되었는지 추적하기 어려움
  • 동일한 데이터를 여러 곳에서 다룰 경우, 일관성이 깨질 가능성이 있음

 

3. SQL에 의존적인 개발을 피하기 어렵다.

  • 새로운 기능이 추가될 때마다 SQL을 반복적으로 작성해야 함 
  • DAO 열어서 sql을 직접 확인해야함 ☹

 


 

 

위와 같은 문제들을 해결하기 위해 등장한 것이 JPA!


JPA를 사용하면 SQL을 직접 작성하지 않아도 자동으로 데이터 처리가 가능하다. JPA가 제공하는 api를 사용하면 JPA가 개발자 대신 적절한 sql을 생성해 DB에 전달한다.

///// JPA 사용해 sql 코드 자동화한 ver /////

// JPA Repository (SQL 자동 처리)
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByAgeGreaterThanEqual(int age);
}

// Service (SQL 없이 비즈니스 로직만)
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public List<User> getAdultUsers() {
        return userRepository.findByAgeGreaterThanEqual(18);
    }
}

 

 

JPA가 제공하는 CRUD API

persist() : 객체를 DB에 저장

find() : 객체 하나를 DB에서 조회

 

별도의 수정 메소드는 없으나, 객체 조회해 값을 변경하면 트랜잭션을 커밋할 때 DB에 적절한 update sql이 전달된다. - 3장에서 추후 설명

연관 객체를 사용할 때, 적절한 select sql을 실행. - 8장에서 추후 설명

 

 


 

 

 

📚 패러다임의 불일치와 JPA의 해결

객체 지향 프로그래밍(OOP)과 관계형 데이터베이스(RDBMS)의 개념 차이로 인해 발생하는 문제

 

애플리케이션은 자바라는 oop 언어로 개발하는데

데이터는 데이터 중심으로 구조화된 관계형 데이터베이스를 사용해야한다면?

-> 패러다임 불일치 문제를 개발자가 중간에서 해결해야 함 😖

 

 

 

패러다임 불일치로 인해 발생하는 문제들

 

 

1. 상속

객체지향에서 상속으로 코드의 재사용성을 높이는데, 관계형 DB에는 상속 개념이 X

 

=> JPA와 상속

개발자는 자바 컬렉션(List)에 객체 저장하듯, JPA에게 객체를 저장하면 된다.

ex ) persist 메소드로 객체 저장 -> JPA가 SQL로 insert into 해줌
find 메소드로 객체 조회 -> JPA가 두 테이블을 조인해서 필요한 데이터 조회하고 그 결과 반환

 


 

2. 연관관계

객체는 참조를 사용하지만, RDB는 외래 키(+ join)를 사용함.

 

객체는 한 객체가 다른 객체를 가르키는 것으로, 참조가 있는 방향으로만 조회가 가능한데, 테이블은 외래 키 하나만 있으면 join이 가능하다.

 

=> JPA와 연관관계

개발자는 관계를 설정(set)하고 객체를 저장(persist)하면 된다.

JPA가 알아서 외래 키를 설정하고 insert sql을 DB에 전달한다.

객체 조회할 때도, 외래키 -> 참조로 JPA가 변환 처리를 한다.


 

3. 객체 그래프 탐색

: 객체를 타고타고 따라가며 데이터를 조회하는 것. 객체의 참조를 이용하여 연관된 엔티티를 가져오는 방식

 

sql을 직접 다루게되면, 처음 실행하는 sql에 따라 객체 그래프를 어디까지 탐색할 수 있는지 정해진다.

 

=> JPA와 객체 그래프 탐색

* 지연 로딩을 활용하기 !

* 지연 로딩
해당 엔티티가 실제로 사용될 때 로딩되는 방식 

sql을 직접 사용하면, 처음 실행하는 select에서 join 여부에 따라 바로바로 가져올 데이터가 결정되는데, join없이 데이터를 가져오면 연관된 데이터는 포함되지 않아서 객체 그래프 탐색 불가능. ( 추가적인 데이터가 필요하면, 별도의 SELECT를 다시 실행해야 함 )

JPA를 사용하면, 지연 로딩을 통해 필요할 때만 추가 데이터 조회 (ORM이 객체 간의 관계를 매핑해놓았기 때문.)
필요한 시점에 추가 조회 => 보다 유연한 객체 그래프 탐색 !
=> 처음 실행하는 SQL에 영향을 받지 않고, 객체를 사용하는 시점에 적절한 select sql을 실행하는 지연 로딩 기능을 써서, 객체 그래프를 동적으로 탐색

 

 


 

4. 비교

DB - 기본 키의 값으로 각 행을 구분

객체 - 동일성 비교(==로 객체 인스터스 주소 값 비교 / 참조값), 동등성 비교(equlas 메소드로 내부 값 비교 / 내용) 2가지 방법이 존재

 

 

=> JPA와 비교 ✔

같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장

JPA는 동일한 엔티티를 조회할 때, 같은 인스턴스를 반환해서 항상 동일성 비교가 true가 되도록 해서 데이터의 일관성을 유지한다.

 

하나의 엔티티는 하나의 인스턴스로 존재해야 한다.

같은 데이터(엔티티. db의 행)가 자바 객체(인스턴스. new 키워드로 생성되는 것)로 여러 개 만들어지면 안 되고,

하나의 데이터는 하나의 객체로만 관리되어야 한다 같은 데이터가 여러 개의 인스턴스로 존재해버리면, 변경 사항을 추적하기 어려워져서 데이터 일관성 유지가 어렵다. 그래서 같은 id 가진 엔티티를 조회할 때, 항상 같은 인스턴스를 반환해야 한다 !

 

 

 


 

 

 

📝 JPA란 무엇인가?

Java Persistence API - 자바의 표준 *ORM 기술

 

 JPA : 자바 ORM 기술에 대한 API 표준 명세.

 자바에서 DB와의 상호작용을 쉽게 해주는 표준 API로, JPA를 사용하면 객체 지향 프로그래밍 방식으로 DB의 데이터를 처리할 수 있다.

 

 애플리케이션과 JDBC 사이에서 동작한다.

 

* ORM (Object-relational mapping)

객체와 관계형 DB를 자동으로 매핑하는 기술
sql을 직접 다루지 않고도 데이터 조작 가능하게, 개발자 대신 sql을 생성해서 db에 전달해줌
이에 더해, ORM 프레임워크가 객체와 테이블을 매핑해서 패러다임 불일치 문제를 개발자 대신 해결해줌.

다양한 ORM 프레임워크가 있지만, 하이버네이트 프레임워크가 가장 많이 사용됨. (대부분의 패러다임 불일치 문제를 해결해줌)

 

 

 


 

 

 

왜 JPA를 사용해야 하는가?

  • 생산성 - 컬렉션에 객체 저장하듯 JPA에 저장할 객체 전달. 
  • 유지보수 - sql과 jdbc api를 사용하는 반복 작업은 jpa가 대신 처리. 코드 줄고 패러다미 불일치 해결로 유지보수 편의
  • 패러다임의 불일치 해결
  • 성능 - 애플리케이션과 DB 사이의 jpa가 성능 최적화 기회 제공
  • 데이터 접근 추상화와 벤더 독립성
  • 표준이기 때문

 

728x90

'study > 웹개발 스터디 백엔드 EFUB 💻' 카테고리의 다른 글

[JPA] 2장 - JPA 시작  (0) 2025.03.16
Comments