2025-04-08T19:56:24
This commit is contained in:
525
docs/34_jdbc.md
Normal file
525
docs/34_jdbc.md
Normal file
@@ -0,0 +1,525 @@
|
||||
# 스프링 부트의 JDBC
|
||||
|
||||
스프링 부트에서 JDBC(Java Database Connectivity)는 데이터베이스와의 연결을 관리하고 SQL을 실행하기 위한 기본적인 방법입니다. 스프링 부트는 `Spring JDBC` 모듈을 통해 JDBC를 추상화하여, 반복적인 보일러플레이트 코드를 줄이고 생산성을 높입니다. 특히, `JdbcTemplate` 클래스를 중심으로 간편하게 데이터베이스 작업을 수행할 수 있으며, 스프링 부트의 자동 설정 기능을 활용해 데이터소스(DataSource) 설정도 최소화할 수 있습니다.
|
||||
|
||||
JDBC는 자바 애플리케이션이 관계형 데이터베이스(RDBMS)에 접근하도록 설계된 표준 API입니다. 스프링 부트는 이를 기반으로:
|
||||
- **연결 관리**: 데이터베이스 연결 풀을 자동 설정.
|
||||
- **쿼리 실행**: SQL 실행과 결과 매핑을 단순화.
|
||||
- **예외 처리**: JDBC 예외를 스프링의 `DataAccessException`으로 변환.
|
||||
|
||||
## 의존성 추가
|
||||
스프링 부트에서 JDBC를 사용하려면 `spring-boot-starter-jdbc` 의존성을 추가합니다. 데이터베이스 드라이버도 필요합니다 (예: H2, MySQL).
|
||||
|
||||
```kotlin
|
||||
implementation("org.springframework.boot:spring-boot-starter-jdbc<")
|
||||
runtimeOnly("com.h2database:h2")
|
||||
```
|
||||
|
||||
|
||||
## `application.yaml` 설정
|
||||
데이터소스(DataSource)를 설정합니다. 스프링 부트는 기본적으로 HikariCP라는 고성능 연결 풀을 사용합니다.
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb # H2 메모리 DB URL
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
h2:
|
||||
console:
|
||||
enabled: true # H2 콘솔 활성화
|
||||
```
|
||||
|
||||
|
||||
## JdbcTemplate 사용
|
||||
`JdbcTemplate`은 스프링 JDBC의 핵심 클래스이며, SQL 실행과 결과를 처리하는 메서드를 제공합니다.
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserService(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
// 사용자 추가
|
||||
public void addUser(String name, int age) {
|
||||
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
|
||||
jdbcTemplate.update(sql, name, age);
|
||||
}
|
||||
|
||||
// 사용자 조회
|
||||
public List<User> getAllUsers() {
|
||||
String sql = "SELECT id, name, age FROM users";
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> new User(
|
||||
rs.getLong("id"),
|
||||
rs.getString("name"),
|
||||
rs.getInt("age")
|
||||
));
|
||||
}
|
||||
|
||||
// ID로 사용자 조회
|
||||
public User getUserById(Long id) {
|
||||
String sql = "SELECT id, name, age FROM users WHERE id = ?";
|
||||
return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> new User(
|
||||
rs.getLong("id"),
|
||||
rs.getString("name"),
|
||||
rs.getInt("age")
|
||||
));
|
||||
}
|
||||
|
||||
// 사용자 삭제
|
||||
public void deleteUser(Long id) {
|
||||
String sql = "DELETE FROM users WHERE id = ?";
|
||||
jdbcTemplate.update(sql, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class User {
|
||||
private Long id;
|
||||
private String name;
|
||||
private int age;
|
||||
}
|
||||
```
|
||||
|
||||
- **설명**:
|
||||
- `update()`: INSERT, UPDATE, DELETE와 같은 쓰기 작업.
|
||||
- `query()`: 여러 행을 조회하고 결과를 객체로 매핑.
|
||||
- `queryForObject()`: 단일 행을 조회.
|
||||
|
||||
|
||||
## 주요 JdbcTemplate 메서드
|
||||
|
||||
|
||||
| **메서드** | **설명** | **반환 타입** | **사용 예시** |
|
||||
|------------------------------------------------|-------------------------------------------------------------------------------------------|----------------------|-----------------------------------------------|
|
||||
| `execute(String sql)` | DDL(예: 테이블 생성)이나 단순 SQL 실행, 결과를 반환하지 않음 | `void` | `jdbcTemplate.execute("CREATE TABLE users(id INT)")` |
|
||||
| `update(String sql, Object... args)` | INSERT, UPDATE, DELETE와 같은 쓰기 작업 실행, 영향을 받은 행 수 반환 | `int` | `jdbcTemplate.update("INSERT INTO users VALUES (?, ?)", name, age)` |
|
||||
| `update(String sql, PreparedStatementSetter pss)` | PreparedStatement를 커스터마이징하여 쓰기 작업 실행 | `int` | `jdbcTemplate.update("INSERT INTO users VALUES (?, ?)", ps -> { ps.setString(1, name); ps.setInt(2, age); })` |
|
||||
| `queryForObject(String sql, Class<T> requiredType, Object... args)` | 단일 값(예: `Integer`, `String`) 조회 | `T` | `jdbcTemplate.queryForObject("SELECT count(*) FROM users", Integer.class)` |
|
||||
| `queryForObject(String sql, RowMapper<T> rowMapper, Object... args)` | 단일 행을 객체로 매핑하여 조회 | `T` | `jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"), rs.getInt("age")), id)` |
|
||||
| `query(String sql, RowMapper<T> rowMapper, Object... args)` | 여러 행을 객체 리스트로 매핑하여 조회 | `List<T>` | `jdbcTemplate.query("SELECT * FROM users", (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"), rs.getInt("age")))` |
|
||||
| `queryForList(String sql, Class<T> elementType, Object... args)` | 여러 행을 단일 값 리스트로 조회 (예: `List<String>`) | `List<T>` | `jdbcTemplate.queryForList("SELECT name FROM users", String.class)` |
|
||||
| `queryForList(String sql, Object... args)` | 여러 행을 `Map` 리스트로 조회 (컬럼명과 값 쌍) | `List<Map<String, Object>>` | `jdbcTemplate.queryForList("SELECT * FROM users")` |
|
||||
| `queryForMap(String sql, Object... args)` | 단일 행을 `Map`으로 조회 (컬럼명과 값 쌍) | `Map<String, Object>` | `jdbcTemplate.queryForMap("SELECT * FROM users WHERE id = ?", id)` |
|
||||
| `query(String sql, ResultSetExtractor<T> rse, Object... args)` | ResultSet을 커스터마이징하여 결과 처리 | `T` | `jdbcTemplate.query("SELECT * FROM users", rs -> { /* 커스텀 처리 */ return result; })` |
|
||||
| `batchUpdate(String sql, List<Object[]> batchArgs)` | 여러 행을 일괄적으로 삽입/업데이트/삭제, 각 행마다 영향을 받은 행 수 배열 반환 | `int[]` | `jdbcTemplate.batchUpdate("INSERT INTO users VALUES (?, ?)", batchArgs)` |
|
||||
| `call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)` | 저장 프로시저 호출 | `Map<String, Object>` | `jdbcTemplate.call(csc, params)` (복잡한 예시는 생략) |
|
||||
|
||||
1. **`execute`**
|
||||
- DDL(테이블 생성/삭제)이나 결과가 필요 없는 작업에 사용.
|
||||
- 예: 데이터베이스 초기화.
|
||||
|
||||
2. **`update`**
|
||||
- 데이터 쓰기 작업에 적합하며, `?` 플레이스홀더를 사용해 안전하게 파라미터 바인딩.
|
||||
- 반환값: 영향을 받은 행 수 (예: 삽입된 행 수).
|
||||
|
||||
3. **`queryForObject`**
|
||||
- 단일 값(스칼라)이나 단일 행 조회에 사용.
|
||||
- 결과가 없으면 `EmptyResultDataAccessException` 발생.
|
||||
|
||||
4. **`query`**
|
||||
- 여러 행 조회 시 `RowMapper`로 각 행을 객체로 변환.
|
||||
- 예: `User` 객체 리스트 반환.
|
||||
|
||||
5. **`queryForList`**
|
||||
- 간단한 리스트 반환에 유용 (컬럼 하나만 조회하거나 `Map`으로 결과 필요 시).
|
||||
- 예: 사용자 이름 리스트.
|
||||
|
||||
6. **`queryForMap`**
|
||||
- 단일 행의 모든 컬럼을 키-값 쌍으로 반환.
|
||||
- 결과가 없으면 예외 발생.
|
||||
|
||||
7. **`batchUpdate`**
|
||||
- 대량 데이터 삽입/업데이트 시 성능 최적화.
|
||||
- 예: `List<Object[]>`로 여러 행을 한 번에 처리.
|
||||
|
||||
8. **`call`**
|
||||
- 저장 프로시저 호출에 사용되며, 복잡한 경우에만 필요.
|
||||
|
||||
|
||||
## 데이터베이스 초기화
|
||||
스프링 부트는 `schema.sql`과 `data.sql` 파일을 통해 데이터베이스를 초기화할 수 있습니다.
|
||||
|
||||
- **`src/main/resources/schema.sql`**:
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
age INT
|
||||
);
|
||||
```
|
||||
|
||||
- **`src/main/resources/data.sql`**:
|
||||
```sql
|
||||
INSERT INTO users (name, age) VALUES ('John', 25);
|
||||
INSERT INTO users (name, age) VALUES ('Jane', 30);
|
||||
```
|
||||
|
||||
- **설정**: `spring.sql.init.mode=always`로 활성화 (`application.yaml`).
|
||||
|
||||
|
||||
## 트랜잭션 관리
|
||||
JDBC 작업에서 트랜잭션을 적용하려면 `@Transactional` 어노테이션을 사용합니다.
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserService(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void addUserWithTransaction(String name, int age) {
|
||||
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
|
||||
jdbcTemplate.update(sql, name, age);
|
||||
// 예외 발생 시 롤백
|
||||
if (age < 0) {
|
||||
throw new IllegalArgumentException("Age cannot be negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **설명**: 트랜잭션 내에서 실행되며, 예외 발생 시 롤백됩니다.
|
||||
|
||||
|
||||
## 커스텀 데이터소스 설정 (옵션)
|
||||
기본 설정 대신 수동으로 `DataSource`를 정의할 수 있습니다.
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class DataSourceConfig {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:h2:mem:testdb");
|
||||
dataSource.setDriverClassName("org.h2.Driver");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
|
||||
return new JdbcTemplate(dataSource);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 사용 예시
|
||||
```java
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserService(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
// 단일 사용자 조회
|
||||
public User findUserById(Long id) {
|
||||
String sql = "SELECT id, name, age FROM users WHERE id = ?";
|
||||
return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> new User(
|
||||
rs.getLong("id"),
|
||||
rs.getString("name"),
|
||||
rs.getInt("age")
|
||||
), id);
|
||||
}
|
||||
|
||||
// 모든 사용자 조회
|
||||
public List<User> findAllUsers() {
|
||||
String sql = "SELECT id, name, age FROM users";
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> new User(
|
||||
rs.getLong("id"),
|
||||
rs.getString("name"),
|
||||
rs.getInt("age")
|
||||
));
|
||||
}
|
||||
|
||||
// 사용자 추가
|
||||
public void addUser(String name, int age) {
|
||||
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
|
||||
jdbcTemplate.update(sql, name, age);
|
||||
}
|
||||
|
||||
// 배치 삽입
|
||||
public void batchAddUsers(List<User> users) {
|
||||
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
|
||||
List<Object[]> batchArgs = users.stream()
|
||||
.map(user -> new Object[]{user.getName(), user.getAge()})
|
||||
.collect(Collectors.toList());
|
||||
jdbcTemplate.batchUpdate(sql, batchArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class User {
|
||||
private Long id;
|
||||
private String name;
|
||||
private int age;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 스프링 부트에서 JPA와 JDBC(JdbcTemplate)의 비교
|
||||
|
||||
| **특징** | **JPA** | **JdbcTemplate** |
|
||||
|---------------------|---------------------------------------------|--------------------------------------------|
|
||||
| **접근 방식** | 객체 지향적 (ORM 기반) | SQL 중심 (직접 쿼리 작성) |
|
||||
| **추상화 수준** | 높음 (엔티티와 매핑 관리) | 낮음 (SQL과 JDBC API 추상화) |
|
||||
| **주요 클래스** | `EntityManager`, `JpaRepository` | `JdbcTemplate` |
|
||||
| **의존성** | `spring-boot-starter-data-jpa` | `spring-boot-starter-jdbc` |
|
||||
| **데이터베이스 제어**| 엔티티와 매핑으로 간접 제어 | SQL로 직접 제어 |
|
||||
|
||||
- **JPA**: 객체와 데이터베이스 테이블 간의 매핑을 통해 SQL을 자동 생성하고 관리.
|
||||
- **JdbcTemplate**: 개발자가 직접 SQL을 작성하며, JdbcTemplate이 JDBC 작업을 단순화.
|
||||
|
||||
|
||||
------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# **Spring JDBC Template의 주요 기능 설명**
|
||||
|
||||
Spring의 `JdbcTemplate`은 SQL을 더욱 간결하고 효율적으로 실행할 수 있도록 돕는 핵심적인 데이터 액세스 기술입니다.
|
||||
이 글에서는 **SQL 파라미터 바인딩(`SqlParameterSource`)**, **행 매핑(`RowMapper`)**, **간단한 JDBC 처리(`SimpleJdbc` 클래스들)**에 대해 설명하겠습니다.
|
||||
|
||||
---
|
||||
|
||||
## **1. SqlParameterSource - SQL 파라미터 바인딩**
|
||||
|
||||
일반적으로 SQL을 실행할 때 **파라미터를 바인딩**해야 합니다.
|
||||
Spring은 이를 쉽게 처리할 수 있도록 **`SqlParameterSource` 인터페이스**를 제공합니다.
|
||||
|
||||
### **✅ 주요 구현체**
|
||||
| 구현체 | 설명 |
|
||||
|--------|------|
|
||||
| `MapSqlParameterSource` | **키-값(Map) 형태**로 파라미터 바인딩 |
|
||||
| `BeanPropertySqlParameterSource` | **Java 객체(Bean)의 필드 값**을 자동으로 바인딩 |
|
||||
| `NamedParameterJdbcTemplate` | **이름 기반**(`:paramName`)으로 SQL 파라미터 바인딩 가능 |
|
||||
|
||||
---
|
||||
|
||||
### **📌 `MapSqlParameterSource` 예제**
|
||||
키-값 형태의 데이터를 SQL에 바인딩하는 방법입니다.
|
||||
|
||||
```java
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserRepository(NamedParameterJdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public void updateUserEmail(Long userId, String newEmail) {
|
||||
String sql = "UPDATE users SET email = :email WHERE id = :id";
|
||||
|
||||
MapSqlParameterSource params = new MapSqlParameterSource()
|
||||
.addValue("email", newEmail)
|
||||
.addValue("id", userId);
|
||||
|
||||
jdbcTemplate.update(sql, params);
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ **`:email`, `:id`** → **이름 기반 파라미터 바인딩**
|
||||
✔ **`MapSqlParameterSource`** → **SQL 실행 시 필요한 파라미터 전달**
|
||||
|
||||
---
|
||||
|
||||
### **📌 `BeanPropertySqlParameterSource` 예제**
|
||||
Java 객체의 필드 값을 자동으로 SQL에 바인딩하는 방법입니다.
|
||||
|
||||
```java
|
||||
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserRepository(NamedParameterJdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public void insertUser(User user) {
|
||||
String sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
|
||||
|
||||
BeanPropertySqlParameterSource params = new BeanPropertySqlParameterSource(user);
|
||||
|
||||
jdbcTemplate.update(sql, params);
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ **User 객체의 필드(`name`, `email`)**가 자동으로 SQL의 `:name`, `:email`에 매핑됨
|
||||
|
||||
---
|
||||
|
||||
## **2. RowMapper - SQL 결과를 객체로 변환**
|
||||
|
||||
데이터베이스에서 조회한 결과(ResultSet)를 **Java 객체로 변환**하는 역할을 합니다.
|
||||
Spring의 `RowMapper<T>` 인터페이스를 사용하면 **JDBC 결과를 쉽게 Java 객체로 매핑**할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
### **📌 `RowMapper` 예제**
|
||||
```java
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class UserRowMapper implements RowMapper<User> {
|
||||
@Override
|
||||
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
User user = new User();
|
||||
user.setId(rs.getLong("id"));
|
||||
user.setName(rs.getString("name"));
|
||||
user.setEmail(rs.getString("email"));
|
||||
return user;
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ `mapRow()` → **`ResultSet`에서 데이터를 읽어 `User` 객체로 변환**
|
||||
|
||||
---
|
||||
|
||||
### **📌 `RowMapper`를 활용한 Repository 예제**
|
||||
```java
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public UserRepository(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public List<User> findAllUsers() {
|
||||
String sql = "SELECT * FROM users";
|
||||
return jdbcTemplate.query(sql, new UserRowMapper());
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ `jdbcTemplate.query(sql, new UserRowMapper())` → **쿼리 결과를 `UserRowMapper`를 이용해 변환**
|
||||
✔ **결과:** `List<User>` 형태로 조회 가능
|
||||
|
||||
---
|
||||
|
||||
## **3. SimpleJdbc 클래스 - 간단한 JDBC 처리**
|
||||
|
||||
Spring에서는 **JDBC 작업을 단순화**하기 위해 `SimpleJdbc` 관련 클래스를 제공합니다.
|
||||
이들은 `JdbcTemplate`보다 **더 직관적이고 간단한 코드로 데이터베이스 작업을 처리**할 수 있습니다.
|
||||
|
||||
### **✅ 주요 클래스**
|
||||
| 클래스 | 설명 |
|
||||
|--------|------|
|
||||
| `SimpleJdbcInsert` | **INSERT 작업을 간단하게 처리** |
|
||||
| `SimpleJdbcCall` | **스토어드 프로시저(Stored Procedure) 호출을 간단하게 처리** |
|
||||
|
||||
---
|
||||
|
||||
### **📌 `SimpleJdbcInsert`를 이용한 INSERT 예제**
|
||||
```java
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
||||
private final SimpleJdbcInsert simpleJdbcInsert;
|
||||
|
||||
public UserRepository(DataSource dataSource) {
|
||||
this.simpleJdbcInsert = new SimpleJdbcInsert(dataSource)
|
||||
.withTableName("users")
|
||||
.usingGeneratedKeyColumns("id");
|
||||
}
|
||||
|
||||
public Long insertUser(String name, String email) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("name", name);
|
||||
params.put("email", email);
|
||||
|
||||
return simpleJdbcInsert.executeAndReturnKey(params).longValue();
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ `withTableName("users")` → **테이블명 지정**
|
||||
✔ `usingGeneratedKeyColumns("id")` → **자동 생성된 키(`id`)를 반환**
|
||||
|
||||
---
|
||||
|
||||
### **📌 `SimpleJdbcCall`을 이용한 스토어드 프로시저 호출**
|
||||
```java
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public class UserRepository {
|
||||
|
||||
private final SimpleJdbcCall simpleJdbcCall;
|
||||
|
||||
public UserRepository(DataSource dataSource) {
|
||||
this.simpleJdbcCall = new SimpleJdbcCall(dataSource)
|
||||
.withProcedureName("get_user_by_id");
|
||||
}
|
||||
|
||||
public Map<String, Object> getUserById(Long userId) {
|
||||
return simpleJdbcCall.execute(Map.of("user_id", userId));
|
||||
}
|
||||
}
|
||||
```
|
||||
✔ `withProcedureName("get_user_by_id")` → **스토어드 프로시저 지정**
|
||||
✔ `execute(Map.of("user_id", userId))` → **프로시저 실행 후 결과 반환**
|
||||
|
||||
---
|
||||
|
||||
## **4. 정리**
|
||||
### **✅ 주요 개념 정리**
|
||||
| 기능 | 설명 |
|
||||
|------|------|
|
||||
| `SqlParameterSource` | SQL에 안전하게 **파라미터 바인딩** |
|
||||
| `RowMapper<T>` | `ResultSet`을 **Java 객체로 변환** |
|
||||
| `SimpleJdbcInsert` | **INSERT 문을 간단하게 처리** |
|
||||
| `SimpleJdbcCall` | **스토어드 프로시저 호출을 간단하게 처리** |
|
||||
|
||||
**JdbcTemplate을 활용하면 SQL을 더욱 직관적이고 안전하게 실행할 수 있습니다! 🚀**
|
||||
Reference in New Issue
Block a user