DB 연동 과정에서 발생 가능한 익셉션
익셉션은 에러로그를 잘 읽어보면 금방 원인을 찾을 수 있기 때문에 간단하게만 짚고 넘어가겠다!
스프링의 익셉션 변환 처리
SQL 문법이 잘못됐을 때 발생한 메시지를 보면
org.springframework.jdbc.BadSqlGrammarException
임을 확인할 수 있다.
BadSqlGrammarException 익셉션이 발생한 이유는 MySQLSyntaxErrorException이 발생했기 떄문이다.
JdbcTemplate의 update() 메서드는 DB 연동을 위해 JDBC API를 사용하는데, JDBC API를 사용하는 과정에서 SQLException이 발생하면 이 익셉션을 알맞은 DataAccessException으로 변환해서 발생한다.
🖐정리해보자면!
1. 잘못된 sql문으로 JdbcTemplate의 update() 메서드 사용
2. update() 메서드는 DB 연동을 위해 JDBC API 사용
3. JDBC 드라이버가 SQLException을 상속받은 MySQLSyntaxException 발생시킴
4. JdbcTemplate이 이 익셉션을 DataAccessException을 상속받은 BadSqlGrammarException으로 변환
🙋♀️ 스프링은 왜 SQLException을 그대로 전파하지 않고 DataAccessException으로 변환하나요?
💡 주된 이유는 연동 기술에 상관없이 동일하게 익셉션을 처리할 수 있도록 하기 위함이다.
스프링은 JDBC뿐만 아니라 JPA, 하이버네이트 등에 대한 연동을 지원하고 MyBatis는 자체적으로 스프링 연동 기능을 제공한다. 그런데 각각의 구현기술마다 익셉션을 다르게 처리해야한다면 개발자는 기술마다 익셉션 처리 코드를 작성해야 할 것이다.
각 연동 기술에 따라 발생하는 익셉션을 스프링이 제공하는 익셉션으로 변환함으로써 구현 기술에 상관없이 동일한 코드로 익셉션을 처리할 수 있게 된다!
‼️ DataAccessException : 스프링이 제공하는 익셉션 타입으로 데이터 연결에 문제가 있을 때 스프링 모듈이 발생시킴
DataAccessException은 RuntimeException으로 필요한 경우에만 익셉션을 처리하면 된다.(=uncheckedException! 잘 모르겠으면 자바 시리즈에 포스팅 해두었으니 다시 확인하기~)
JDBC를 직접 이용하면 try~catch를 이용해서 필요한 경우에 따라 익셉션을 처리한다! (SQLException을 반드시 알맞게 처리해주어야 함)
트랜잭션 처리
아주아주아주 중요한 트랜잭션! 트랜잭션은 DB 상태변경을 위해 수행하는 작업의 논리적 단위이다. 실무에서 트랜잭션의 중요성에 대해서는 아주 잘~ 배웠기 때문에 이론은 이정도로 넘어가겠다.
JDBCSMS Connection의 setAutoCommit(false)를 이용하여 트랜잭션을 시작하고 commit()과 rollback()을 이용해서 트랜잭션을 반영하거나 취소한다.
하지만 이 방식은 코드 누락의 위험이 있으며 구조적인 중복이 반복되는 문제가 있다. 스프링은 이런 부분을 보완하기 위해 트랜잭션 기능을 제공한다.
@Transactional을 이용한 트랜잭션 처리
@Transactional 어노테이션을 사용하면 트랜잭션 범위를 매우 쉽게 지정할 수 있다. @Transactional 어노테이션이 제대로 동작하려면 다음의 두 가지 내용을 스프링 설정에 추가해야 한다.
@Configuration
@EnableTransactionManagement
public class AppCtx {
//..생략..
// 플랫폼 트랜잭션 매니저(PlatformTransactionManager) 빈 설정
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(dataSource());
return tm;
}
//..생략..
PlatformTransactionManager는 스프링이 제공하는 트랜잭션 매니터 인터페이스이다. JDBC는 DataSourceTransactionManager 클래스를 PlatformTransactionManager로 사용한다.
@EnableTransactionManagement 어노테이션은 @Transactional 어노테이션이 붙은 메서드를 트랜잭션 범위에서 실행하는 기능을 활성화한다.
트랜잭션 처리를 위한 설정을 완료하면 트랜잭션 범위에서 실행하고 싶은 스프링 빈 객체의 메서드에 @Transactional 어노테이션을 붙이면 된다.
@Transactional
//(value = "test") 이 속성 없으면 PlatformTransactionManager 타입으로 찾아서 사용
public void changePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if(member == null)
throw new MemberNotFoundException();
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
❗️❕ 트랜잭션이 시작되고 커밋되는지 확인하기 위해서는 스프링이 출력하는 로그 메시지를 보면 된다. 트랜잭션과 관련 로그 메시지를 추가로 출력하기 위해 Logback을 사용한다.❕❗️
// Logback 모듈 : 트랜잭션과 관련 로그 메시지 추가로 출력한다
implementation 'org.slf4j:jcl-over-slf4j'
implementation 'ch.qos.logback:logback-classic'
@Transactional과 프록시
AOP의 대표예시 중 하나가 바로 Transaction이다.
AOP에 대해 다시 한번 정리!
관점 지향 프로그래밍이란 뜻으로 여러 빈 객체에 공통으로 적용되는 기능을 구현하는 방법을 말한다.
따로 코드 밖에서 개발을 해두고 프록시개념으로 메서드가 실행되기전, 실행된 직후, 실행시점에 따라 따로 기능을 적용 시키는 것이다.
스프링은 @Transactional 어노테이션을 이용해서 트랜잭션을 처리하기 위해 내부적으로 AOP를 사용한다.
@EnableTransactionManagement 태그를 사용하면 스프링은 @Transactional 어노테이션이 적용된 빈 객체를 찾아 알맞은 프록시 객체를 생성한다.
1.설정파일 읽음 -> 2.@Transactional 어노테이션이 붙은 빈 찾음 -> 3.해당 객체의 프록시 객체를 생성 -> 4.트랜잭션 시작 -> 5.실제 객체의 메서드 실행 -> 6.성공적이면 커밋
@Transactional 적용 메서드의 롤백 처리
커밋과 동일하게 프록시 객체를 통해 처리된다. 프록시 객체는 원본 객체의 메서드를 실행하는 과정에서 RuntimeException이 발생하면 트랜잭션을 롤백한다.
별도 설정을 추가하지 않으면 발생한 익셉션이 RuntimeException일 때 트랜잭션을 롤백하는데, SQLException은 RuntimeException을 상속하고 있지 않으므로 트랜잭션을 롤백하지 않는다. 이 경우 롤백하고 싶다면
@Transactional(rollbackFor = SQLException.class)
// 여러 익셉션 지정하고 싶을 땐
@Transactional(rollbackFor = {SQLException.class, IOException.class})
public void someMethod() {
// 기능..
}
이렇게 rollbackFor 속성을 설정해주면 된다. 이와 반대되는 속성은 noRollbackFor 속성이다.
@Transactional 주요 속성
// 트랜잭션적용파일 (ChangePasswordService.java)
@Transactional(value = "test
public void changePassword(String email, String oldPwd, String newPwd) {
// 설정파일 (AppCtx.java)
@Bean
public PlatformTransactionManager test() {
@EnableTransactionManagement 어노테이션의 주요 속성
@트랜잭션 전파