✏️ 오늘의 학습

Embedded DataBase

지금까지 Database에 CRUD가 잘되는지 테스팅을 위해 도커로 서버를 계속 띄워줬다. 만약 서버가 구동되지 않은 상태에서 테스트를 하면 어떻게될까? 당연히 실패할 것 이다.이처럼 외부환경에 의해 테스트의 성공 및 실패에 영향을 끼치게 되면 테스트 자동화가 불가능하다.

스프링에서는 Database와 통합테스를 위해서 Embedded DataBase를 제공한다. Embedded DataBase를 이용하기위해서는 Embedded DatabaseBuilder()를 이용해서 Embedded DataBase를 만들 수 있다.

MySql과 호환이 되는 외부 라이브러리를 선택해서 Embedded DataBase를 연동시킬 수 있다.

<dependency>
    <groupId>com.wix</groupId>
	<artifactId>wix-embedded-mysql</artifactId>
	<version>4.6.1</version>
	<scope>test</scope>
</dependency>
@SpringJUnitConfig
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class RegularCustomerRepositoryTest {

    @Configuration
    @ComponentScan(
            basePackages = {"org.prgrms.kdt"}
    )
    
    static class Config {
        @Bean
        public DataSource dataSource() {
            return DataSourceBuilder.create()
                    .url(url)
                    .username(user)
                    .password(password)
                    .type(HikariDataSource.class)
                    .build();
        }

        @Bean
        public JdbcTemplate jdbcTemplate(DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    }

    @Autowired
    DataSource dataSource;

    EmbeddedMysql embeddedMysql;

    @BeforeAll
    void setUp() {
        newCustomer = new RegularCustomer(UUID.randomUUID(), "test1-user", "test1-user@gmail.com", LocalDateTime.now());
        MysqldConfig mysqlConfig = aMysqldConfig(v8_0_11)
                .withCharset(UTF8)
                .withPort(2215)
                .withUser(user, password)
                .withTimeZone("Asia/Seoul")
                .build();
        embeddedMysql = anEmbeddedMysql(mysqlConfig)
                .addSchema(dbTableName, classPathScript("schema.sql"))
                .start();
    }

    @AfterAll
    void cleanup() {
        embeddedMysql.stop();
    }

}

NamedParameterJdbcTemplate

Spring은 JDBC Template 외 NamedParameterJdbcTemplate도 제공한다. 기존에 인덱스 기반에서 이름 기반의 파라미터를 설정할 수 있게해주는 Jdbc Template이다. NamedParameterJdbcTemplate 생성자 코드를 확인해보면 JdbcTemplate을 사용하는걸 확인할 수 있다.
NamedParameterJdbcTemplate생성자코드
NamedParameterJdbcTemplate를 사용할 경우, 인덱스기반인 JDBC Template에 비해 실수할 수 있는 여지를 줄여준다.

    private Map<String, Object> toParamMap(Customer customer) {
        return new HashMap<String, Object>() {{
            put("customerId", customer.getCustomerId().toString().getBytes());
            put("name", customer.getName());
            put("email", customer.getEmail());
            put("createdAt", Timestamp.valueOf(customer.getCreatedAt()));
            put("lastLoginAt", customer.getLastLoginAt() != null ? Timestamp.valueOf(customer.getLastLoginAt()) : null);
        }};
    }

    @Override
    public Customer insert(Customer customer) {
        int update = jdbcTemplate.update("INSERT INTO customers(customer_id, name, email, created_at) VALUES (UUID_TO_BIN(:customerId), :name, :email, :createdAt)", toParamMap(customer));
        if(update != 1){
            throw new RuntimeException("Nothing was inserted");
        }
        return customer;
    }

트랜잭션

하나의 작업을 수행하기위해서 필요한 데이터베이스 연산을 모아놓은것을 의미하며 논리적인 작업의 한 단위가 된다.

트랜잭션 필요성

홍길동 계좌에서 김길동 계좌로 송금을 한다고 가정해보자. 홍길동 계좌에서 송금할 금액인 1억이 빠졌는데, 어떤 이유에서 오류가 발생하여 김길동 계좌로 입금되지 않았다. 이 경우, 홍길동 계좌 출금을 취소를 하거나, 홍길동 계좌에서 김길동 계좌로 송금하는 과정을 다시 수행할수도있다. 하지만 이 방법은 다른 오류를 유발할 수 있다. 이런 상황에서 트랜잭션이 쓰인다.
거래가 성공적으로 끝나는 과정까지가 하나의 논리적인 작업의 한 단위가 되고, 작업 단위를 수행하는 도중 오류가 발생했으면 거래를 처음으로 원복시킨다. 트랜잭션 방식을 사용하면 안정성을 확보할 수 있다.

트랜잭션 특징

  • 원자성 (Atomicity) : 트랜잭션이 부분적 실행되거나 중단되지 않는 것을 보장하는 것을 말한다.
  • 일관성 (Consistency) : 트랜잭션이 성공적으로 완료되면 일괄적인 상태를 유지하는 것을 말한다.
  • 격리성 (Isolation) : 트랜잭션 수행 시 다른 트랜잭션 작업이 끼어들이 못하도록 하는것을 말한다.
  • 지속성 (Durability) : 성공적으로 수행된 트랜잭션은 영구적으로 반영되는 것을 말한다.

Commit

commit은 변경사항을 저장한다. commit되면 데이터베이스의 데이터를 영구적으로 변경하고, 이전 데이터는 완전히 상실된다.

RollBack

RollBack은 변경사항을 취소한다. RollBack은 트랜잭션이 실패할 경우 트랜잭션을 실행하기 전 상태로 되돌려준다.


🔗 오늘의 알고리즘

leetcode 633. Sum of Square Numbers

class Solution {
    public boolean judgeSquareSum(int c) {
        int left = 0, right = (int)Math.sqrt(c);
	    while(left <= right) {
	        int curNum = left*left + right*right;
	        if(curNum < c) {
	            left++;
	        } else if(curNum > c) {
	            right--;
            } else {
                return true;
            }
        }
	    return false;
    }
}

이분탐색과 비슷하게 풀었다.
탐색할 배열에서 범위를 좁혀가면서 특정값 1개를 도출하는 경우는 주로 이분탐색을 많이 쓰는 듯 싶다.


🎤 데일리 스터디 발표

08.26.(목) W4D3 SpringBoot Part2 학습 내용 발표 범위

  • DataSource - 연수님
  • DataSource - HikariCp - 연수님
  • DataSource - CustomerRepository1 - 연재님
  • DataSource - CustomerRepository2 - 연재님
  • DataSource - TestInstance Lifecycle - 효희님
  • DataSource - update추가 - 효희님
  • JDBC Template(1) - 재원님
  • JDBC Template(2) - 재원님
  • JDBC Template(3) - 나
  • JDBC Template Debug - 나

❓오늘의 궁금증

  • 깊게 판다는 기준은 참 모호하다.
  • 경쟁력은 어디서 나올까?

🎊 오늘의 느낀점

  • JDBC Template 부분은 나중에 다시 한번 복습을 해야할 것 같다. 손으로 안익히면 까먹기 딱좋을 것 같은 내용이다.
  • 아직도 조급함과 불안함이 내면에 남아있나보다. 조급함과 불안함이 극에 달했을 때가 있었고 정말 많이 힘들었다. 극에 달했을 때에 비하면 정말! 많이 회복되었지만 아직도 티가 나는걸보면 이너!피스~를 찾아가는과정에 있나보다. 요즘은 아쉬운 마음을 갖지 않으려고 노력하고 있다. 아쉬운 마음에서 자꾸만 불안함이 피어오르고 불안함은 조급함과 함께 자라나는걸 알기때문이다. 생각한대로, 뜻대로 되지않는다고 아쉬워하지말자. 생각한대로, 뜻대로 되지않아서 행복한 일도 많으니까!
profile
개발 덕질 중(?)

0개의 댓글