JPA

JPA Null 처리 방법, List가 null이 아닌 이유

du.study 2020. 9. 15. 00:10
728x90

 

이번에는 자바로 JPA Null 처리하는 방법에 대해 기록하려합니다.

 

당연하게 db조회시, 객체가 없을경우 null이 발생할 수 있고, 우리는 null을 대비해야만 합니다.

 

1. Optional 

이전에 Java8 부터 등장한 Optional에 대해 포스팅을 한 적이 있습니다.

duooo-story.tistory.com/38?category=881766

 

Java Optional 사용하기

이번에는 Optional 사용법에 대해 기록해보려 합니다. 먼저 Optional은 NULL 처리( 또는 반환값이 없는 ) 에 유용하게 사용되며 이 덕분에 런타임에서 발생되는 NullPointerException를 좀 더 깔끔하도록?(사�

duooo-story.tistory.com

JPA에서 단일 엔티티를 조회하는 경우, Optional을 사용하게 되어있습니다. 해당 부분으로 인하여 좀더 우아하게? null을 막을 수 있습니다. 

public interface AccountRepository extends JpaRepository<Account,Long> {
	Optional<Account> findById(Long id);
}

or

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
	Optional<T> findById(ID id);    
}

Optional사용법은 위 포스팅을 참고 부탁드립니다.

 

 

이번에는 단일 entity가 아닌 List를 받는경우를 살펴보겠습니다.

우선 결과부터 작성하면 List로 받는 객체의 경우, null이 아닌 Empty List가 내려옵니다.

 

그렇다면 왜 그렇게 내려오는지를 확인하기위해 테스트를 진행하고자 몇가지의 코드를 작성했습니다.

// 1
(CrudRepository) findAll()

public interface AccountRepository extends JpaRepository<Account,Long> {
    // 2
    List<Account> findByIdGreaterThan(Long id);

    // 3
    @Query( value = "select myAccount from myAccount a where a.id > 1" ,nativeQuery = true)
    List<Account> findAccountList(Long id);
}

 

 

1) 우선 기본 CrudRepository 에 있는 findAll을 살펴봤습니다.

기본 findAll 호출시, SimpleJpaRepository를 통해 findAll을 타고 들어가다 보면 다음과 같은 과정을 타게 됩니다.

 

- CriteriaQueryTypeQueryAdapter 에 있는 getResultList() 호출,

- org.hibernate.loader 에 processResultSet 과정을 통해 빈리스트 리턴

public List<X> getResultList() {
	return jpqlQuery.getResultList();
}
-------------------------------------------

protected List processResultSet(
			ResultSet rs,
			QueryParameters queryParameters,
			SharedSessionContractImplementor session,
			boolean returnProxies,
			ResultTransformer forcedResultTransformer,
			int maxRows,
			List<AfterLoadAction> afterLoadActions) throws SQLException {
            
	....
	final List results = new ArrayList();
	....

	final boolean debugEnabled = LOG.isDebugEnabled();
	for ( count = 0; count < maxRows && rs.next(); count++ ) {
		....
		Object result = getRowFromResultSet(
			rs,
			session,
			queryParameters,
			lockModesArray,
			optionalObjectKey,
			hydratedObjects,
			keys,
			returnProxies,
			forcedResultTransformer
		);
		results.add( result );
		....
	}
	....

	return results;
}

 

2) method Keyword를 통해 쿼리를 작성하고 리스트를 가져오는 경우에도 거의 비슷한 경우입니다.

static class CollectionExecution extends JpaQueryExecution {
	@Override
	protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
		return query.createQuery(accessor).getResultList();
	}
}

public List<X> getResultList() {
	return jpqlQuery.getResultList();
}

- JpaQueryExecution에 있는 

- 이후 과정 위와 동일

 

 

3) 마지막으로 native Query를 이용하여 조회하는 경우,  2)와 동일한 과정을 통하여 결국 빈 리스트를 가져오게 됩니다.

 

다른 List조회 쿼리 생성방법이 많겠지만, 아마 거의 유사하거나 동일한 과정을 통해 결국 빈값을 가져오리라 생각합니다. 혹시 다른 케이스가 나오신다면 공유..! 부탁드립니다!

 

728x90