[SPRING] Spring RowMapper 인터페이스는 정확히 어떻게 작동합니까?
SPRINGSpring 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.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.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; }
from https://stackoverflow.com/questions/27591847/how-exactly-work-the-spring-rowmapper-interface by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Jspx 파일 및 조건부 주석 (0) | 2019.03.31 |
---|---|
[SPRING] 어노테이션으로 최대 절전 모드에서 데이터베이스 스키마의 유효성을 검사하는 방법 (0) | 2019.03.31 |
[SPRING] Spring MVC에서 http 요청 헤더를 기반으로 json을 동적으로 멋지게 출력하는 방법은 무엇입니까? (0) | 2019.03.31 |
[SPRING] 복잡한 관계가있는 엔티티를 저장할 때의 StaleStateException (0) | 2019.03.31 |
[SPRING] 데이터베이스의 Spring 설정 (0) | 2019.03.31 |