스프링
DB 연동
1. JDBC 프로그래밍의 단점을 보완하는 스프링
// 반복 되는 코드 1
Member member;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/chap14?");
}
// 반복 되는 코드 2
finally {
if (rs != null)
try {rs.close();}catch(SQLException e2) {}
if (pstmt != null)
try {pstmt.close();}catch(SQLException e3) {}
if (conn != null)
try {conn.close();}catch(SQLException e3) {}
}
위에 코드를 보면 데이터 처리와는 상관없는 코드지만 JDBC 프로그래밍을 할 때 구조적으로 반복 된다.
구조적인 반복을 줄이기 위한 방법은 템플릿 메서드 패턴과 전략 패턴을 함께 사용하는 것이다.
스프링은 바로 이 두 패턴을 엮은 JdbcTemplate 클래스를 제공한다.
스프링이 제공하는 또 다른 장점은 트랜잭션 관리가 쉽다. 트랜잭션을 적용하고 싶은 메서드에 @Transactional
애노테이션을 붙이기만 하면 된다. ( 커밋 롤백 )
2. JDBC Template, DB 커넥션풀 사용 예제
1). pom.xml
spring-jdbc : JdbcTemplate 등 JDBC 연동에 필요한 기능을 제공 ( 트랜잭션 기능 spring-tx모듈 자동으로 포함 )
tomcat-jdbc : DB 커넥션풀 기능을 제공
mysql-connector-java : MySql 연결에 필요한 JDBC 드라이버 제공
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.db</groupId>
<artifactId>chap5-sp5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>chap5-sp5</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>8.5.27</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok-maven-plugin -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.20.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2). DB 테이블 생성
1. root 계정에서 계정 생성
create user 'jspexam'@'localhost' identified by 'jsppw';
2. 생성한 jspexam 계정 접속 후 데이터베이스 생성
create database (데이터베이스 이름) chap14 character set utf8mb4;
3. 데이터 베이스 권한 설정
grant all privileges on chap14.* to 'jspexam'@'localhost';
create user 'jspexam'@'%' identified by 'jsppw';
grant all privileges on chap14.* to 'jspexam'@'%';
4. 테이블 생성
create table chap14 (
memberid varchar(10) not null primary key,
password varchar(10) not null,
name varchar(20) not null,
email varchar(80)
)
5. 테스트용 테이블 데이터 추가
INSERT INTO member(memberid, password, name, email)
VALUES ('test2', '1234', '김길순','hisnd@email.com')
3). DataSource 설정 ( 커넥션 풀 관리 )
스프링이 제공하는 DB 연동 기능은 DataSource를 사용해서 DB Connection을 구한다.
DB 연동에 사용할 DataSource를 스프링 빈으로 등록하고 DB연동 기능을 구현한 빈 객체는 DataSource를 주입받아 사용한다.Tomcat JDBC 모듈에서 DataSource 클래스를 제공
package config;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.MemberDao;
@Configuration
public class DbConfig {
@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/chap14?"
+"useSSL=true&useUnicode=true&characterEncoding=utf8");
ds.setUsername("jspexam");
ds.setPassword("jsppw");
ds.setInitialSize(2); // 초기 커넥션 개수 지정
ds.setMaxActive(10); // 최대 커넥션 개수 지정
return ds;
}
@Bean
public MemberDao memberDao() {
return new MemberDao(dataSource());
}
}
3). DbQueryConfig ( DbQuery 빈을 설정하고 등록, DataSource 자동 주입 설정 )
package config;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DbQueryConfig {
@Autowired
private DataSource dataSource;
// 클래스의 객체가 생성될 때 스프링은 dataSource 빈을 찾아서 자동으로 주입
@Bean
public DbQuery dbQuery() {
return new DbQuery(dataSource);
}
}
4). DbQuery ( DAO, 데이터베이스 쿼리를 수행 )
package config;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.tomcat.jdbc.pool.DataSource;
import spring.Member;
public class DbQuery {
private DataSource dataSource;
public DbQuery(DataSource dataSource) {
this.dataSource = dataSource;
}
// list 전체 출력
public List selectAll() {
Connection conn = null;
List<Member> list = new ArrayList<>();
try {
conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String sql = "select * from member";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()) {
list.add(new Member(
rs.getString("memberid"),
rs.getString("password"),
rs.getString("name"),
rs.getString("email")
));
}
return list;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
// Select문 갯수
public int count() {
Connection conn = null;
try {
conn = dataSource.getConnection(); // 풀에서 구함
try(Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select count(*) from MEMBER")){
rs.next();
return rs.getInt(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
if (conn != null)
try {
conn.close(); // 풀에 반환
}catch (SQLException e) {
}
}
}
}
5). 실행
package main;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import config.DbConfig;
import config.DbQuery;
import config.DbQueryConfig;
import spring.Member;
public class Ex1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext
(DbConfig.class, DbQueryConfig.class);
DbQuery dbQuery = ctx.getBean("dbQuery",DbQuery.class);
int c1 = dbQuery.count();
System.out.println(c1);
List<Member> list = dbQuery.selectAll();
for(Member member : list) {
System.out.println(member);
}
}
}
JdbcTemplate(템플릿)을 이용한 쿼리 실행
스프링을 사용하면 DataSource나 Connection, Statemement, ResultSet을 직접 사용하지 않고 JdbcTemplate을
이용해서 편리하게 쿼리를 실행할 수 있다.
1). DB정보 토대로 DTO 만들기 ( CRUD하기 위해서 ) lombok 사용
package spring;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Member {
private String memberid;
private String password;
private String name;
private String email;
}
2). JdbcTemplate 생성하기 ( DAO에 생성, DAO 생성자에 DataSource를 주입받도록 구현 )
여기서 주의해야 할 점은 마이바티스랑 틀리게 추가, 업데이트, 삭제 시 동일하게 jdbcTemplate.update 사용
package spring;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class MemberDao {
private JdbcTemplate jdbcTemplate;
public MemberDao(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// select 갯수 구현
public int count() {
Integer count = jdbcTemplate.queryForObject("select count(*) from member", Integer.class);
return count;
}
// insert 구현
public void insert(Member member) {
String sql = "insert into member(memberid, password, name, email)"
+ "values (?,?,?,?)";
jdbcTemplate.update(sql,
member.getMemberid(), member.getPassword(),
member.getName(), member.getEmail()
);
}
// 업데이트 구현
public void update(Member member) {
String sql = "update member set password=?, name=?, email=? "
+ "where memberid = ?";
jdbcTemplate.update(sql,
member.getPassword(),
member.getName(), member.getEmail(), member.getMemberid()
);
System.out.println("업데이트 완료");
}
// 삭제 구현
public void delete(String id) {
String sql = "delete from member where memberid = ?";
jdbcTemplate.update(sql, id);
System.out.println("삭제완료");
}
// List 전체 목록 출력 구현
public List<Member> selectAll(){
List<Member> result = jdbcTemplate.query("select * from member",
new RowMapper<Member>() {
@Override
public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
Member member = new Member(
rs.getString("memberid"),
rs.getString("email"),
rs.getString("password"),
rs.getString("name"));
return member;
}
});
return result;
}
}
3). 실행
package main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import config.DbConfig;
import config.DbQueryConfig;
import spring.Member;
import spring.MemberDao;
public class TestMemberDao {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(DbConfig.class, DbQueryConfig.class);
MemberDao memberDao = ctx.getBean("memberDao", MemberDao.class);
System.out.println(memberDao.count());
// 삭제
//memberDao.delete("test4");
// 조회
// List<Member> list = memberDao.selectAll();
// for(Member member : list) {
// System.out.println(member);
// }
// 생성
//memberDao.insert(new Member("test4", "111", "구마적", "sed@scd.com"));
// 업데이트
Member member = new Member("test4", "222", "신마적","ewewe@dd.com");
memberDao.update(member);
}
}
'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글
2023-08-04 56일차 (0) | 2023.08.04 |
---|---|
2023-08-03 55일차 (0) | 2023.08.03 |
2023-08-01 53일차 (0) | 2023.08.01 |
2023-07-31 52일차 (0) | 2023.07.31 |
2023-07-28 51일차 (0) | 2023.07.28 |