복붙노트

[SPRING] Spring RowMapper 인터페이스는 정확히 어떻게 작동합니까?

SPRING

Spring RowMapper 인터페이스는 정확히 어떻게 작동합니까?

저는 Spring 핵심 인증을 받기 위해 공부하고 있으며 Spring의 JDBC 쿼리 처리 방법에 대한 몇 가지 의구심이 있습니다.

그래서 나는 내가 얻을 것으로 기대되는 데이터 유형에 따라 다양한 방법으로 DB 테이블에서 데이터를 얻을 수 있다는 것을 알고 있습니다.

1) 간단한 유형의 쿼리 (int, long 또는 String) : jdbcTemplate 클래스의 queryForObject () 메소드를 사용합니다.

String sql = "SELECT count(*) FROM T_REWARD";
int rowsNumber = jdbcTemplate.queryForObject(sql, Integer.class);

int 값으로 간단한 객체를 얻으려면 queryForObject () 메서드를 사용하여 sql stattment 및 메서드의 출력에서받을 것으로 예상되는 객체 유형을 전달하십시오.

좋아, 이것은 꽤 간단하고 나는 괜찮다고 생각한다.

2) Map 객체에 퍼팅 된 전체 테이블 행에 대한 쿼리 : 따라서 단일 값 (테이블의 특정 행에있는 단일 열 또는 이와 유사한 예가 될 수 있음)이 필요하지 않으면 queryForMap ( ..) 및 queryForList () 메소드를 다음과 같이 사용합니다.

2.1) queryForMap () : 각 행 값이 내 맵에 맵핑되는 단일 맵 오브젝트로 퍼팅되는 단일 행을 예상하는 경우이를 사용합니다.

String sql = "select * from T_REWARD where CONFIRMATION_NUMBER = ?";
Map<String, Object> values = jdbcTemplate.queryForMap(sql,confirmation.getConfirmationNumber());

2.2) queryForList () : 쿼리 결과가 더 많은 행을 기대할 때 사용합니다. 그래서 각 Map 객체가 질의 출력의 특정 행을 나타내는 Map 객체 목록을 얻을 것입니다. 그것을 좋아하는 것 :

String sql = “select * from PERSON”;
return jdbcTemplate.queryForList(sql);

나는 이것이 또한 꽤 분명하다고 생각한다.

그렇다면 JdbcTemplate을 사용하여 ResultSet을 도메인 객체에 매핑 할 수 있습니다.

문서를 읽는 것은 JdbcTemplate이 콜백 접근법을 사용하여이를 지원한다는 것이다. 정확히이 콜백 접근법은 무엇입니까?

Spring이 ResultSet의 단일 행을 객체에 매핑하기위한 RowMapper 인터페이스를 제공한다는 것을 알고있다.

public interface RowMapper<T> {
    T mapRow(ResultSet rs, int rowNum)
    throws SQLException;
}

이 메서드는 새로운 RestaurandRowMapper 객체를 queryForObject () 메서드의 반환 된 객체로 사용하는 다음과 같은 예제를 작성했습니다.

public Restaurant findByMerchantNumber(String merchantNumber) {
    String sql = "select MERCHANT_NUMBER, NAME, BENEFIT_PERCENTAGE, BENEFIT_AVAILABILITY_POLICY from T_RESTAURANT where MERCHANT_NUMBER = ?";

    return jdbcTemplate.queryForObject(sql, new RestaurantRowMapper(), merchantNumber);

그리고이 내부 클래스 :

class RestaurantRowMapper implements RowMapper<Restaurant> {
    public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
        return mapRestaurant(rs);
    }
}

이 private 메서드를 사용하여 매핑을 만듭니다.

private Restaurant mapRestaurant(ResultSet rs) throws SQLException {
    // get the row column data
    String name = rs.getString("NAME");
    String number = rs.getString("MERCHANT_NUMBER");
    Percentage benefitPercentage = Percentage.valueOf(rs.getString("BENEFIT_PERCENTAGE"));
    // map to the object
    Restaurant restaurant = new Restaurant(number, name);
    restaurant.setBenefitPercentage(benefitPercentage);
    restaurant.setBenefitAvailabilityPolicy(mapBenefitAvailabilityPolicy(rs));
    return restaurant;
}

그래서 나는이 모든 것들이 정확히 어떻게 작동 하는지를 이해하는 데 약간의 어려움이 있습니다.

내 주된 의심은 다음과 같습니다. queryForObject () 메서드를 사용하면 입력 매개 변수로 전달할 객체의 유형 (예 : Interger 또는 Long)을 전달한다는 것을 알고 있습니다.

