๐[์คํ๋ง ๋ถํธ - ์ดํด์ ์๋ฆฌ] ์คํ๋ง JDBC ์๋ ๊ตฌ์ฑ ๊ฐ๋ฐ
์๋ ๊ตฌ์ฑ ํด๋์ค์ ๋น ์ค๊ณ
์๋ก์ด ๊ธฐ์ ์ ์๋ ๊ตฌ์ฑ ํด๋์ค๋ฅผ ์์ฑํ ๋๋ ์๋ ๊ตฌ์ฑ ํด๋์ค์ ์ ์ฉํ ์กฐ๊ฑด๊ณผ ๋ง๋ค์ด์ง๋ ๋น ์ค๋ธ์ ํธ์ ์ข
๋ฅ ๋ฑ์ ๋จผ์ ์ค๊ณํ๋ค.
๋ ๊ฐ์ DataSource ๊ตฌํ ํด๋์ค๋ฅผ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ฑ๋ก๋๋๋ก ํ๋ค. ์ด ๋ ๊ฐ์ ๋น์ DataSourceProperties๋ผ๋ ํ๋กํผํฐ ํด๋์ค๋ฅผ ์ด์ฉํ๋ค.
์คํ๋ง JDBC
DataSource ์๋ ๊ตฌ์ฑ ํด๋์ค
DataSourceConfig์ JdbcOperations ํด๋์ค์ ์กด์ฌ๋ฅผ ํ์ธํด์ ๋ฑ๋ก๋๋๋ก ํ๋ค.
DataSource ๋น ๋ฉ์๋์์ ํ๋กํผํฐ๋ก ์ฌ์ฉํ ํ๋กํผํฐ๋ฅผ ์ ์ํ๋ค.
@EnableTransactionManagement๋ ์ ๋
ธํ
์ด์
์ ํ์ฉํ ํธ๋์ญ์
๊ธฐ๋ฅ์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๊ตฌ์ฑ์ฉ ์ ๋
ธํ
์ด์
์ด๋ค.
@MyAutoConfiguration
@ConditionalMyOnClass("org.springframework.jdbc.core.JdbcOperations")
@EnableMyConfigurationProperties(MyDataSourceProperties.class)
@EnableTransactionManagement
public class DataSourceConfig {
SimpleDriverDataSource๋ ๊ฐ๋จํ ํ
์คํธ์์๋ง ์ฌ์ฉํด์ผ ํ๋ค. ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ฉด ์ ๋๋ค.
@ConditionalOnMissingBean์ ์ด์ฉํด์ ์์์ DataSource๊ฐ ๋ฑ๋ก๋๋ฉด ๋น์ ๋ง๋ค์ง ์๋๋ก ํ๋ค.
@Bean
@ConditionalOnMissingBean
DataSource dataSource(MyDataSourceProperties properties) throws ClassNotFoundException {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass((Class<? extends Driver>) Class.forName(properties.getDriverClassName()));
dataSource.setUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
Hikari Data Source๋ Hikari ํด๋์ค๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ง ๋ง๋ค์ด์ง๋๋ก ์กฐ๊ฑด์ ๊ฑธ์ด์ค๋ค.
@Bean
@ConditionalMyOnClass("com.zaxxer.hikari.HikariDataSource")
@ConditionalOnMissingBean
DataSource hikariDataSource(MyDataSourceProperties properties) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(properties.getDriverClassName());
dataSource.setJdbcUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
JdbcTemplate๊ณผ ํธ๋์ญ์ ๋งค๋์ ๊ตฌ์ฑ
@ConditionalOnSingleCandidate๋ ๋น ๊ตฌ์ฑ์ ๋ณด์ ํด๋น ํ์ ์ ๋น์ด ํ ๊ฐ๋ง ๋ฑ๋ก๋์ด์๋ ๊ฒฝ์ฐ์ ์กฐ๊ฑด์ด ๋งค์นญ๋๋ค.
JdbcTemplate์ DataSource๋ฅผ ์ฃผ์
๋ฐ์์ ์์ฑํ๋ค.
@Bean
@ConditionalOnSingleCandidate(DataSource.class)
@ConditionalOnMissingBean
JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
์คํ๋ง์ ํธ๋์ญ์ ์ถ์ํ ๊ธฐ๋ฅ์ ํ์ฉํ๊ธฐ ์ํด์ ํธ๋์ญ์ ๋งค๋์ ๋น๋ ๋ง๋ค์ด์ค๋ค.
@Bean
@ConditionalOnSingleCandidate(DataSource.class)
@ConditionalOnMissingBean
JdbcTransactionManager jdbcTransactionManager(DataSource dataSource) {
return new JdbcTransactionManager(dataSource);
}
์ ๋ ธํ ์ด์ ์ ์ด์ฉํ๋ ํธ๋์ญ์ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ธฐ ์ํด @EnableTransactionManagement์ ํด๋์ค ๋ ๋ฒจ์ ๋ฃ๋ ๊ฒ๋ ์์ง ๋ง์์ผ ํ๋ค.
Hello Repository
๐ก์ธํฐํ์ด์ค์ default ๋ฉ์๋, static ๋ฉ์๋๋ฅผ ๋ฃ์ด์ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์๋ฐ์ Comparator
์ธํฐํ์ด์ค๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋์์ด ๋๋ค.
JdbcTemplate์ queryForObject๋ฅผ ์ด์ฉํด์ ํ๋์ ์กฐํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค. ์ค๋ธ์ ํธ์ ์ปฌ๋ผ ๊ฐ์ ๋งคํํ๋ ๊ฒฝ์ฐ RowMapper ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ ResultSet์ ๋ฐ์ดํฐ ์ค๋ธ์ ํธ๋ก ์ ํํ๋ ์ฝ๋๋ฅผ ๋ฃ์ด ์ฝ๋ฐฑ์ผ๋ก ์ ๋ฌํด ์ฌ์ฉํ๋ค.
<T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException;
@FunctionalInterface
public interface RowMapper<T> {
@Nullable
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ๋๋ JdbcTemplate์ update()๋ฅผ ์ด์ฉํ๋ค.
๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ HelloService
ํ ์คํธ ์ฝ๋์ ์ฌ์ฉ๋๋ ์ ๋ ธํ ์ด์ ๋ ํฉ์ฑ ์ ๋ ธํ ์ด์ ์ผ๋ก ๋ง๋ค์ด ์ฌ์ฉํ๋ฉด ํธ๋ฆฌํ๋ค.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = HellobootApplication.class)
@TestPropertySource("classpath:/application.properties")
@Transactional
public @interface HellobootTest {
}
๋๊ธ๋จ๊ธฐ๊ธฐ