[Spring] Spring DB - 쿼리실행
Spring에서 제공하는 쿼리 실행 방법을 알아보겠습니다. JdbcTemplate을 이용한 변경 쿼리 실행 INSERT, UPDATE, DELETE 쿼리는 update() 메서드를 사용합니다. * int update(String sql) * int update(String sql, Object... args
muscleking3426.tistory.com
이전 포스팅에서 작성했던 코드를 테스트해보는 시간을 가지겠습니다.
간단한 메인 클래스를 작성해서 테스트해봅시다.
설정 클래스
@Configuration
public class AppCtx {
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8");
ds.setUsername("spring5");
ds.setPassword("spring5");
ds.setInitialSize(2);
ds.setMaxActive(10);
ds.setTestWhileIdle(true);
ds.setMinEvictableIdleTimeMillis(10 * 1000);
return ds;
}
@Bean
public MemberDao memberDao() {
return new MemberDao(dataSource());
}
}
Member
package spring;
import java.time.LocalDateTime;
public class Member {
private Long id;
private String email;
private String password;
private String name;
private LocalDateTime registerDateTime;
public Member(String email, String password, String name, LocalDateTime regDateTime) {
// TODO Auto-generated constructor stub
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = regDateTime;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDateTime getRegisterDateTime() {
return registerDateTime;
}
public void setRegisterDateTime(LocalDateTime registerDateTime) {
this.registerDateTime = registerDateTime;
}
//비밀번호 변경 메소드
public void changePassword(String oldPassword, String newPassword) {
//기존비밀번호 검증 로직
if(!password.equals(oldPassword))
throw new WrongIdPasswordException();
this.password = newPassword;
}
}
MemberDao
public class MemberDao {
private JdbcTemplate jdbcTemplate;
public MemberDao(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public Member selectByEmail(String email) {
List<Member> results = jdbcTemplate.query("select * from MEMBER where EMAIL = ?", new RowMapper<Member>() {
@Override
public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
Member member = new Member(rs.getString("EMAIL"), rs.getString("PASSWORD"), rs.getString("NAME"),
rs.getTimestamp("REGDATE").toLocalDateTime());
member.setId(rs.getLong("ID"));
return member;
}
}, email);
return results.isEmpty() ? null : results.get(0);
}
public void insert(Member member) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update((Connection conn) -> {
PreparedStatement pstmt = conn.prepareStatement("insert into MEMBER (EMAIL, PASSWORD, NAME, REGDATE) " +
"values (?, ?, ?, ?)",
new String[] {"ID"} );
// 인덱스 파라미터의 값 설정
pstmt.setString(1, member.getEmail());
pstmt.setString(2, member.getPassword());
pstmt.setString(3, member.getName());
pstmt.setTimestamp(4, Timestamp.valueOf(member.getRegisterDateTime()));
// 생성한 pstmt 객체 리턴
return pstmt;
}, keyHolder);
Number keyValue = keyHolder.getKey();
member.setId(keyValue.longValue());
}
public void update(Member member) {
jdbcTemplate.update("update MEMBER set NAME = ?, PASSWORD = ? where EMAIL = ?", member.getName(),
member.getPassword(), member.getEmail());
}
public Collection<Member> selectAll() {
List<Member> results = jdbcTemplate.query("select * from MEMBER", new RowMapper<Member>() {
@Override
public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
Member member = new Member(rs.getString("EMAIL"), rs.getString("PASSWORD"), rs.getString("NAME"),
rs.getTimestamp("REGDATE").toLocalDateTime());
member.setId(rs.getLong("ID"));
return member;
}
});
return results;
}
public int count() {
Integer count = jdbcTemplate.queryForObject("select count(*) from MEMBER", Integer.class);
return count;
}
}
메인클래스
package main;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import config.AppCtx;
import spring.Member;
import spring.MemberDao;
public class MainForMemberDao {
private static MemberDao memberDao;
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMddHHmmss");
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx.class);
memberDao = ctx.getBean(MemberDao.class);
selectAll();
updateMember();
insertMember();
ctx.close();
}
private static void selectAll() {
System.out.println("----selectAll");
int total = memberDao.count();
System.out.println("전체 데이터 : " + total);
List<Member> members = (List<Member>) memberDao.selectAll();
for (Member m : members) {
System.out.println(m.getId() + ":" + m.getEmail() + ":" + m.getName());
}
}
private static void updateMember() {
System.out.println("----updateMember");
Member member = memberDao.selectByEmail("madvirus@madvirus.net");
String oldPw = member.getPassword();
String newPw = Double.toHexString(Math.random());
member.changePassword(oldPw, newPw);
memberDao.update(member);
System.out.println("암호 변경 : " + oldPw + " > " + newPw);
}
private static void insertMember() {
System.out.println("----insertMember");
String prefix = formatter.format(LocalDateTime.now());
Member member = new Member(prefix + "@test.com", prefix, prefix, LocalDateTime.now());
memberDao.insert(member);
System.out.println(member.getId() + "데이터 추가");
}
}
SSL 관련 예외
메인 클래스를 실행할 때, SSL 관련 익셉션이 발생한다면 다음과 같이 설정클래스의 DataSource 빈을 변경해 줍니다.
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8&useSSL=false");
ds.setUsername("spring5");
ds.setPassword("spring5");
ds.setInitialSize(2);
ds.setMaxActive(10);
ds.setTestWhileIdle(true);
ds.setMinEvictableIdleTimeMillis(60000 * 3);
ds.setTimeBetweenEvictionRunsMillis(10 * 1000);
return ds;
}
MySQL 5.5.45+, 5.6.26+ 및 5.7.6+ 버전부터는 SSL연결에 대한 명시적으로 설정을 해줘야 합니다. 따라서, useSSL=false 구문을 추가해 주었습니다.
caching_sha2_password
java.sql.SQLException: Unable to load authentication plugin 'caching_sha2_password'.
또한 위와 같은 익셉션이 발생할 것입니다. 해당 문제는 MySQL 8.0 이상의 버전에서 발생하는 문제로써, 8.0 버전의 기본 인증플러그인 변경으로 인한 발생 하였습니다.
MySQL 8.0 SHA-256 해싱을 구현하는 두 가지 플러그인을 지원합니다.
- SHA256 : 기본적인 SHA-256 인증을 구현한 플러그인
- caching_sha2_password : sha256_password와 동일하지만, 성능 향상을 위해 서버 캐싱 이용
MySQL8.0의 기본 인증 플러그인은 caching_sha2_password입니다.
caching_sha2_password를 사용하려면 'SSL 보안 연결을'을 사용하거나 RSA 보안을 적용한 비암호 연결을 사용해야 합니다.
따라서 보안 연결이나 RSA 보안을 사용하지 않는다면 해당 에러가 발생하는 것입니다.
해당 문제를 해결하기 위해 가장 쉬운 방식인 인증 방식을 MySQL 5.* 버전에서 디폴트로 사용되었던 'mysql_native_password' 방식으로 변경하는 것입니다.
alter user '사용자'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
[출처 : https://developer-hm.tistory.com/16]
실행결과
Spring이 제공하는 JdbcTemplate를 이용해, 데이터를 select , update, insert 하는 테스트를 진행해 보았습니다.
'Spring' 카테고리의 다른 글
[Spring] Spring DB - 익셉션 변환처리 (0) | 2024.02.27 |
---|---|
[Spring] Spring DB 연동 과정에서 발생하는 Exception (0) | 2024.02.26 |
[Spring] Spring DB - 쿼리실행 (0) | 2024.02.21 |
[Spring] Spring JdbcTemplate - qureyForObject 메서드 (0) | 2024.02.19 |
[Spring] Spring JDBCTemplate 쿼리실행 (0) | 2024.02.19 |