테이블의 전체 행 (예 : Restaurand 객체에 매핑 된 Restaurant 테이블의 행)을 나타내는 도메인 객체를 얻으려는 경우이 객체를 Restaurant 객체로 사용해야한다고 생각하지만 이전 예제 도메인 객체 대신 ** 행 매퍼 객체를 사용합니다.

return jdbcTemplate.queryForObject(sql, new RestaurantRowMapper(), merchantNumber);

이 내부 클래스에는 예상 도메인 객체를 반환하는 mapRow () 메서드 만 포함되어 있습니다.

class RestaurantRowMapper implements RowMapper<Restaurant> {
    public Restaurant mapRow(ResultSet rs, int i) throws SQLException {
        return mapRestaurant(rs);
    }
}

그래서 스프링은 자동으로 queryForObject () 메소드 나 이와 비슷한 것으로 Restaurand 도메인 객체를 반환하는 mapRow () 메소드를 호출한다고 생각합니다. 그러나 정확하게 작동하는지 나는 확신하지 못한다.

내가 뭘 놓치고 있니? 무대 뒤에서 정확히 무슨 일이 일어 났는지 설명해 주시겠습니까?

Txx

해결법

  1. ==============================

    1.queryForObject 메소드는 다음과 같습니다.

    queryForObject 메소드는 다음과 같습니다.

    public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
        List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));
        return DataAccessUtils.requiredSingleResult(results);
    }
    

    queryForObject-method는 내부적으로 JdbcTemplate 오브젝트에서 메소드 조회를 호출합니다. query-method는 다음과 같이 정의됩니다.

    public <T> T query(
            PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
            throws DataAccessException;
    

    보시다시피 ResultSetExtractor 가 query-method에 전달되고 Spring은 RowMapper 를 new RowMapperResultSetExtractor (rowMapper, 1) 유형의 객체로 편리하게 변환합니다. RowMapperResultSetExtractor는 마법에 대한 열쇠를 보유하고있는 객체입니다. 객체가 호출되면이 스 니펫에 따라 모든 행이 반복됩니다.

    public List<T> extractData(ResultSet rs) throws SQLException {
        List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>());
        int rowNum = 0;
        while (rs.next()) {
            results.add(this.rowMapper.mapRow(rs, rowNum++));
        }
        return results;
    }
    

    따라서 원래 RowMapper는 각 행에 대해 호출되는 콜백입니다. 또한 여기에서 볼 수 있듯이 일치하는 모든 결과에 대해 RowMapper가 호출되고 사용자가 만든 Restaurant-object가 결과 목록에 추가됩니다. 그러나 하나의 객체 만 쿼리하면 마침내 다음 명령문이 단일 Restaurant 객체를 반환하는 데 사용됩니다.

            return DataAccessUtils.requiredSingleResult(results);
    

    요약하자면, JdbcTempalte는 Strategy Pattern (Template 메소드 패턴과 유사 함)을 구현한다. 그리고 Strategy 인터페이스 (RowMapper)를 제공함으로써 JdbcTemplate이 당신을 위해 무거운 짐을 처리하도록 할 수 있습니다 (예외, 연결 처리 등). RowMapper는 각 히트를 POJO (레스토랑)로 매핑하고 모든 히트는 List에 수집됩니다. 그런 다음 queryForObject 메소드는 해당 List의 첫 x 째 행을 취하여 호출자에게 리턴합니다. 반환 값은 Restaurant에있는 RowMapper의 제네릭 형식을 기반으로합니다.

  2. ==============================

    2.jdbcTemplate.queryForObject를 사용하면 다음과 같이 문제를 해결할 수 있습니다.

    jdbcTemplate.queryForObject를 사용하면 다음과 같이 문제를 해결할 수 있습니다.

    public YourPojo getDatabaseDetails(int masterId) {
    
        sql = "Select * FROM <table_name> where ID=?";
        YourPojo pojo = (YourPojo) jdbcTemplate.queryForObject(sql,
                new Object[] { masterId }, new RowMapper<YourPojo>() {
                    @Override
                    public <YourPojo> mapRow(ResultSet rs, int rowNum)
                            throws SQLException {
                        YourPojo pojo2 = new YourPojo();
                        pojo2.setAccountId(rs.getString("AccountId"));
                        pojo2.setAccountName(rs.getString("AccountName"));
                        pojo2.setAccountCRN(rs.getString("AccountCRN"));
                        pojo2.setAccountStatus(rs.getString("AccountStatus"));
                        return pojo2;
                    }
                });
        return pojo;
    }
    
  3. from https://stackoverflow.com/questions/27591847/how-exactly-work-the-spring-rowmapper-interface by cc-by-sa and MIT license