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 : 현재 진행중인 트랜잭션이 존재하면 해당 트랜잭션 사용, 존재하지 않으면 새로운 트랜잭션을 생성한다