1. JDBC (Java Database Connectivity)
개념 및 동작 방식
JDBC는 자바 애플리케이션에서 관계형 데이터베이스에 연결하고 SQL 쿼리를 실행하며 결과를 처리하기 위한 표준 API입니다. JDBC를 사용하면 다양한 데이터베이스 시스템(MySQL, PostgreSQL, Oracle 등)에 독립적으로 접근할 수 있습니다.
• DriverManager: JDBC 드라이버를 로드하고 데이터베이스 연결을 관리합니다.
• Connection: 데이터베이스와의 연결을 나타내는 객체입니다.
• Statement와 PreparedStatement: SQL 문을 실행하기 위한 객체입니다.
• ResultSet: 쿼리 실행 결과를 담는 객체로, 결과 데이터를 처리할 때 사용합니다.
동작 방식:
1. 드라이버 로드: 데이터베이스에 맞는 JDBC 드라이버 클래스를 로드합니다.
2. 연결 생성: DriverManager.getConnection()을 사용하여 데이터베이스에 연결합니다.
3. SQL 실행: Statement나 PreparedStatement를 통해 SQL 문을 실행합니다.
4. 결과 처리: ResultSet을 사용하여 쿼리 결과를 처리합니다.
5. 자원 해제: close() 메서드를 사용하여 연결 및 자원을 해제합니다.
Spring Boot에서의 사용
Spring Boot에서 JDBC를 직접 사용할 수 있지만, 반복적인 코드와 예외 처리로 인해 복잡해질 수 있습니다. 아래 예시는 JDBC를 직접 사용하여 데이터베이스에 접근하는 DAO 클래스입니다.
예시 코드:
// DataSourceConfig.java
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driver;
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
config.setDriverClassName(driver);
HikariDataSource hikariDataSource = new HikariDataSource(config);
return hikariDataSource;
}
}
// UserJdbcApiDao.java
@Repository
@RequiredArgsConstructor
public class UserJdbcApiDao {
private final DataSource dataSource;
public User findById(int userId) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT * FROM \"user\" WHERE id = ?");
statement.setInt(1, userId);
resultSet = statement.executeQuery();
if (resultSet.next()) {
return new User(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"),
resultSet.getString("job"),
resultSet.getString("specialty"),
resultSet.getTimestamp("created_at").toLocalDateTime()
);
}
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "유저 정보가 존재하지 않습니다 - id : " + userId);
} catch (SQLException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스 오류", e);
} finally {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
}
}
// 다른 메서드들도 동일한 방식으로 구현
}
설명:
• DataSourceConfig 클래스에서 DataSource를 설정하여 데이터베이스 연결을 관리합니다.
• UserJdbcApiDao 클래스에서 JDBC를 사용하여 데이터베이스에 접근하고 있습니다.
• Connection, PreparedStatement, ResultSet 등을 수동으로 관리하며, 예외 처리와 자원 해제를 직접 처리해야 합니다.
장단점
장점:
• 데이터베이스와의 직접적인 연결로 인해 세밀한 제어가 가능합니다.
• 표준 JDBC API를 사용하므로 모든 자바 개발자가 이해할 수 있습니다.
단점:
• 반복적인 코드가 많아 가독성이 떨어집니다.
• 자원 관리와 예외 처리를 수동으로 해야 하므로 코드가 복잡해집니다.
• 생산성이 낮아지고 유지보수가 어렵습니다.
2. JdbcTemplate
개념 및 필요성
JdbcTemplate은 Spring Framework에서 제공하는 클래스로, JDBC의 반복적인 작업(연결, 예외 처리, 자원 해제 등)을 추상화하여 개발 생산성을 높여줍니다.
필요성:
• JDBC를 직접 사용할 때 발생하는 반복적인 코드를 줄여줍니다.
• 예외 처리를 간소화하고 일관성 있는 예외 변환을 제공합니다.
• 자원 관리를 자동으로 처리하여 코드의 안정성을 높입니다.
주요 기능
• SQL 실행 및 결과 매핑: SQL 쿼리를 실행하고 결과를 객체로 매핑합니다.
• 예외 변환: SQLException을 스프링의 DataAccessException으로 변환하여 일관된 예외 처리를 제공합니다.
• 자원 관리 자동화: Connection, Statement, ResultSet 등의 자원을 자동으로 관리합니다.
사용 예제
예시 코드:
// UserJdbcTemplateDao.java
@Repository
@RequiredArgsConstructor
public class UserJdbcTemplateDao {
private final JdbcTemplate jdbcTemplate;
public User findById(int userId) {
String sql = "SELECT * FROM \"user\" WHERE id = ?";
return this.jdbcTemplate.queryForObject(
sql,
(resultSet, rowNum) -> new User(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"),
resultSet.getString("job"),
resultSet.getString("specialty"),
resultSet.getTimestamp("created_at").toLocalDateTime()
),
userId
);
}
// 다른 메서드들도 동일한 방식으로 구현
}
설명:
• JdbcTemplate을 사용하여 SQL 쿼리를 실행하고 결과를 객체로 매핑합니다.
• 람다 표현식을 사용하여 RowMapper를 간결하게 작성합니다.
• 자원 관리와 예외 처리가 자동으로 이루어지므로 코드가 간결해집니다.
dbcTemplate은 따로 DataSource를 설정할 필요가 없음:
• DataSource 빈: 위의 데이터베이스 접속 정보를 기반으로 Spring Boot가 자동으로 생성합니다.
• 기본적으로 HikariCP를 사용하여 커넥션 풀링을 제공합니다.
• JdbcTemplate 빈: DataSource 빈이 존재하면 Spring Boot가 자동으로 생성합니다.
• EntityManagerFactory 및 TransactionManager 빈: spring-boot-starter-data-jpa 의존성이 있고, JPA 관련 설정이 존재하면 자동으로 생성됩니다.
장단점
장점:
• 코드의 간결성과 가독성이 향상됩니다.
• 자원 관리와 예외 처리가 자동으로 처리됩니다.
• 개발 생산성이 높아집니다.
단점:
• 여전히 SQL 문을 직접 작성해야 합니다.
• 객체와 데이터베이스 간의 매핑을 수동으로 처리해야 합니다.
3. JPA (Java Persistence API)
개념 및 동작 방식
JPA는 자바 객체와 관계형 데이터베이스의 테이블을 매핑하여 ORM(Object-Relational Mapping)을 구현하기 위한 표준 인터페이스입니다.
• 엔티티(Entity): 데이터베이스 테이블과 매핑되는 자바 클래스입니다.
• 엔티티 매니저(EntityManager): 엔티티의 생성, 수정, 삭제, 조회 등을 관리합니다.
• JPQL(Java Persistence Query Language): 엔티티 객체를 대상으로 하는 쿼리 언어입니다.
동작 방식:
1. 엔티티 클래스 정의: 데이터베이스 테이블과 매핑될 클래스를 정의하고 어노테이션을 사용하여 매핑 정보를 설정합니다.
2. 엔티티 매니저를 통해 작업 수행: 엔티티 매니저를 사용하여 엔티티의 생명주기를 관리하고 데이터베이스 작업을 수행합니다.
3. 트랜잭션 관리: 데이터의 일관성을 유지하기 위해 트랜잭션을 관리합니다.
ORM과 Hibernate
• ORM(Object-Relational Mapping): 객체 지향 프로그래밍의 객체와 관계형 데이터베이스의 테이블을 매핑하는 기술입니다.
• Hibernate: JPA의 대표적인 구현체로, 다양한 추가 기능과 최적화를 제공합니다. Spring Boot에서 기본적으로 사용하는 JPA 구현체입니다.
Spring Boot에서의 사용
Spring Boot에서는 Spring Data JPA를 통해 JPA를 간편하게 사용할 수 있습니다.
예시 코드:
// User.java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer age;
private String job;
private String specialty;
private LocalDateTime createdAt;
// getters and setters
}
// UserRepository.java
public interface UserRepository extends JpaRepository<User, Integer> {
// 기본적인 CRUD 메서드가 제공됩니다.
}
// UserService.java
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public User findById(int userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "유저 정보를 찾을 수 없습니다 - id: " + userId));
}
// 다른 메서드들도 동일한 방식으로 구현
}
설명:
• 엔티티 클래스에서 @Entity 어노테이션을 사용하여 데이터베이스 테이블과 매핑합니다.
• 리포지토리 인터페이스에서 JpaRepository를 상속받아 기본적인 CRUD 메서드를 사용할 수 있습니다.
• 서비스 클래스에서 비즈니스 로직을 구현하며, UserRepository를 주입받아 사용합니다.
• SQL을 직접 작성하지 않아도 되며, 메서드 이름으로 쿼리를 생성하거나 @Query 어노테이션을 사용하여 JPQL 또는 네이티브 쿼리를 작성할 수 있습니다.
장단점
장점:
• 객체 지향적인 코드 작성이 가능하여 비즈니스 로직에 집중할 수 있습니다.
• 생산성이 높아지고 유지보수가 용이합니다.
• 데이터베이스 벤더에 종속적이지 않은 코드를 작성할 수 있습니다.
단점:
• 학습 곡선이 있으며, ORM의 동작 방식을 이해해야 합니다.
• 복잡한 쿼리나 성능 최적화가 필요한 경우 직접 튜닝이 필요합니다.
• 추상화로 인해 발생하는 오버헤드를 고려해야 합니다.
4. 세 기술의 비교
기능 및 사용성 비교
특징 | JDBC | JdbcTemplate | JPA |
SQL 직접 작성 | 필요 | 필요 | 보통 필요 없음 |
코드의 간결성 | 낮음 | 중간 | 높음 |
자원 관리 | 수동 처리 | 자동 처리 | 자동 처리 |
예외 처리 | 수동 처리 | 자동 처리 | 자동 처리 |
학습 난이도 | 낮음 | 낮음 | 높음 |
생산성 | 낮음 | 중간 | 높음 |
객체-관계 매핑 | 수동 매핑 | 수동 매핑 | 자동 매핑 |
언제 어떤 것을 선택해야 하는지
• JDBC:
• 데이터베이스에 대한 세밀한 제어가 필요한 경우
• 직접 SQL을 작성하고 최적화해야 하는 경우
• 작은 규모의 애플리케이션이나 간단한 작업에 적합
• JdbcTemplate:
• JDBC의 반복적인 코드를 줄이고 싶을 때
• SQL은 직접 작성하되, 자원 관리와 예외 처리를 자동화하고 싶은 경우
• 중간 규모의 애플리케이션에 적합
• JPA:
• 객체 지향적인 방식으로 데이터베이스를 다루고 싶은 경우
• 생산성과 유지보수성을 높이고 싶은 경우
• 대규모 애플리케이션이나 복잡한 비즈니스 로직이 필요한 경우
5. 결론
Spring Boot를 통해 데이터베이스와 연결할 때 JDBC, JdbcTemplate, JPA 세 가지 방법을 사용할 수 있습니다. 각 기술은 고유한 장단점이 있으며, 프로젝트의 요구사항과 규모, 팀의 역량에 따라 적절한 기술을 선택해야 합니다.
• JDBC는 데이터베이스에 대한 세밀한 제어가 가능하지만, 반복적인 코드와 자원 관리로 인해 생산성이 낮습니다.
• JdbcTemplate은 JDBC의 단점을 보완하여 코드의 간결성과 생산성을 높여주지만, 여전히 SQL을 직접 작성해야 합니다.
• JPA는 객체 지향적인 방식으로 데이터베이스를 다룰 수 있어 생산성과 유지보수성이 높지만, 학습 곡선이 있고 성능 최적화에 신경 써야 합니다.
제공해주신 예시 코드를 통해 JDBC와 JdbcTemplate의 사용 방법을 살펴보았습니다. JPA를 사용하면 더 간결하고 유지보수하기 쉬운 코드를 작성할 수 있으므로, 프로젝트의 특성에 맞게 기술을 선택하시기 바랍니다.
추가로 궁금하신 사항이나 도움이 필요한 부분이 있으시면 언제든지 말씀해주세요!
'spring' 카테고리의 다른 글
[Spring] JdbcTemplate (0) | 2024.11.22 |
---|---|
[Spring] JDBC (0) | 2024.11.22 |
[Spring] JdbcTemplate과 일반 JDBC 코드의 차이점 (1) | 2024.11.19 |
[Spring] 예시를 통한 BaseResponse 학습하기 (0) | 2024.11.07 |
[Spring] RuntimeException을 통한 CustomException (0) | 2024.10.31 |