bong-u/til

08_connect_DB

수정일 : 2024-11-15

DataSource 설정

  • AppCtx.java
 1    @Bean(destroyMethod = "close")
 2    public DataSource dataSource() {
 3        DataSource ds = new DataSource();
 4        ds.setDriverClassName("com.mysql.jdbc.Driver");
 5        ds.setUrl("jdbc:mysql://localhost/spring5fs?"+
 6        "enabledTLSProtocols=TLSv1.2&"+
 7        "useSSL=false&"+
 8        "characterEncoding=utf8");
 9        ds.setUsername("spring5");
10        ds.setPassword("spring5");
11        ds.setInitialSize(2);
12        ds.setMaxActive(10);
13        ds.setTestWhileIdle(true);
14        ds.setMinEvictableIdleTimeMillis(60000 * 3);
15        ds.setTimeBetweenEvictionRunsMillis(10 * 1000);
16        return ds;
17    }

Query 실행

JdbcTemplate을 이용한 select

 1jdbcTemplate.query(
 2"select * from MEMBER where EMAIL = ?",
 3new RowMapper<Member>() {
 4    @Override
 5    public Member mapRow(ResultSet rs, int rowNum)
 6        throws SQLException {
 7            Member member = new Member(
 8                rs.getString("EMAIL"),
 9                rs.getString("PASSWORD"),
10                rs.getString("NAME"),
11                rs.getTimestamp("REGDATE").toLocalDateTime());
12            member.setId(rs.getLong("ID"));
13            return member;
14        }
15    },
16    email);

PreparedStatementCreater를 이용한 update

 1jdbcTemplate.update(new PreparedStatementCreator() {
 2    @Override
 3    public PreparedStatement createPreparedStatement(Connection con)
 4    throws SQLException {
 5        PreparedStatement pstmt = con.prepareStatement(
 6            "insert into MEMBER (EMAIL, PASSWORD, NAME, REGDATE) values (?, ?, ?, ?)");
 7        pstmt.setString(1, member.getEmail());
 8        pstmt.setString(2, member.getPassword());
 9        pstmt.setString(3, member.getName());
10        pstmt.setTimestamp(4, Timestamp.valueOf(member.getRegisterDateTime()));
11
12        return pstmt;
13    }
14})

java.sql.SQLException: Unable to load class: come.mysql.jdbc.Driver from …

  • 오류를 잘 보자… come.mysql…
  • 오타로 인한 문제였다

java.sql.SQLException: Unable to load authentication plugin ‘caching_sha2_password’.

  • mysql 비밀번호 인증 방식에 따른 오류이다
  • 해결방법 : mysql에서 비밀번호 인증방식을 바꾸자
    1ALTER USER '사용자'@'localhost' IDENTIFIED WITH mysql_native_password BY '비밀번호';
    

javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

  • url에 enabledTLSProtocols=TLSv1.2를 지정하여 해결할 수 있다
  • url형식때문에 해결하는데 조금 시간이 걸렸다.
  • 올바른 URL 형식은 아래와 같다 기억하자

    jdbc:mysql://localhost/spring5fs?속성1=값1&속성2=값2…"

Transaction 처리

Transaction

데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위

배경

  • 쿼리 두 개를 실행하는데 만약 2번째 쿼리에서 오류가 발생했을때
  • 1번째 쿼리 실행 이전 상태로 되돌리는 (롤백) 작업이 필요하다
  • 이와 같이 쿼리 두 개를 묶어야 하는 상황에 Transaction을 이용한다.
  • rollback 함수를 직접 호출하는 방법도 있지만, Spring에서는 @Transactional을 이용해 더 간편하게 구현할 수 있다.

AppCtx.java

1@Bean
2public PlatformTransactionManager transactionManager() {
3    DataSourceTransactionManager tm = new DataSourceTransactionManager();
4    tm.setDataSource(dataSource());
5    return tm;
6}

ChangePasswordService.java

 1@Transactional
 2public void changePassword(String email, String oldPwd, String newPwd) {
 3    Member member = memberDao.selectByEmail(email);
 4
 5    if (member == null)
 6        throw new MemberNotFoundException();
 7
 8    member.changePassword(oldPwd, newPwd);
 9    memberDao.update(member);
10}

트랜잭션 관련 로그 메시지 출력

logback.xml

 1<?xml version="1.0" encoding="UTF-8">
 2
 3<configuration>
 4    <appender name="stdout" class="chqos.logback.core.ConsoleAppender">
 5        <encoder>
 6            <pattern>%d %5p %c{2} - %m%n</pattern>
 7        </encoder>
 8    </appender>
 9    <root level="INFO">
10        <appender-ref ref="stdout" />
11    </root>
12
13    <logger name="org.springframework.jdbc" level="DEBUG" />
14</configuration>
  • 로그 출력하는 것도 배워보았다.

Transaction 전파

 1public class SomeService {
 2    private AnyService anyService;
 3
 4    @Transactional
 5    public void some() {
 6        anyService.any();
 7    }
 8
 9    public void setAnyService(AnyService as) {
10        anyService = as;
11    }
12}
13
14public class AnyService {
15    @Transactional
16    public void any() { ... }
17}
  • some메소드가 any메소드를 호출했다. 위 코드에서는 메소드 둘 다 @Transactional이 붙어있지만 만약 붙어있지 않으면 어떻게 될까?
  • 이렇게 메소드 간 호출이 발생할 때 트랜잭션이 유지되는 것을 트랜잭션 전파라고 한다.
  • @Transactional annotation에 사용할 수 있는 속성 중 propagation이 트랜잭션 전파타입을 지정한다.
  • 기본값 : REQUIRED : 현재 진행중인 트랜잭션이 존재하면 해당 트랜잭션 사용, 존재하지 않으면 새로운 트랜잭션을 생성한다