From 8c30706ca277f29a401a969866524e5ca7c82173 Mon Sep 17 00:00:00 2001 From: haerong22 Date: Wed, 4 May 2022 00:33:13 +0900 Subject: [PATCH] #9 spring data access exception --- .../jdbc/repository/MemberRepositoryV4_2.java | 137 ++++++++++++++++++ .../SpringExceptionTranslatorTest.java | 65 +++++++++ .../jdbc/service/MemberServiceV4Test.java | 4 +- 3 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 jdbc/src/main/java/com/example/jdbc/repository/MemberRepositoryV4_2.java create mode 100644 jdbc/src/test/java/com/example/jdbc/exception/translator/SpringExceptionTranslatorTest.java diff --git a/jdbc/src/main/java/com/example/jdbc/repository/MemberRepositoryV4_2.java b/jdbc/src/main/java/com/example/jdbc/repository/MemberRepositoryV4_2.java new file mode 100644 index 00000000..5d9bce3e --- /dev/null +++ b/jdbc/src/main/java/com/example/jdbc/repository/MemberRepositoryV4_2.java @@ -0,0 +1,137 @@ +package com.example.jdbc.repository; + +import com.example.jdbc.domain.Member; +import com.example.jdbc.repository.ex.MyDbException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; +import org.springframework.jdbc.support.SQLExceptionTranslator; + +import javax.sql.DataSource; +import java.sql.*; +import java.util.NoSuchElementException; + +/** + * SQLExceptionTranslator 추가 + */ +@Slf4j +public class MemberRepositoryV4_2 implements MemberRepository { + + private final DataSource dataSource; + private final SQLExceptionTranslator exTranslator; + + public MemberRepositoryV4_2(DataSource dataSource) { + this.dataSource = dataSource; + this.exTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource); + } + + @Override + public Member save(Member member) { + String sql = "insert into member(member_id, money) values(?, ?)"; + + Connection con = null; + PreparedStatement pstmt = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setString(1, member.getMemberId()); + pstmt.setInt(2, member.getMoney()); + pstmt.executeUpdate(); + return member; + } catch (SQLException e) { + log.error("db error", e); + throw exTranslator.translate("save", sql, e); + } finally { + close(con, pstmt, null); + } + } + + @Override + public Member findById(String memberId) { + String sql = "select * from member where member_id = ?"; + + Connection con = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setString(1, memberId); + + rs = pstmt.executeQuery(); + if (rs.next()) { + Member member = new Member(); + member.setMemberId(rs.getString("member_id")); + member.setMoney(rs.getInt("money")); + return member; + } else { + throw new NoSuchElementException("member not found memberId=" + memberId); + } + } catch (SQLException e) { + log.error("db error", e); + throw exTranslator.translate("findById", sql, e); + } finally { + close(con, pstmt, rs); + } + } + + @Override + public void update(String memberId, int money) { + String sql = "update member set money=? where member_id=?"; + + Connection con = null; + PreparedStatement pstmt = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setInt(1, money); + pstmt.setString(2, memberId); + + int result = pstmt.executeUpdate(); + log.info("resultSize={}", result); + } catch (SQLException e) { + log.error("db error", e); + throw exTranslator.translate("update", sql, e); + } finally { + close(con, pstmt, null); + } + } + + @Override + public void delete(String memberId) { + String sql = "delete from member where member_id=?"; + + Connection con = null; + PreparedStatement pstmt = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setString(1, memberId); + pstmt.executeUpdate(); + } catch (SQLException e) { + log.error("db error", e); + throw exTranslator.translate("delete", sql, e); + } finally { + close(con, pstmt, null); + } + } + + private void close(Connection con, Statement stmt, ResultSet rs) { + JdbcUtils.closeResultSet(rs); + JdbcUtils.closeStatement(stmt); + // 트랜잭션 동기화를 사용하려면 DataSourceUtils 를 사용해야 한다. + DataSourceUtils.releaseConnection(con, dataSource); + } + + private Connection getConnection() throws SQLException { + // 트랜잭션 동기화를 사용하려면 DataSourceUtils 를 사용해야 한다. + Connection con = DataSourceUtils.getConnection(dataSource); + log.info("get connection={}, class={}", con, con.getClass()); + return con; + } +} diff --git a/jdbc/src/test/java/com/example/jdbc/exception/translator/SpringExceptionTranslatorTest.java b/jdbc/src/test/java/com/example/jdbc/exception/translator/SpringExceptionTranslatorTest.java new file mode 100644 index 00000000..95bd036a --- /dev/null +++ b/jdbc/src/test/java/com/example/jdbc/exception/translator/SpringExceptionTranslatorTest.java @@ -0,0 +1,65 @@ +package com.example.jdbc.exception.translator; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import static com.example.jdbc.connection.ConnectionConst.*; +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +public class SpringExceptionTranslatorTest { + + DataSource dataSource; + + @BeforeEach + void init() { + dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD); + } + + @Test + void sqlExceptionErrorCode() { + String sql = "select bad grammer"; + + try { + Connection con = dataSource.getConnection(); + PreparedStatement pstmt = con.prepareStatement(sql); + pstmt.executeQuery(); + } catch (SQLException e) { + int errorCode = e.getErrorCode(); + assertThat(errorCode).isEqualTo(42122); + log.info("errorCode={}", errorCode); + log.info("error", e); + } + } + + @Test + void exceptionTranslator() { + String sql = "select bad grammer"; + + try { + Connection con = dataSource.getConnection(); + PreparedStatement pstmt = con.prepareStatement(sql); + pstmt.executeQuery(); + } catch (SQLException e) { + int errorCode = e.getErrorCode(); + assertThat(errorCode).isEqualTo(42122); + + // org.springframework.jdbc.support.sql-error-codes.xml + SQLErrorCodeSQLExceptionTranslator exTranslator = new SQLErrorCodeSQLExceptionTranslator(); + DataAccessException resultEx = exTranslator.translate("select", sql, e); + log.info("resultEx", resultEx); + + assertThat(resultEx.getClass()).isEqualTo(BadSqlGrammarException.class); + } + } +} diff --git a/jdbc/src/test/java/com/example/jdbc/service/MemberServiceV4Test.java b/jdbc/src/test/java/com/example/jdbc/service/MemberServiceV4Test.java index 4d079515..ff7dc83d 100644 --- a/jdbc/src/test/java/com/example/jdbc/service/MemberServiceV4Test.java +++ b/jdbc/src/test/java/com/example/jdbc/service/MemberServiceV4Test.java @@ -3,6 +3,7 @@ package com.example.jdbc.service; import com.example.jdbc.domain.Member; import com.example.jdbc.repository.MemberRepository; import com.example.jdbc.repository.MemberRepositoryV4_1; +import com.example.jdbc.repository.MemberRepositoryV4_2; import lombok.extern.slf4j.Slf4j; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; @@ -50,7 +51,8 @@ class MemberServiceV4Test { @Bean MemberRepository memberRepository() { - return new MemberRepositoryV4_1(dataSource); +// return new MemberRepositoryV4_1(dataSource); + return new MemberRepositoryV4_2(dataSource); } @Bean