티스토리 뷰

Framework/Spring

Spring JDBC 실습

Seogineer 2021. 1. 4. 17:05

파일 구조

ㄴconfig
    ㄴApplicationConfig.java
    ㄴDBConfig.java
ㄴdao
    ㄴRoleDao.java
ㄴdto
    ㄴRole.java
ㄴmain
    ㄴTest.java

 

pom.xml 설정 및 DAO 작성

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <spring.version>5.1.5.RELEASE</spring.version>
</properties>

<dependencies>
  <!-- Spring -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <!-- basic data source -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.1.1</version>
  </dependency>

  <!-- mariaDB -->
  <dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>2.7.0</version>
  </dependency>
</dependencies>

 

Role.java

public class Role {
    private int roleId;
    private String description;
    public int getRoleId() {
        return roleId;
    }
    public void setRoleId(int roleId) {
        this.roleId = roleId;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    @Override
    public String toString() {
        return "Role [roleId=" + roleId + ", description=" + description + "]";
    }
}

 

ApplicatoinConfig.java

@Configuration
@ComponentScan(basePackages = { "kr.or.connect.daoexam.dao" })
@Import({ DBConfig.class })
public class ApplicationConfig {

}

 

DBConfig.java

@Configuration
@EnableTransactionManagement
public class DBConfig {
    private String driverClassName = "org.mariadb.jdbc.Driver";
    private String url = "jdbc:mariadb://localhost:3306/connectdb?useUnicode=true&characterEncoding=utf8";

    private String username = "connectuser";
    private String password = "connect123!@#";

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

 

JdbcTemplate 클래스를 이용한 RoleDao.java 작성

@Repository
public class RoleDao {
    private JdbcTemplate jdbc;
    private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);

    public RoleDao(DataSource dataSource) {
        this.jdbc = new JdbcTemplate(dataSource);
    }

    public int jdbcTest01() {
        return this.jdbc.queryForObject("select count(*) from role", Integer.class);
    }

    public int jdbcTest02(int roleId) {
        try {
            return this.jdbc.queryForObject("select count(*) from role where role_id = ?", Integer.class, roleId);
        } catch (EmptyResultDataAccessException e) {
            return 0;
        }

    }

    public String jdbcTest03(int roleId) {
        try {
            return this.jdbc.queryForObject("select description from role where role_id = ?", new Object[]{roleId}, String.class);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }

    }

    public Role jdbcTest04(int roleId) {
        try {
            return this.jdbc.queryForObject("select * from role where role_id = ?", new Object[]{roleId}, rowMapper);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    public List<Role> jdbcTest05() {
        return (List<Role>) this.jdbc.query("select * from role", rowMapper);
    }

    public int jdbcTest06(int roleId, String description) {
        return this.jdbc.update("insert into role values (?, ?)",  roleId, description);
    }

    public int jdbcTest07(int roleId, String description) {
        return this.jdbc.update("update role set description = ? where role_id = ?", description, roleId);
    }

    public int jdbcTest08(int roleId) {
        return this.jdbc.update("delete from role where role_id = ?", roleId);
    }
}

 

NamedParameterJdbcTemplate 클래스를 이용한 RoleDao.java 작성

@Repository
public class RoleDao {
    private NamedParameterJdbcTemplate jdbc;
    private SimpleJdbcInsert insertAction;
    private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);
    
    //스프링4.0 이상부터 @Autowired 없어도 Bean 객체라면 의존성이 주입된다.
    public RoleDao(DataSource dataSource) {
        this.jdbc = new NamedParameterJdbcTemplate(dataSource);
        this.insertAction = new SimpleJdbcInsert(dataSource).withTableName("role");
    }

    public List<Role> selectAll() {
        //NamedJdbcTemplate은 Map을 이용해서 값을 바인딩하는데 바인딩할 값이 없기 때문에 emptyMap을 넣어줌
        return jdbc.query("SELECT role_id, description FROM role order by role_id", Collections.emptyMap(), rowMapper);
    }

    public int insert(Role role) {
    	//role객체를 Map객체로 변환
        SqlParameterSource params = new BeanPropertySqlParameterSource(role);
        return insertAction.execute(params);
    }

    public int update(Role role) {
        SqlParameterSource params = new BeanPropertySqlParameterSource(role);
        return jdbc.update("UPDATE role SET description = :description WHERE role_id = :roleId", params);
    }

    public int deleteById(Integer id) {
        Map<String, ?> params = Collections.singletonMap("roleId", id);
        return jdbc.update("DELETE FROM role WHERE role_id = :roleId", params);
    }

    public Role selectById(Integer id) {
        try {
            Map<String, ?> params = Collections.singletonMap("roleId", id);
            return jdbc.queryForObject("SELECT role_id, description FROM role WHERE role_id = :roleId", params, rowMapper);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }
}

 

다건 Select

ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);    
RoleDao roleDao = ac.getBean(RoleDao.class);
List<Role> list = roleDao.selectAll();
for(Role role : list) {
    System.out.println(role);
}

 

단건 Select

ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);        
Role resultRole = roleDao.selectById(201);
System.out.println(resultRole);

 

Insert

ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
Role role = new Role();
role.setRoleId(201);
role.setDescription("PROGRAMMER");
int count = roleDao.insert(role);
System.out.println(count + "건 입력하였습니다.");

 

Update

ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
Role role = new Role();
role.setRoleId(201);
role.setDescription("PROGRAMMER");
int count = roleDao.update(role);
System.out.println(count + "건 수정하였습니다.");

 

Delete

ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);   
int deleteCount = roleDao.deleteById(201);
System.out.println(deleteCount + "건 삭제하였습니다.");

 

