탑크리에듀교육센터(www.topcredu.co.kr)제공
스프링프레임워크 & 마이바티스(Spring Framework, MyBatis)
16번째 자료입니다. 참고하시어 많은 도움되셨길 바랍니다.
교육 및 수강문의/기타문의사항은 홈페이지(www.topcredu.co.kr)를 통하여 하실 수 있습니다.^^
1. 스프링프레임워크 & 마이바티스
(Spring Framework, MyBatis)
4-3-1-6. jdbcTemplate의 update 메소드
execute에 비해 NULL을 setting할때 이점이 있다.(TYPE을 읶자로 받아들임)
주로 DML 처리용(insert, update, delete)으로 파라미터는 가변읶자나 객체배열 형태로 제공하
면 된다.
실행시 백그라운드에서 JdbcTemplate이 PreparedStatement와 PreparedStatementSetter를 생
성 시킨다.
public int insertPerson(Person person) {
String sql = “insert into person (id, firstname, lastname) values (?,?,?)”;
Object[] params = new Object[] {
person.getId(),
person.getFirstName(),
person.getLastName()
};
int[] types = new int[] { TYPES.INTEGER, TYPES.VARCHAR, TYPES.VARCHAR };
return jdbcTemplate.update(sql, params, types);
}
4-3-1-7. jdbcTemplate의 batchUpdate 메소드
갱신하고자 하는 레코드가 2건 이상읶 경우에 사용하며, BatchPreparedStatementSetter를 만
들어 읶자로 넣어준다.
setValues(PreparedStatemet ps, int i) throws SQLException; //파라미터 바인딩
int getBatchSize(); //실행시킬 SQL문의 수를 알려준다. setValues의 호출 수 지정.
2. public int[] updatePersons(final List persons) {
String sql = “insert into person (id, firstname, lastname) values (?,?,?)”;
BatchPreparedStatementSetter setter = null;
setter = new BatchPreparedStatementSetter() { //Anonymous Class(익명클래스)
public int getBatchSize() {
return persons.size();
}
public void setValues(PreparedStatement ps, int index)
throws SQLException {
Person person = (Person)persons.get(index);
int parameterIndex = 1;
ps.setString(parameterIndex++, person.getId());
ps.setString(parameterIndex++, person.getFirstName());
ps.setString(parameterIndex, person.getLastName());
}
};
return this.jdbcTemplate.batchUpdate(sql, setter); //질의문 실행
}//:
4-3-1-8. jdbcTemplate의 query 메소드와 RowMapper 인터페이스
RowMapper 읶터페이스
여러 건의 레코드(여러 person 객체)를 얻을 수 있는 메소드가 필요하다면 RowMapper를 구현
해서 데이터를 추출할 수 있는데 RowMapper는 ResultSet의 SELECT된 레코드와 객체를 매핑 시
키는 역할을 한다.
//레코드(행, 로우)를 매핑할 PersonRowMapper를 RowMapper인터페이스를 구현해서 만든다.
public class PersonRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int index) throws SQLException {
Person person = new Person();
person.setId(new Integer(rs.getInt("id")));
person.setFirstName(rs.getString(“firstname"));
person.setLastName(rs.getString(“lastname"));
return person;
}
}
3. …………
public List getAllPersons() {
String sql = “select id, firstname, lastname from person”;
return jdbcTemplate.query( sql, new PersonRowMapper()); //queryForList
}
}
//아이디를 통해 person 객체를 얻어오는 메소드
public Person getPerson(Integer id) {
String sql = “select id, firstname, lastname from person where id =? “;
Person person = (Person)jdbcTemplate.query(sql, id, new PersonRowMapper());
return person;
}//:
4-3-1-9. jdbcTemplate의 queryForObject, queryForList, 기타 query
메소드
queryForObject : 한 개의 레코드 처리용, 객체타입으로 결과를 리턴해 준다.
public Person getLastNameById(Integer id) {
String sql = "SELECT lastname FROM person WHERE id = ? ";
Object[] args = new Object[] { id }; //?에 대입되는 매개변수
String lastname=(String)this.jdbcTemplate.queryForObject(sql, args, String.class);
return lastname;
}
queryForList : 한 개 이상의 레코드 처리용, 여러건의 레코드를 List 객체로 리턴해 준다.
public List<Person> getAllPerson() {
String sql = "" + "SELECT * FROM person ";
List<Person> persons = this.jdbcTemplate.queryForList(sql, new PersonMapper());
return persons;
}
기타 query 메소드
//queryForInt, queryForLong은 더 이상 사용되지 않는다.
4. String sql = "SELECT count(*) FROM person WHERE id = ?";
int count = jdbcTemplate.queryForObject(sql, new Object[] { id }, Integer.class);
String sql = "SELECT longCol FROM person WHERE id = ?";
long col = jdbcTemplate.queryForObject(sql, new Object[] { id }, Long.class);}
// 아래 double형이나 date형은 queryForObject를 적절히 사용하면 된다.
String sql = " SELECT doubleCol FROM Table ";
Double d = (Double)this.jdbcTemplate.queryForObject(sql, Double.class);
String sql = " SELECT dateCol FROM Table ";
Date d = (Date)this.jdbcTemplate.queryForObject(sql, Date.class);
4-3-1-10. jdbcTemplate을 이용한 CRUD 예제
Spring Boot, MariaDB를 이용해서 EMP 테이블을 만들고 JdbcTemplate을 이용하여 CRUD 기
능을 구현해 보자.
STS에서
File -> New -> Project -> Spring Starter Project
Name : jdbc2
Package : jdbc
다음화면에서 SQL : JDBC, MySQL 선택
MariaDB에서 직접 SQL을 작성하여 테이블 및 데이터를 생성할 수 있지만 스프링 부트
에서는 클래스패스 경로에 schema.sql, data.sql이 존재하면 자동실행 하므로 스키마 생성
부분과 데이터 생성부분을 파읷로 만들어두면 된다.
[src/main/resources/schema.sql]
drop database if exists jdbc2;
create database jdbc2;
use jdbc2;
create table emp
5. (
empno int(4) not null auto_increment,
ename varchar(50),
primary key (empno)
) ENGINE=InnoDB;
[src/main/resources/data.sql(파일 속성에서 text encoding을 UTF-8로)]
insert into emp(ename) values ('1길동');
insert into emp(ename) values ('2길동');
insert into emp(ename) values ('3길동');
[src/main/resources/application.properties]
spring.datasource.platform=mysql
spring.datasource.url=jdbc:mysql://localhost/jdbc2?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=1111
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.sql-script-encoding=UTF-8
#커넥션풀에서 커넥션을 가져올 경우 커넥션이 유효한지 검사
도메인 클래스(Emp.java) – 테이블구조와 동일하다.
package jdbc.domain;
public class Emp {
private Long empno;
private String ename;
public Emp() { }
public Emp(String ename) { this.ename = ename; }
public Emp(Long empno, String ename) {
this.empno = empno;
this.ename = ename;
}
public Long getEmpno() { return empno; }
public void setEmpno(Long empno) {
this.empno = empno;
6. }
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String toString() { return "[empno=" + empno +",ename=" + ename +
"]"; }
}
RowMapper 구현체(EmpRowMapper.java)
package jdbc.repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import jdbc.domain.Emp;
@Repository
public class EmpRowMapper implements RowMapper {
@Override
public Emp mapRow(ResultSet rs, int rowNum) throws SQLException {
Long empno = rs.getLong("empno");
String ename = rs.getString("ename");
return new Emp(empno, ename);
}
}
Repository 인터페이스(EmpRepository.java) – 영속성 서비스용 인터페이스
package jdbc.repository;
8. @Autowired
RowMapper<Emp> empRowMapper;
@Autowired //스프링부트에서 DataSource를 자동 주입해 준다.
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public List<Emp> findAll() {
List<Emp> emps = jdbcTemplate.query("select empno, ename from
emp",empRowMapper);
return emps;
}
@Override
public Emp findOne(Long empno) {
return (Emp)jdbcTemplate.queryForObject("select empno, ename from
emp where empno = ?", empRowMapper, empno);
}
@Override
@Transactional(readOnly=false)
public Emp save(Emp emp) {
SqlParameterSource param = new
BeanPropertySqlParameterSource(emp);
if (emp.getEmpno() == null) {
Number key = jdbcInsert.executeAndReturnKey(param);
emp.setEmpno(key.longValue());
}
else {
this.jdbcTemplate.update(
9. "insert into emp (empno, ename) values (?, ?)",
emp.getEmpno(), emp.getEname()
);
}
return emp;
}
@Override
@Transactional(readOnly=false)
public void delete(Long empno) {
this.jdbcTemplate.update(
"delete from emp where empno = ?",
empno
);
}
//생성자가 실행된 후에 실행된다.
@PostConstruct
public void init() {
//INSERT SQL Auto Create
jdbcInsert = new
SimpleJdbcInsert(jdbcTemplate).withTableName("emp").usingGeneratedKeyColumns("emp
no");
}
}
스프링 부트 메인(Jdbc2Application.java)
package jdbc;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
10. import jdbc.domain.Emp;
import jdbc.repository.EmpRepository;
@SpringBootApplication
public class Jdbc2Application implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(Jdbc2Application.class, args);
}
@Autowired
EmpRepository empRepository;
public void run(String...args) {
//전체 사원 SELECT
List<Emp> emps = empRepository.findAll();
for(Emp e : emps) { System.out.println(e); }
System.out.println("---------------------");
//2번 사원 SELECT
Emp e = empRepository.findOne(2L);
System.out.println(e);
System.out.println("---------------------");
//3번 사원 DELETE
empRepository.delete(3L);
emps = empRepository.findAll();
for(Emp e1 : emps) { System.out.println(e1); }
System.out.println("---------------------");
//4번 사원 INSERT
e = empRepository.save(new Emp(4L, "4길동"));
emps = empRepository.findAll();
for(Emp e1 : emps) { System.out.println(e1); }
System.out.println("---------------------");
//'5길동' 사원 INSERT
Emp e5 = new Emp(“5길동”);
11. e = empRepository.save(e5);
emps = empRepository.findAll();
for(Emp e1 : emps) { System.out.println(e1); }
}
}
[결과]
4-3-1-10. Spring Data JPA를 이용한 CRUD 예제
이전의 예제를 Spring Data JPA를 이용한 형태로 변형하여 작성해 보자.
간단히 Spring Data JPA 구조, 기본적읶 CRUD읶 경우 쿼리를 직접 만들지 않아도 된다는 것
만 확읶하자.
마리아DB는 아래 URL을 참조하여 설치하자.
http://ojc.asia/bbs/board.php?bo_table=LecSpring&wr_id=524
STS에서 File -> New -> Project -> Spring Starter Project
Name : springjpa, Package name : jpa
다음화면에서 SQL-> JPA, MySQL 선택
src/main/resources/data.sql(파일 속성에서 text encoding을 UTF-8로)
12. insert into emp(ename) values ('1길동');
insert into emp(ename) values ('2길동');
insert into emp(ename) values ('3길동');
Spring Data JPA는 테이블을 자동으로 생성하므로 이전 예제에서 작성한 schema.sql은 필요 없다.
src/main/resources/application.properties(파일 속성에서 text encoding을 UTF-8로)
spring.datasource.platform=mysql
spring.datasource.url=jdbc:mysql://localhost/emp2?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=1111
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.sql-script-encoding=UTF-8
# 자동으로 DDL을 만들어 테이블 생성
spring.jpa.hibernate.ddl-auto=create
# 실행되는 SQL문을 로그에서 보이도록
spring.jpa.show-sql=true
도메인 클래스(Emp.java) – 테이블구조와 동일하다.
package jpa.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Emp {
@Id //PK임을 지정
@GeneratedValue //자동증분 칼럼
private Long empno;
//@Column 어노테이션이없더라도 테이블 칼럼명과 자동 매핑
private String ename;
public Emp() { }
public Emp(String ename) { this.ename = ename; }
public Emp(Long empno, String ename) { this.empno = empno; this.ename = ename; }
public Long getEmpno() { return empno; }
public void setEmpno(Long empno) { this.empno = empno; }
public String getEname() { return ename; }
public void setEname(String ename) { this.ename = ename; }
public String toString() { return "[empno=" + empno +",ename=" + ename + "]";}
13. }
Repository 인터페이스(EmpRepository.java) – 영속성 서비스용 인터페이스
package jpa.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import jpa.domain.Emp;
/*
* JpaRepository에는 기본적인 CRUD(findAll, findOne, save, delete, deleteAll) 메소드가
* 정의되어 있으며 이를 상속한 인터페이스를 만듦으로써 구현클래스 없이 레포지터리 구성이
가능하다. 제너릭으로 도메인 클래스와 키칼럼(ID칼럼)의 타입을 기술하면 된다.
*/
public interface EmpRepository extends JpaRepository<Emp, Long> { }
스프링 부트 메인(SpringjpaApplication.java)
package jpa;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import jpa.domain.Emp;
import jpa.repository.EmpRepository;
@SpringBootApplication
public class SpringjpaApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringjpaApplication.class, args); }
@Autowired
EmpRepository empRepository;
public void run(String...args) {
14. //전체 사원 SELECT
List<Emp> emps = empRepository.findAll();
for(Emp e : emps) { System.out.println(e); }
System.out.println("---------------------");
//2번 사원 SELECT
Emp e = empRepository.findOne(2L);
System.out.println(e);
System.out.println("---------------------2번사원 SELECT");
//3번 사원 DELETE
empRepository.delete(3L);
emps = empRepository.findAll();
for(Emp e1 : emps) { System.out.println(e1); }
System.out.println("---------------------3번 DELETE후");
//4번 사원 INSERT
e = empRepository.save(new Emp(4L, "4길동"));
emps = empRepository.findAll();
for(Emp e1 : emps) { System.out.println(e1); }
System.out.println("---------------------4번 INSERT후");
//'5길동' 사원 INSERT
Emp e5 = new Emp(“5길동”);
e = empRepository.save(e5);
emps = empRepository.findAll();
for(Emp e1 : emps) {
System.out.println(e1);
}
System.out.println("---------------------5번 INSERT후");
//'5길동' 사원 이름 수정
e = empRepository.findOne(5L);
e.setEname("수정된5길동");
empRepository.save(e);
emps = empRepository.findAll();
for(Emp e1 : emps) {