@Bean
DataSource dataSource(){
return new DriverManagerDataSource(URL, USERNAME, PASSWORD);
}
@Bean
PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
이때 스프링 부트는 다음과 같이 application.properties 에 있는 속성을 사용해서 DataSource 를 생성한다. 그리고 스프링 빈에 등록한다.\
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.username=sa
spring.datasource.password=
어떤 트랜잭션 매니저를 선택할지는 현재 등록된 라이브러리를 보고 판단하는데, JDBC를 기술을 사용하면 DataSourceTransactionManager 를 빈으로 등록하고, JPA를 사용하면 JpaTransactionManager 를 빈으로 등록한다. 둘다 사용하는 경우 JpaTransactionManager를 등록한다. 참고로 JpaTransactionManager는 DataSourceTransactionManager가 제공하는 기능도 대부분 지원한다.
package hello.jbdc.service
import hello.jbdc.Log
import hello.jbdc.connection.ConnectionConst
import hello.jbdc.domain.Member
import hello.jbdc.repository.MemberRepositoryV3
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.aop.support.AopUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.jdbc.datasource.DataSourceTransactionManager
import org.springframework.jdbc.datasource.DriverManagerDataSource
import java.sql.SQLException
import javax.sql.DataSource
@SpringBootTest
internal class MemberServiceV3_4Test: Log{
val MEMBER_A = "memberA"
val MEMBER_B = "memberB"
val MEMBER_EX = "ex"
@Autowired
lateinit var memberRepository: MemberRepositoryV3
@Autowired
lateinit var memberService: MemberServiceV3_3
@AfterEach
@Throws(SQLException::class)
fun after(){
memberRepository.delete(MEMBER_A);
memberRepository.delete(MEMBER_B);
memberRepository.delete(MEMBER_EX);
}
@TestConfiguration
class TestConfig(
private val dataSource: DataSource
){
@Bean
fun memberRepositoryV3() = MemberRepositoryV3(dataSource)
@Bean
fun memberServiceV3_3() = MemberServiceV3_3(memberRepositoryV3())
}
@Test
fun AopCheck() {
logger.info("memberService class={}", memberService.javaClass)
logger.info("memberRepository class={}", memberRepository.javaClass)
Assertions.assertThat(AopUtils.isAopProxy(memberService)).isTrue()
Assertions.assertThat(AopUtils.isAopProxy(memberRepository)).isFalse()
}
@Test
@DisplayName("정상 이체")
@Throws(SQLException::class)
fun accountTransfer() {
//given
val memberA = Member(MEMBER_A, 10000)
val memberB = Member(MEMBER_B, 10000)
memberRepository.save(memberA)
memberRepository.save(memberB)
//when
memberService.accountTransfer(memberA.memberId,
memberB.memberId, 2000)
// //then
val findMemberA: Member = memberRepository.findById(memberA.memberId)
val findMemberB: Member = memberRepository.findById(memberB.memberId)
assertThat(findMemberA.money).isEqualTo(8000)
assertThat(findMemberB.money).isEqualTo(12000)
}
@Test
@DisplayName("이체 중 예외 발생")
fun accountTransferEx(){
//given
val memberA = Member(MEMBER_A, 10000)
val memberEx = Member(MEMBER_EX, 10000)
memberRepository.save(memberA)
memberRepository.save(memberEx)
// when
assertThatThrownBy {
memberService.accountTransfer(memberA.memberId, memberEx.memberId,
2000)
}
.isInstanceOf(IllegalStateException::class.java)
// then
val findMemberA = memberRepository.findById(memberA.memberId)
val findMemberEx = memberRepository.findById(memberEx.memberId)
assertThat(findMemberA.money).isEqualTo(10000)
assertThat(findMemberEx.money).isEqualTo(10000)
}
}