사용된 Class와 Method

  1. SimpleJdbcInsert
    • 인스턴스화해서 사용한다.
    • 초기화에 DataSource를 인자로 받는다.
    • withTableName으로 테이블명을 설정한다.
    • execute() 메소드의 파라미터로 java.utils.Map을 받는다.
    • 이때 Map에 사용한 키는 데이터베이스에 정의한 테이블의 컬럼명과 일치해야 한다.
  2. RowMapper
    • SQL의 결과(record type)를 객체(object type)에 Mapping하여 리턴한다.
  3. BeanPropertyRowMapper.newInstance()
    • Bean 객체를 기반으로 RowMapper를 생성해주는 메서드
  4. BeanPropertySqlParameterSource
    • BeanPropertySqlParameterSource는 SqlParameterSource 인터페이스를 구현한 클래스이다.
    • SQL에 들어갈 SqlParameterSource 객체를 생성한다.
    • Bean 객체를 Map 객체로 변환한다.
    • 생성할 때 JavaBeans를 넣어주면 JavaBeans 변수명과 쿼리안의 :변수명을 자동으로 Mapping 시켜준다.
  5. Collections.singletonMap()
    • key-value쌍이 단 하나인 Map을 만들어야 하는 경우 사용.
  6. Collections.emptyMap()
    • 외부에서 반환한 데이터가 없거나 내부 로직에 의해 빈 데이터가 반환되어야 하는 경우 NullPointerException을 방지하기 위하여 반환 형태에 따라 List나 Map의 인스턴스를 생성하여 반환하여 처리해야 하는 경우에 사용한다.
    • 후속 로직에서 size 메소드 등으로 체크를 하고 추가적인 값을 변경하지 않은 경우 매번 동일한 정적 인스턴스가 반환되므로 각 호출에 대해 불필요한 인스턴스 생성이 되지 않아 메모리 사용량을 줄일 수 있다.
    • Collections.emptyList()나 Collections.emptyMap() 메소드로 반환된 객체에 add 혹은 put 메소드를 호출하는 경우 UnsupportedOperationException이 발생하므로 추가적인 데이터 수정을 하지 않는 경우에만 사용해야 한다.

 

참조
www.boostcourse.org/web316/lecture/254338/
https://www.boostcourse.org/web316/lecture/254339/
https://www.boostcourse.org/web316/lecture/254340/
https://www.boostcourse.org/web316/lecture/254341/

rio-kim.github.io/java/2018/06/27/make_easy_java_collection_code/

blog.outsider.ne.kr/883

velog.io/@lacomaco/Spring-Jdbc-Template-%EC%8B%A4%EC%8A%B5-%EC%A0%95%EB%A6%AC

gmlwjd9405.github.io/2018/12/19/jdbctemplate-usage.html

winmargo.tistory.com/118

lucaskim.tistory.com/41

'Framework > Spring' 카테고리의 다른 글

Spring MVC 설정  (0) 2021.01.06
Spring MVC  (0) 2021.01.06
Spring JDBC  (0) 2021.01.04
Inversion of Control / Dependency Injection  (0) 2021.01.01
Spring Container metadata 설정 방법  (0) 2021.01.01
댓글
Total
Today
Yesterday
링크
Apple 2023 맥북 프로 14 M3, 스페이스 그레이, M3 8코어, 10코어 GPU, 512GB, 8GB, 한글