✅ JPA(Java Persistence API)는 객체와 데이터베이스를 매핑하는 ORM 기술입니다. Hibernate 같은 구현체를 사용하여 SQL을 직접 작성하지 않고도 데이터베이스 연동이 가능합니다.
✅ JpaRepository 또는 EntityManager를 활용하여 CRUD 작업을 수행할 수 있습니다.
🔹 JPA 사용 예제
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}
✅ R2DBC(Reactive Relational Database Connectivity)는 비동기 & 논블로킹 방식의 데이터베이스 연동 기술로, 리액티브 프로그래밍(WebFlux 등)과 함께 사용됩니다.
✅ Flux, Mono 같은 리액티브 스트림을 통해 데이터를 효율적으로 처리할 수 있습니다.
🔹 R2DBC 사용 예제
@Repository
public interface UserRepository extends ReactiveCrudRepository<User, Long> {}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Flux<User> getUsers() {
return userRepository.findAll(); // 비동기 Flux 반환
}
}
이 질문은 두 가지 의도를 가질 수 있습니다.
✅ Spring에서 JDBC를 사용할 때 JdbcTemplate 같은 편의 기능을 활용했는지를 묻는 것입니다. Spring을 사용하면서 단순히 기존 JDBC만 사용했는지, 아니면 Spring이 제공하는 편의 기능(JdbcTemplate 등)을 활용했는지를 확인.
💡 좋은 답변 예시(Spring의 JDBC 지원 기능을 활용했을 경우):
"네, Spring에서 제공하는
JdbcTemplate을 사용하여 JDBC와 연동했습니다. JDBC의 번거로운 리소스 관리나 예외 처리를 간소화하고, SQL을 직접 작성할 수 있어 최적화가 가능하기 때문에 사용했습니다."
=> 이 답변의 의미:
JdbcTemplate)을 제공한다는 것을 알고 있다. ✅ JdbcTemplate을 사용하면 SQL을 직접 작성하면서도 Connection, Statement, ResultSet 관리가 자동화됩니다.
🔹 JdbcTemplate 사용 예제
@Autowired
private JdbcTemplate jdbcTemplate;
public List<User> getUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, (rs, rowNum) -> new User(rs.getInt("id"), rs.getString("name")));
}
✅ Spring 프로젝트에서 JDBC를 직접 쓰는 경우는 많지 않고, 대부분 MyBatis나 JPA를 사용합니다. 하지만 성능 최적화가 필요한 경우 JDBC를 직접 사용할 수도 있습니다.
그래서 면접관이 "Spring과 JDBC를 같이 썼다 = SQL을 직접 작성했다는 건가?"를 확인하고 싶었을 수도 있다.
💡 좋은 답변 예시:
"Spring과 JDBC를 직접 사용한 적은 거의 없고, 일반적으로 MyBatis나 JPA 같은 ORM을 사용했습니다. 하지만 특정 성능 튜닝이 필요한 경우
JdbcTemplate을 사용하여 직접 SQL을 작성한 경험이 있습니다."
=> 이 답변의 의미:
✅ Spring JDBC 관련 기능(JdbcTemplate)을 알고 있는지 보여주자.
✅ ORM(MyBatis, JPA)도 함께 고려했는지 설명하자.
✅ JDBC를 직접 쓴 경우라면, 그 이유(SQL 최적화, 성능 문제 해결 등)를 설명하자.
💡 좋은 대답 예시:
"보통 Spring에서는 JPA나 MyBatis 같은 ORM을 사용하지만, SQL을 직접 컨트롤할 필요가 있을 때
JdbcTemplate을 활용했습니다. 예를 들면, JPA의 N+1 문제를 피해야 할 때나, 복잡한 SQL 튜닝이 필요할 때JdbcTemplate을 사용해 최적화한 경험이 있습니다."
Spring JDBC Template은 Spring Framework에서 제공하는 JDBC(Simple JDBC) API를 쉽게 사용할 수 있도록 도와주는 유틸리티 클래스입니다.
JDBC의 복잡한 SQL 실행, 예외 처리, 커넥션 관리 등을 자동으로 처리하여 개발자의 부담을 줄여줍니다.
✅ Spring에서 JDBC를 사용할 때 JdbcTemplate을 활용하면 코드가 간결해지고 예외 처리, 리소스 관리가 자동화됩니다.
✅ 직접 JDBC 코드를 작성하면 Connection, Statement, ResultSet을 직접 관리해야 하므로 코드가 길어지고 유지보수가 어려워질 수 있습니다.
기본적인 JDBC 코드를 사용하면 다음과 같은 문제점이 있습니다.
String sql = "SELECT * FROM users WHERE id = ?";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 1);
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
System.out.println("User: " + rs.getString("name"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
🔴 문제점:
close() 호출 필요) ➡ Spring JDBC Template을 사용하면 위의 문제를 해결할 수 있음! ✅
@Autowired
private JdbcTemplate jdbcTemplate;
public List<User> getUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, (rs, rowNum) -> new User(rs.getInt("id"), rs.getString("name")));
}
🔹 개선된 점:
✅ 반복 코드 제거 (Connection, Statement, ResultSet 관리 불필요)
✅ 자동 예외 처리 (SQL 예외를 DataAccessException으로 변환)
✅ 더욱 간결한 코드
public List<User> getAllUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new User(rs.getInt("id"), rs.getString("name"))
);
}
public int getUserCount() {
String sql = "SELECT COUNT(*) FROM users";
return jdbcTemplate.queryForObject(sql, Integer.class);
}
public void addUser(String name) {
String sql = "INSERT INTO users (name) VALUES (?)";
jdbcTemplate.update(sql, name);
}
public void updateUser(int id, String name) {
String sql = "UPDATE users SET name = ? WHERE id = ?";
jdbcTemplate.update(sql, name, id);
}
public void deleteUser(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
| 비교 항목 | JdbcTemplate | MyBatis | JPA (Hibernate) |
|---|---|---|---|
| 방식 | SQL 직접 사용 | SQL 매핑(XML, 어노테이션) | ORM (객체 매핑) |
| SQL 작성 필요 | ✅ 직접 작성 | ✅ 직접 작성 | ❌ 자동 생성 (JPQL 지원) |
| 코드량 | 많음 | 중간 | 적음 |
| 자동화 수준 | 낮음 | 중간 | 높음 |
| 성능 | 높음 (SQL 최적화 가능) | 중간 | 낮음 (Lazy Loading 주의) |
| 복잡성 | 낮음 | 중간 | 높음 |
✅ JdbcTemplate: SQL을 직접 작성하고 성능 최적화가 가능하지만 코드량이 많음.
✅ MyBatis: SQL을 XML이나 어노테이션으로 관리하여 가독성이 높음.
✅ JPA: SQL 없이 객체 매핑이 가능하지만 성능 튜닝이 필요함.
➡ SQL을 직접 제어하면서 간편한 JDBC 활용을 원하면 JdbcTemplate을 사용하면 좋음! 🚀
✅ 장점
❌ 단점
✅ 장점
❌ 단점
🔹 JDBC 연동 예제 (Java & MySQL)
import java.sql.*;
public class JDBCExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
while (rs.next()) {
System.out.println("User: " + rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
✅ 장점
Flux, Mono 같은 리액티브 스트림을 통해 데이터를 효율적으로 처리. ❌ 단점
🔹 R2DBC 연동 예제 (Spring Boot & PostgreSQL)
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
@Table("users")
public class User {
@Id
private Long id;
private String name;
}
@Repository
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Flux<User> getUsers() {
return userRepository.findAll(); // 비동기 Flux 반환
}
}
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public Flux<User> getUsers() {
return userService.getUsers();
}
}
✅ 장점
❌ 단점
🔹 JPA 사용 예제 (Spring Boot & Hibernate)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getter, Setter
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
✅ 장점
❌ 단점
🔹 REST API 연동 예제 (Node.js & Express + MongoDB)
const express = require('express');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/testdb');
const UserSchema = new mongoose.Schema({ name: String });
const User = mongoose.model('User', UserSchema);
const app = express();
app.use(express.json());
app.get('/users', async (req, res) => {
const users = await User.find();
res.json(users);
});
app.listen(3000, () => console.log('Server running on port 3000'));
✅ 장점
❌ 단점
🔹 GraphQL 연동 예제 (Node.js & Apollo Server)
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type User {
id: ID!
name: String!
}
type Query {
users: [User]
}
`;
const resolvers = {
Query: {
users: () => [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
| 방식 | 특징 | 장점 | 단점 |
|---|---|---|---|
| 파일 기반(DB 직접 접근) | 로컬 파일 형태 | 간단하고 빠름 | 확장성이 낮음 |
| JDBC (SQL 직접 사용) | Java 표준 API | 세밀한 제어 가능 | SQL 직접 작성 필요 |
| R2DBC (비동기 SQL API) | 논블로킹 & 리액티브 | 높은 동시성 처리 | 기존 JDBC와 호환 안 됨 |
| ORM (JPA, Hibernate) | 객체와 DB 매핑 | SQL 없이 개발 가능 | 성능 튜닝 어려움 |
| MyBatis | SQL 매핑(XML, 어노테이션) | SQL 제어 가능 | 코드량이 많아질 수 있음 |
| REST API | API 서버와 통신 | 확장성이 높음 | API 개발 필요 |
| GraphQL | 필요 데이터만 요청 | 효율적인 데이터 조회 | 복잡한 설정 |
✅ JdbcTemplate: SQL을 직접 작성하면서도 Spring의 기능을 활용하고 싶을 때 사용
✅ JPA (Hibernate): ORM을 활용하여 데이터베이스 연동을 간소화하고 싶을 때 사용
✅ MyBatis: SQL을 직접 관리하면서도 XML/어노테이션을 활용하고 싶을 때 사용
✅ R2DBC: 비동기 환경에서 데이터베이스 연동이 필요할 때 사용