JPA는 백엔드 개발하는 사람이라면 다들 써봤을 것이다.
그럼, 다른 사람이 JPA가 뭔가요? 왜 쓰나요? 라는 질문을 받았다면 잘 설명할 수 있을까?
실제로 동기가 JPA에 대해 물어봤는데, 나 역시 사용하는 법만 알지 JPA가 정확히 무엇이고 왜 사용하는지 몰랐다.
JPA를 알기 전 ORM에 대해 알아보자.
ORM이란 Object-Relational Mapping의 약자로 직역을 해보자면, 객체 관계 맵핑이라는 뜻이 있다. 이는 객체는 객체대로 설계하고 RDB는 RDB대로 설계할 수 있게 맵핑시켜주는 것을 말한다.
JPA는 현재 자바 진영의 ORM 기술 표준, 인터페이스의 모음이다.
인터페이스의 모음이기 때문에 구현체가 필요하며 이를 구현한 오픈소스는 Hibernate가 대표적이다. 그 외에도 EclipseLink, DataNucleus가 있는데 이 중 하나를 사용해서 개발하면 된다.
그리고 JPA는 인터페이스이기 때문에, 개발자가 직접 JPA 구현체를 만들어서 사용할 수 있다.
JPA는 ORM 역할을 하기 때문에 애플리케이션과 JDBC 사이에 동작한다.
그래서 개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하고 DB와 통신을 대신 해준다.
// DBUtil.java - DB 연결하는 코드
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/database_name";
private static final String USER = "username";
private static final String PASSWORD = "password";
public static Connection getConnection() throws SQLException {
try {
// MySQL JDBC 드라이버 로딩
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (ClassNotFoundException e) {
throw new SQLException("JDBC 드라이버를 찾을 수 없습니다.", e);
}
}
}
// DAO.java
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserDAO {
// 사용자 목록 조회
public List<User> getAllUsers() {
List<User> users = new ArrayList<>();
String sql = "SELECT * FROM users";
try (Connection connection = DBUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String email = resultSet.getString("email");
users.add(new User(id, username, email));
}
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
// 특정 사용자 조회 (ID로)
public User getUserById(int id) {
User user = null;
String sql = "SELECT * FROM users WHERE id = ?";
try (Connection connection = DBUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, id);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
String username = resultSet.getString("username");
String email = resultSet.getString("email");
user = new User(id, username, email);
}
} catch (SQLException e) {
e.printStackTrace();
}
return user;
}
}
JPA를 사용하기 전에는 이런 식으로 DB와 연결을 해주고 DAO(Data Access Object)를 만들어서 원하는 쿼리를 실행한다.
나는 개인적으로 Java코드에는 Java만 있어야 마음이 편하기 때문에 조금 불편한 감이 없이 않아 있다.
# MySQL 데이터베이스 연결 설정 == DBUtil.java
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
// Repository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
// 사용자 조회를 위한 추가적인 메서드를 정의할 수 있습니다.
User findByUsername(String username);
}
// Service.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 모든 사용자 조회
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 사용자 ID로 조회
public User getUserById(int id) {
return userRepository.findById(id).orElse(null);
}
// 사용자 이름으로 조회
public User getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
}
JPA로 변경된 코드를 보면 DBUtil.java는 properties에 설정을 하고 따로 객체를 만들지 않는다. 그리고 쿼리문이 포함되어 있던 DAO역시 JpaRepository를 상속받는 인터페이스로 대체된다.
그리고 사용하는 방법은 보통 Service 단에서 인터페이스 메서드를 실행해서 사용한다.
이러한 이유로 JPA를 사용하는 편이다. 특히, 느슨한 결합도가 코드 유지보수의 핵심이라고 생각한다.
사용하는 이유와 내포된 장점을 알아봤는데, 마냥 좋은 것만 있는 것은 아니다.
요즘에 크게 와 닿는 점은, 결국 SQL문을 쓰는게 더 편한거 같은데? 라는 생각이 종종 든다.
이유는 정말로 SQL문이 편한 것도 있지만, 아직 JPA를 완벽하게 알지 못하기 때문인 것 같다.