1 ๋ถ„ ์†Œ์š”

์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ๋นˆ ์„ค๊ณ„

์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์˜ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์— ์ ์šฉํ•  ์กฐ๊ฑด๊ณผ ๋งŒ๋“ค์–ด์ง€๋Š” ๋นˆ ์˜ค๋ธŒ์ ํŠธ์˜ ์ข…๋ฅ˜ ๋“ฑ์„ ๋จผ์ € ์„ค๊ณ„ํ•œ๋‹ค. image ๋‘ ๊ฐœ์˜ 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 {

}

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