Skip to content

Instantly share code, notes, and snippets.

@jjangga0214
Last active October 6, 2022 12:11
Show Gist options
  • Save jjangga0214/2dc6b788b8db74aadffb1625d6e7f6de to your computer and use it in GitHub Desktop.
Save jjangga0214/2dc6b788b8db74aadffb1625d6e7f6de to your computer and use it in GitHub Desktop.
JPQL 로 시간 조건걸기

JPQL 로 시간 조건걸기

일반적으로 시간을 다루는 연산은 그 종류가 많고, 다소 복잡합니다. 예를 들어, 시간대, 시간 타입 (DATE 인지 DATETIME 인지 Timestamp 인지, 혹은.. String인지 등), 단위 연산( [초, 분, 시, 날, 월, 년] * [덧셈, 뺄셈] ) 등 처리할 것이 많습니다. 기본적으로 sql 은 dsl 이므로 완전 선언적 인 언어입니다. 선언적인 언어의 약점은 아주 잘 정의하지 않으면 이런 복잡한 여러 case 들을 처리하기 번거로울 수 있다는 것이죠. 때문에 어플리케이션 영역에서 시간 객체를 조건에 알맞게 수정해서 sql 에서는 간단한 비교만 가능하게 하는 것이 좋습니다. jpql 도 sql 과 맥락이 같기 때문에, jpql 내부에서 기본타입이 아니거나 시간처럼 복잡한 연산을 하는 것은 피하는 것이 필요합니다.

setup

Spring Data JPA를 사용하고, Foo Entity와 timelog(시작시간) 속성을 가정했습니다.

Repository

어플리케이션 level 에서 시간을 조절하기 위해, 시간 대소를 비하는 메서드를 선언하고, facade pattern 으로 현재시간으로부터 10분 전까지 select 하는 method 를 추가선언했습니다.

@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

    @Query("select f from Foo f where f.timelog < :threshold ")
    List<Foo> findByTimelogLessThan(@Param("threshold") LocalDateTime threshold);

    default List<Foo> findOlds() {
        long minutesGap = 10; // 허용 갭이 10분이라 가정
        return findByTimelogLessThan(LocalDateTime.now().minusMinutes(minutesGap));
    }
}

위에서는 JPQL 을 쓰는 것을 가정했지만, 만약 시간만 비교하는 것이라면, Spring Data JPA 의 장점을 사용해, 아래처럼 @Query 없이 메서드 시그지처만으로도 같은 쿼리가 가능합니다. findBy속성명+조건

List<Product> findByTimelogLessThan(LocalDateTime threshold);

Test

다음 test는 pass합니다.

import static org.junit.Assert.assertEquals;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class FooRepositoryTests {

    @Autowired
    private FooRepository fooRepository;

    @Before
    public void setUp() {

        Foo f1 = new Foo();
        f1.setTimelog(LocalDateTime.now().minusMinutes(12)); //12분 전 => select 되어야 함.

        Foo f2 = new Foo();
        f2.setTimelog(LocalDateTime.now().minusMinutes(8)); //8분 전 => select 되지 말아야 함.

        fooRepository.saveAll(Arrays.asList(f1, f2));
    }

    @Test
    public void test(){
        List<Foo> foos = fooRepository.findOlds();
        //::setUp 에서 12분 전으로 설정하고 저장한 record 만 select 된다.
        assertEquals(1, foos.size());
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment