๋ ผ๋ฆฌ์ ์ฐ๊ฒฐ / ๋ฌผ๋ฆฌ์ ์ฐ๊ฒฐ
๐ DB์ Java ์ ํ๋ฆฌ์ผ์ด์ ์ฐ๊ฒฐ ๋ฐ DB ์ฟผ๋ฆฌ ์ํํ๊ธฐ
Java ์ ํ๋ฆฌ์ผ์ด์ ์ JVM ์์์ ์คํ๋๋ฉฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋ณ๋์ ์์คํ ์ด๋ค. ์ด๋ฅผ ์ฐ๊ฒฐํ๊ธฐ ์ํด์ ๋ค์ ๋ ๋จ๊ณ๋ฅผ ๊ฑฐ์น๋ค.
1๏ธโฃ DB ์ฐ๊ฒฐ
Java ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํต์ ํ๊ธฐ ์ํด์ ๋จผ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ํด์ผ ํ๋ค.
Java์์์ DB ์ ์์ ๋ฌผ๋ฆฌ์ ์ ์ ๋ ผ๋ฆฌ์ ์ ์ ๋ ๋ฐฉ์ ์ค ํ๋๋ฅผ ์ ํํ๋ค.
- ๋ฌผ๋ฆฌ์ ์ ์์ ๋งค ์ ์ ๋๋ง๋ค DB์ ์ง์ ๋ถ๋ ๊ฒ์ผ๋ก Create์ Close๋ฅผ ๋ฐ๋ณตํ๋ค.
- ๋ ผ๋ฆฌ์ ์ ์์ ๋งค ์ ์ ๋๋ง๋ค DB์ ์ ์๋์ด ์๋ Connection Pool ์ค ํ๋๋ฅผ ์ฌ์ฉ ํ ๋ฐํํ์ฌ ์ฌ์ฌ์ฉํ๋ค.
1-1. ๋ฌผ๋ฆฌ์ ์ ์ (DriverManager)
DriverManger๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ ์(Connection)์ ์์ฑ(Create)ํ๊ณ ์ฟผ๋ฆฌ ์ํ ํ ์ข ๋ฃ(Close)ํ๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ
- Driver๋ฅผ ํตํด Connection ์์ฑ
- ์ฟผ๋ฆฌ๋ฅผ ์ํํ Statement ๋๋ PreparedStatemenet ์์ฑ
- ์ฟผ๋ฆฌ ์คํ ํ ๋ฐํ๋ ResultSet ์ฒ๋ฆฌ
- ๋ชจ๋ ์์(Connection, Statement, ResultSet) ์ข ๋ฃ
// 1) ์ ์๊ณผ ๋์์ Connection์ ๋ฐํํ๋ ์ฝ๋
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
- JDBC API๋ 3๊ฐ๋ก ๊ตฌ์ฑ๋์ด ์๋ค. Connection ์ ์ → Statement ์ฟผ๋ฆฌ→ ResultSet ๊ฒฐ๊ณผ
- ์ด ์ค Connection ์ ์ ์ DriverManager ์ฌ์ฉํ๋ฉด ๋ฌผ๋ฆฌ์ ์ ์(Create-Close ๋ฐ๋ณต)
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM \"user\" WHERE id = " + userId);
if (resultSet.next()) {
return new User(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"),
resultSet.getString("job"),
resultSet.getString("specialty"),
resultSet.getDate("createAt")
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
)
};
API ๋ก์ง ๋ณ๊ฒฝ
์์ฒ๋ผ ๋ฌผ๋ฆฌ์ ์ ์์ผ๋ก JDBC๋ฅผ ์ฐ๊ฒฐํ๋ค๋ฉด, ๊ธฐ์กด UserService์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค.
๊ธฐ์กด UserService๋ Map ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ ์ ์ ์กฐํ findByID ๊ตฌํ์ฒด์ด๊ธฐ ๋๋ฌธ์ JDBC API๋ก ๊ต์ฒดํ๋ ์์ ์ด ํ์ํ๋ค.
- ๋ณ๊ฒฝ ์ ๋ก์ง
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public UserResponseDto findById(Integer id) {
User user = userRepository.findById(id);
return UserResponseDto.from(user);
- ๋ณ๊ฒฝ ํ ๋ก์ง
public class UserService {
private final UserRepository userRepository;
private final UserJdbcApiDao userJdbcRepository;
public UserResponseDto findById(Integer id) {
try {
User user = userJdbcRepository.findById(id);
return UserResponseDto.from(user);
} catch (SQLException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"์์ ๋ฐ๋ฉ ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.");
}
}
1-2. ๋ ผ๋ฆฌ์ ์ ์ (DataSource)
DataSource๋ Connection Pool์ ์ด์ฉํ์ฌ ๋ฏธ๋ฆฌ ์์ฑ๋ Connection์ ์ฌ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก ๋ ผ๋ฆฌ์ ์ ์์ ์ ๊ณตํ๋ค.
ํน์ง
- ๋งค๋ฒ Connection์ ์๋ก ์์ฑํ์ง ์์ ์ฑ๋ฅ ํฅ์
- ์ฌ์ฉ ํ Connection์ Pool๋ก ๋ฐํ
์ค์ ๋ฐฉ๋ฒ
- HikariCP(Spring Boot ๊ธฐ๋ณธ Connection Pool)๋ฅผ ์ค์ ํ์ฌ DataSource ์์ฑ
- Connection์ Pool์์ ๊ฐ์ ธ์ ์ฌ์ฉ ํ ๋ฐํ
// 0.1) DataSource ์ค์
HikariConfig config = new HikariConfig();
config.setJdbcUrl(URL);
config.setUsername(USER);
config.setPassword(PASSWORD);
config.setDriverClassName("com.mysql.cj.jdbcDriver");
config.setMaximumPoolSize(20);
config.setMinimumIdel(10);
// 0.1) DataSource ์์ฑ
HikariDataSource hikariDataSource = new HikariDataSource(config);
// 1) ์ ์์ Connection Pool์์ ๊ฐ์ ธ์ค๋ ์ฝ๋
Connection connection = hikariDataSource.getConnection();
- `setConnectionTimeout(30000)`: ์ปค๋ฅ์ ์ ์ป๊ธฐ ์ํด ๋๊ธฐ ์ค์ ํด๋น ์๊ฐ์ด ๋ง๋ฃ๋๋ฉด ์์ธ ๋ฐ์
- `setMinimumIdel(10)`: ์ฌ์ฉ์ ์ํด ์ปค๋ฅ์ ํ์ ์ ์งํด ๋์ ์ปค๋ฅ์ ์ (IDLE)
- `setMaximumPoolSize(20)`: Connection Pool ์ต๋ ์ปค๋ฅ์ ์ ์ค์
DataSource Bean ๊ฐ์ฒด๋ฅผ ์ฃผ์ ๋ฐ์ Connection ์ ์ ๊ฐ์ฒด๋ฅผ ์ทจ๋
- common/DatasourceConfing
@Configuration
public class DataSourceConfig {
@Value("jdbc:postgresql://localhost:54322/example?useSS...")
private String url;
@Value("asac")
private String username;
@Value("1234")
private String password;
@Value("org.postgresql.Driver")
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;
}
}
- service/UserJdbcApiDao
@Slf4j
@Repository
@RequiredArgsConstructor
public class UserJdbcApiDao {
private final DataSource dataSource;
public User findById(int userId) throws SQLException {
Connection connection = null; // 1
Statement statement = null; // 2
ResultSet resultSet = null; // 3
try {
connection = dataSource.getConnection(); // 1
statement = connection.createStatement(); // 2
resultSet = statement.executeQuery( // 3
"SELECT * FROM \"user\" WHERE id = " + userId
);
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")
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
);
}
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
"์ ์ ์ ๋ณด๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค - id : " + userId);
} catch (SQLException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
"์์์ ๋ํ ์ ๊ทผ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.");
} finally {
// ์์ ๋ฐ๋ฉ
if (resultSet != null) {
resultSet.close(); // 1
}
if (statement != null) {
statement.close(); // 2
}
if (connection != null) {
connection.close(); // 3
}
}
}
}
2๏ธโฃ DB ์กฐ์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐ์์ JDBC APIs๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋ฉฐ, DAO(Data Access Object)์ ์ฐ๊ฒฐ๋๋ค.
2-1. JDBC API ๊ตฌ์ฑ ์์
1. Connection
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ์์ ๊ด๋ฆฌ
- ํธ๋์ญ์ ์ฒ๋ฆฌ๋ฅผ ์ํ Auto-Commit ์ง์ (`connection.commit()`)
2. Staement/PreparedStatement
- SQL ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ ๊ฐ์ฒด
- PreparedStatement๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ ์ ๊ณตํ๋ค
- SQL Injection ๋ฐฉ์ง: ํ๋ผ๋ฏธํฐ๋ฅผ ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ
- Statement ์บ์ฑ: ๋์ผํ SQL ๊ตฌ๋ฌธ ์ฌ์ฌ์ฉ ๊ฐ๋ฅ
2-2. JDBC APIs ์ฌ์ฉ ์์
1๏ธโฃ SELECT(์ ์ฒด ์ ์ ์กฐํ)
public List<User> findAll() throws SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM \"user\"");
List<User> results = new ArrayList<>();
while (resultSet.next()) {
results.add(new User(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"),
resultSet.getString("job"),
resultSet.getString("specialty")
));
}
return results;
} finally {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
}
}
2๏ธโฃ SELECT (์ ์ ID๋ก ์กฐํ, ๋จ์ผ์กฐํ) with PreparedStatement
public User getUser(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")
);
}
throw new SQLException("User not found.");
} finally {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
}
}
3๏ธโฃ INSERT (์ ์ ์ ์ถ๊ฐ) with PreparedStatement
public User save(String name, Integer age, String job, String specialty) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement(
"INSERT INTO \"user\" (name, age, job, specialty, created_at) VALUES (?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS
);
statement.setString(1, name);
statement.setInt(2, age);
statement.setString(3, job);
statement.setString(4, specialty);
statement.setTimestamp(5, Timestamp.valueOf(LocalDateTime.now()));
statement.executeUpdate();
resultSet = statement.getGeneratedKeys();
if (resultSet.next()) {
int userId = resultSet.getInt(1);
return new User(userId, name, age, job, specialty);
}
throw new SQLException("User not created.");
} finally {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
}
}
- Postman ์์ฒญ
- ์ค์ DB์ ์ฑ๊ณต์ ์ผ๋ก ์ฝ์ ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๐ ์ด์ ๊ฐ์ ๊ธฐ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Spring JDBC๋ JPA์ ๊ฐ์ ๊ณ ์์ค ORM์ผ๋ก์ ํ์ฅ์ด ๊ฐ๋ฅํ๋ค ๐
๋ฐ๋ผ์ ๋ค์ ํฌ์คํ ์ ์ด์ด์ Spring JDBC์ ๋ํด ์์ฑํด ๋ณผ ์์ ์ด๋ค.
โน๏ธ ์ฐธ๊ณ
[ASAC 6๊ธฐ ๊ฐ์์๋ฃ]
'๐ปDEV-STUDY > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Java] Stream (0) | 2024.10.02 |
---|---|
[Java] Optional (1) | 2024.10.02 |
[Java] SOLID ์์น (1) | 2024.10.02 |
[Java] Enum (0) | 2024.10.01 |
[Java] Interface / Abstract Class (1) | 2024.10.01 |