지금까지 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();
}
}
Spring은 JDBC Template 외 NamedParameterJdbcTemplate도 제공한다. 기존에 인덱스 기반에서 이름 기반의 파라미터를 설정할 수 있게해주는 Jdbc Template이다. NamedParameterJdbcTemplate 생성자 코드를 확인해보면 JdbcTemplate을 사용하는걸 확인할 수 있다.
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억이 빠졌는데, 어떤 이유에서 오류가 발생하여 김길동 계좌로 입금되지 않았다. 이 경우, 홍길동 계좌 출금을 취소를 하거나, 홍길동 계좌에서 김길동 계좌로 송금하는 과정을 다시 수행할수도있다. 하지만 이 방법은 다른 오류를 유발할 수 있다. 이런 상황에서 트랜잭션이 쓰인다.
거래가 성공적으로 끝나는 과정까지가 하나의 논리적인 작업의 한 단위가 되고, 작업 단위를 수행하는 도중 오류가 발생했으면 거래를 처음으로 원복시킨다. 트랜잭션 방식을 사용하면 안정성을 확보할 수 있다.
commit은 변경사항을 저장한다. commit되면 데이터베이스의 데이터를 영구적으로 변경하고, 이전 데이터는 완전히 상실된다.
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 - 나