2024.03.17 - [프로그래밍언어/JAVA] - 순수 JAVA JPA

순수 JAVA JPA

https://docs.spring.io/spring-framework/reference/data-access/orm/jpa.html JPA :: Spring FrameworkAs an alternative to JpaTransactionManager, Spring also allows for multi-resource transaction coordination through JTA, either in a Jakarta EE environment or

kwaksh2319.tistory.com

https://github.com/hibernate/

Hibernate

Hibernate has 55 repositories available. Follow their code on GitHub.

github.com

먼저 hibernate 란 뭘까? 
Hibernate는 자바 기반의 객체 관계 매핑(ORM) 라이브러리입니다. ORM은 객체 지향 프로그래밍 언어를 사용하여 데이터베이스와의 상호작용을 추상화하는 프로그래밍 기법 중 하나로, 개발자가 객체 지향적인 방식으로 데이터베이스를 다룰 수 있게 해줍니다. Hibernate는 이 ORM을 구현한 대표적인 프레임워크 중 하나입니다.
Hibernate의 주요 목적은 Java 어플리케이션에서 사용하는 데이터베이스 작업을 단순화하고, 데이터베이스와 객체 사이의 불일치를 해결하는 것입니다. 이를 통해 개발자는 복잡한 JDBC(Java Database Connectivity) 코드를 작성하는 대신, 더 간결하고 객체 지향적인 코드로 데이터베이스 작업을 수행할 수 있습니다.
-chat gpt-
chat gpt 선생님께서는 이렇게 설명하신다.역시나 정확하시다. 
 
그렇다면 hibrernate의 github을 통해서 코드와 현재 사용중인 내 코드와 비교하면서 확인해보자.
https://github.com/hibernate/hibernate-orm

GitHub - hibernate/hibernate-orm: Hibernate's core Object/Relational Mapping functionality

Hibernate's core Object/Relational Mapping functionality - hibernate/hibernate-orm

github.com

 

일반적으로  gradle을 이용하면  hibernate를 사용할수 있습니다.
실제 라이브러리는

이런식으로 있습니다. hibernate 대략적인 구조를 보죠.

출처: https://docs.jboss.org/hibernate/orm/6.5/userguide/html_single/Hibernate_User_Guide.html
https://docs.jboss.org/hibernate/orm/6.5/userguide/html_single/Hibernate_User_Guide.html

유저 가이드를 통해서 보면 이런식으로 되어있습니다.
그렇다면 대략적인 형태를 보았으니 코드로 확인해보자! 
 
spring jpa 의 순수 jpa에서 확인할수 잇지만 필자는 spring jpa로 개발을 많이 하기때문에 spring jpa 로 확인해보겠습니다.
 
jpaRepostory의 구현체이다. 
SimpleJpaRepository 클래스 실제로 실행된다면 아래의 클래스가 jpaRepostory가 실행됩니다.
여기서 라이브러리를 보면 

package org.springframework.data.jpa.repository.support;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.ProxyUtils;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

@Repository
@Transactional(
    readOnly = true
)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
    private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";
    private final JpaEntityInformation<T, ?> entityInformation;
    private final EntityManager em;
    private final PersistenceProvider provider;
    @Nullable
    private CrudMethodMetadata metadata;
    private EscapeCharacter escapeCharacter;

    public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        this.escapeCharacter = EscapeCharacter.DEFAULT;
        Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");
        Assert.notNull(entityManager, "EntityManager must not be null!");
        this.entityInformation = entityInformation;
        this.em = entityManager;
        this.provider = PersistenceProvider.fromEntityManager(entityManager);
    }

    public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
        this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
    }

    public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
        this.metadata = crudMethodMetadata;
    }

    public void setEscapeCharacter(EscapeCharacter escapeCharacter) {
        this.escapeCharacter = escapeCharacter;
    }

    @Nullable
    protected CrudMethodMetadata getRepositoryMethodMetadata() {
        return this.metadata;
    }

    protected Class<T> getDomainClass() {
        return this.entityInformation.getJavaType();
    }

    private String getDeleteAllQueryString() {
        return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());
    }

    private String getCountQueryString() {
        String countQuery = String.format("select count(%s) from %s x", this.provider.getCountQueryPlaceholder(), "%s");
        return QueryUtils.getQueryString(countQuery, this.entityInformation.getEntityName());
    }

    @Transactional
    public void deleteById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        this.delete(this.findById(id).orElseThrow(() -> {
            return new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", this.entityInformation.getJavaType(), id), 1);
        }));
    }

    @Transactional
    public void delete(T entity) {
        Assert.notNull(entity, "Entity must not be null!");
        if (!this.entityInformation.isNew(entity)) {
            Class<?> type = ProxyUtils.getUserClass(entity);
            T existing = this.em.find(type, this.entityInformation.getId(entity));
            if (existing != null) {
                this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));
            }
        }
    }

    @Transactional
    public void deleteAllById(Iterable<? extends ID> ids) {
        Assert.notNull(ids, "Ids must not be null!");
        Iterator var2 = ids.iterator();

        while(var2.hasNext()) {
            ID id = var2.next();
            this.deleteById(id);
        }

    }

    @Transactional
    public void deleteAllByIdInBatch(Iterable<ID> ids) {
        Assert.notNull(ids, "Ids must not be null!");
        if (ids.iterator().hasNext()) {
            if (this.entityInformation.hasCompositeId()) {
                List<T> entities = new ArrayList();
                ids.forEach((id) -> {
                    entities.add(this.getReferenceById(id));
                });
                this.deleteAllInBatch(entities);
            } else {
                String queryString = String.format("delete from %s x where %s in :ids", this.entityInformation.getEntityName(), this.entityInformation.getIdAttribute().getName());
                Query query = this.em.createQuery(queryString);
                if (Collection.class.isInstance(ids)) {
                    query.setParameter("ids", ids);
                } else {
                    Collection<ID> idsCollection = (Collection)StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toCollection(ArrayList::new));
                    query.setParameter("ids", idsCollection);
                }

                query.executeUpdate();
            }

        }
    }

    @Transactional
    public void deleteAll(Iterable<? extends T> entities) {
        Assert.notNull(entities, "Entities must not be null!");
        Iterator var2 = entities.iterator();

        while(var2.hasNext()) {
            T entity = var2.next();
            this.delete(entity);
        }

    }

    @Transactional
    public void deleteAllInBatch(Iterable<T> entities) {
        Assert.notNull(entities, "Entities must not be null!");
        if (entities.iterator().hasNext()) {
            QueryUtils.applyAndBind(QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName()), entities, this.em).executeUpdate();
        }
    }

    @Transactional
    public void deleteAll() {
        Iterator var1 = this.findAll().iterator();

        while(var1.hasNext()) {
            T element = var1.next();
            this.delete(element);
        }

    }

    @Transactional
    public void deleteAllInBatch() {
        this.em.createQuery(this.getDeleteAllQueryString()).executeUpdate();
    }

    public Optional<T> findById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        Class<T> domainType = this.getDomainClass();
        if (this.metadata == null) {
            return Optional.ofNullable(this.em.find(domainType, id));
        } else {
            LockModeType type = this.metadata.getLockModeType();
            Map<String, Object> hints = new HashMap();
            this.getQueryHints().withFetchGraphs(this.em).forEach(hints::put);
            return Optional.ofNullable(type == null ? this.em.find(domainType, id, hints) : this.em.find(domainType, id, type, hints));
        }
    }

    protected QueryHints getQueryHints() {
        return (QueryHints)(this.metadata == null ? NoHints.INSTANCE : DefaultQueryHints.of(this.entityInformation, this.metadata));
    }

    /** @deprecated */
    @Deprecated
    public T getOne(ID id) {
        return this.getReferenceById(id);
    }

    /** @deprecated */
    @Deprecated
    public T getById(ID id) {
        return this.getReferenceById(id);
    }

    public T getReferenceById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        return this.em.getReference(this.getDomainClass(), id);
    }

    public boolean existsById(ID id) {
        Assert.notNull(id, "The given id must not be null!");
        if (this.entityInformation.getIdAttribute() == null) {
            return this.findById(id).isPresent();
        } else {
            String placeholder = this.provider.getCountQueryPlaceholder();
            String entityName = this.entityInformation.getEntityName();
            Iterable<String> idAttributeNames = this.entityInformation.getIdAttributeNames();
            String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);
            TypedQuery<Long> query = this.em.createQuery(existsQuery, Long.class);
            if (!this.entityInformation.hasCompositeId()) {
                query.setParameter((String)idAttributeNames.iterator().next(), id);
                return (Long)query.getSingleResult() == 1L;
            } else {
                Iterator var7 = idAttributeNames.iterator();

                while(var7.hasNext()) {
                    String idAttributeName = (String)var7.next();
                    Object idAttributeValue = this.entityInformation.getCompositeIdAttributeValue(id, idAttributeName);
                    boolean complexIdParameterValueDiscovered = idAttributeValue != null && !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());
                    if (complexIdParameterValueDiscovered) {
                        return this.findById(id).isPresent();
                    }

                    query.setParameter(idAttributeName, idAttributeValue);
                }

                return (Long)query.getSingleResult() == 1L;
            }
        }
    }

    public List<T> findAll() {
        return this.getQuery((Specification)null, (Sort)Sort.unsorted()).getResultList();
    }

    public List<T> findAllById(Iterable<ID> ids) {
        Assert.notNull(ids, "Ids must not be null!");
        if (!ids.iterator().hasNext()) {
            return Collections.emptyList();
        } else if (!this.entityInformation.hasCompositeId()) {
            Collection<ID> idCollection = Streamable.of(ids).toList();
            ByIdsSpecification<T> specification = new ByIdsSpecification(this.entityInformation);
            TypedQuery<T> query = this.getQuery(specification, (Sort)Sort.unsorted());
            return query.setParameter(specification.parameter, idCollection).getResultList();
        } else {
            List<T> results = new ArrayList();
            Iterator var3 = ids.iterator();

            while(var3.hasNext()) {
                ID id = var3.next();
                this.findById(id).ifPresent(results::add);
            }

            return results;
        }
    }

    public List<T> findAll(Sort sort) {
        return this.getQuery((Specification)null, (Sort)sort).getResultList();
    }

    public Page<T> findAll(Pageable pageable) {
        return (Page)(isUnpaged(pageable) ? new PageImpl(this.findAll()) : this.findAll((Specification)null, pageable));
    }

    public Optional<T> findOne(@Nullable Specification<T> spec) {
        try {
            return Optional.of(this.getQuery(spec, Sort.unsorted()).getSingleResult());
        } catch (NoResultException var3) {
            return Optional.empty();
        }
    }

    public List<T> findAll(@Nullable Specification<T> spec) {
        return this.getQuery(spec, Sort.unsorted()).getResultList();
    }

    public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
        TypedQuery<T> query = this.getQuery(spec, pageable);
        return (Page)(isUnpaged(pageable) ? new PageImpl(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec));
    }

    public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
        return this.getQuery(spec, sort).getResultList();
    }

    public <S extends T> Optional<S> findOne(Example<S> example) {
        try {
            return Optional.of(this.getQuery(new ExampleSpecification(example, this.escapeCharacter), example.getProbeType(), (Sort)Sort.unsorted()).getSingleResult());
        } catch (NoResultException var3) {
            return Optional.empty();
        }
    }

    public <S extends T> long count(Example<S> example) {
        return executeCountQuery(this.getCountQuery(new ExampleSpecification(example, this.escapeCharacter), example.getProbeType()));
    }

    public <S extends T> boolean exists(Example<S> example) {
        Specification<S> spec = new ExampleSpecification(example, this.escapeCharacter);
        CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
        cq.select(this.em.getCriteriaBuilder().literal(1));
        this.applySpecificationToCriteria(spec, example.getProbeType(), cq);
        TypedQuery<Integer> query = this.applyRepositoryMethodMetadata(this.em.createQuery(cq));
        return query.setMaxResults(1).getResultList().size() == 1;
    }

    public boolean exists(Specification<T> spec) {
        CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
        cq.select(this.em.getCriteriaBuilder().literal(1));
        this.applySpecificationToCriteria(spec, this.getDomainClass(), cq);
        TypedQuery<Integer> query = this.applyRepositoryMethodMetadata(this.em.createQuery(cq));
        return query.setMaxResults(1).getResultList().size() == 1;
    }

    public <S extends T> List<S> findAll(Example<S> example) {
        return this.getQuery(new ExampleSpecification(example, this.escapeCharacter), example.getProbeType(), (Sort)Sort.unsorted()).getResultList();
    }

    public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
        return this.getQuery(new ExampleSpecification(example, this.escapeCharacter), example.getProbeType(), (Sort)sort).getResultList();
    }

    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
        ExampleSpecification<S> spec = new ExampleSpecification(example, this.escapeCharacter);
        Class<S> probeType = example.getProbeType();
        TypedQuery<S> query = this.getQuery(new ExampleSpecification(example, this.escapeCharacter), probeType, (Pageable)pageable);
        return (Page)(isUnpaged(pageable) ? new PageImpl(query.getResultList()) : this.readPage(query, probeType, pageable, spec));
    }

    public <S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
        Assert.notNull(example, "Sample must not be null!");
        Assert.notNull(queryFunction, "Query function must not be null!");
        Function<Sort, TypedQuery<S>> finder = (sort) -> {
            ExampleSpecification<S> spec = new ExampleSpecification(example, this.escapeCharacter);
            Class<S> probeType = example.getProbeType();
            return this.getQuery(spec, probeType, (Sort)sort);
        };
        FluentQuery.FetchableFluentQuery<S> fluentQuery = new FetchableFluentQueryByExample(example, finder, this::count, this::exists, this.em, this.escapeCharacter);
        return queryFunction.apply(fluentQuery);
    }

    public long count() {
        return (Long)this.em.createQuery(this.getCountQueryString(), Long.class).getSingleResult();
    }

    public long count(@Nullable Specification<T> spec) {
        return executeCountQuery(this.getCountQuery(spec, this.getDomainClass()));
    }

    @Transactional
    public <S extends T> S save(S entity) {
        Assert.notNull(entity, "Entity must not be null.");
        if (this.entityInformation.isNew(entity)) {
            this.em.persist(entity);
            return entity;
        } else {
            return this.em.merge(entity);
        }
    }

    @Transactional
    public <S extends T> S saveAndFlush(S entity) {
        S result = this.save(entity);
        this.flush();
        return result;
    }

    @Transactional
    public <S extends T> List<S> saveAll(Iterable<S> entities) {
        Assert.notNull(entities, "Entities must not be null!");
        List<S> result = new ArrayList();
        Iterator var3 = entities.iterator();

        while(var3.hasNext()) {
            S entity = var3.next();
            result.add(this.save(entity));
        }

        return result;
    }

    @Transactional
    public <S extends T> List<S> saveAllAndFlush(Iterable<S> entities) {
        List<S> result = this.saveAll(entities);
        this.flush();
        return result;
    }

    @Transactional
    public void flush() {
        this.em.flush();
    }

    /** @deprecated */
    @Deprecated
    protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Specification<T> spec) {
        return this.readPage(query, this.getDomainClass(), pageable, spec);
    }

    protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable, @Nullable Specification<S> spec) {
        if (pageable.isPaged()) {
            query.setFirstResult((int)pageable.getOffset());
            query.setMaxResults(pageable.getPageSize());
        }

        return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> {
            return executeCountQuery(this.getCountQuery(spec, domainClass));
        });
    }

    protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
        Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
        return this.getQuery(spec, this.getDomainClass(), sort);
    }

    protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Pageable pageable) {
        Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
        return this.getQuery(spec, domainClass, sort);
    }

    protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
        return this.getQuery(spec, this.getDomainClass(), sort);
    }

    protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<S> query = builder.createQuery(domainClass);
        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
        query.select(root);
        if (sort.isSorted()) {
            query.orderBy(QueryUtils.toOrders(sort, root, builder));
        }

        return this.applyRepositoryMethodMetadata(this.em.createQuery(query));
    }

    /** @deprecated */
    @Deprecated
    protected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {
        return this.getCountQuery(spec, this.getDomainClass());
    }

    protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<Long> query = builder.createQuery(Long.class);
        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
        if (query.isDistinct()) {
            query.select(builder.countDistinct(root));
        } else {
            query.select(builder.count(root));
        }

        query.orderBy(Collections.emptyList());
        return this.em.createQuery(query);
    }

    private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass, CriteriaQuery<S> query) {
        Assert.notNull(domainClass, "Domain class must not be null!");
        Assert.notNull(query, "CriteriaQuery must not be null!");
        Root<U> root = query.from(domainClass);
        if (spec == null) {
            return root;
        } else {
            CriteriaBuilder builder = this.em.getCriteriaBuilder();
            Predicate predicate = spec.toPredicate(root, query, builder);
            if (predicate != null) {
                query.where(predicate);
            }

            return root;
        }
    }

    private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {
        if (this.metadata == null) {
            return query;
        } else {
            LockModeType type = this.metadata.getLockModeType();
            TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);
            this.applyQueryHints(toReturn);
            return toReturn;
        }
    }

    private void applyQueryHints(Query query) {
        this.getQueryHints().withFetchGraphs(this.em).forEach(query::setHint);
    }

    private static long executeCountQuery(TypedQuery<Long> query) {
        Assert.notNull(query, "TypedQuery must not be null!");
        List<Long> totals = query.getResultList();
        long total = 0L;

        Long element;
        for(Iterator var4 = totals.iterator(); var4.hasNext(); total += element == null ? 0L : element) {
            element = (Long)var4.next();
        }

        return total;
    }

    private static boolean isUnpaged(Pageable pageable) {
        return pageable.isUnpaged();
    }

    private static class ExampleSpecification<T> implements Specification<T> {
        private static final long serialVersionUID = 1L;
        private final Example<T> example;
        private final EscapeCharacter escapeCharacter;

        ExampleSpecification(Example<T> example, EscapeCharacter escapeCharacter) {
            Assert.notNull(example, "Example must not be null!");
            Assert.notNull(escapeCharacter, "EscapeCharacter must not be null!");
            this.example = example;
            this.escapeCharacter = escapeCharacter;
        }

        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            return QueryByExamplePredicateBuilder.getPredicate(root, cb, this.example, this.escapeCharacter);
        }
    }

    private static final class ByIdsSpecification<T> implements Specification<T> {
        private static final long serialVersionUID = 1L;
        private final JpaEntityInformation<T, ?> entityInformation;
        @Nullable
        ParameterExpression<Collection<?>> parameter;

        ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {
            this.entityInformation = entityInformation;
        }

        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            Path<?> path = root.get(this.entityInformation.getIdAttribute());
            this.parameter = cb.parameter(Collection.class);
            return path.in(this.parameter);
        }
    }
}

 
hibernate에서 사용하는 라이브러리이다.

 
 
가장 중요한게 EntitiManger를 먼저 보자.

 private final EntityManager em;

 
코드에

hibernate에서 사용하는걸 코드에서 볼수 있습니다.
그렇다면 

 
Session 클래스를 보자.
보면 EntityMager를 상속받는 Hiberante 라이브러리에 있는 클래스이다.

 
그렇다면 다음 구조를 확인해보자.
SessionImpl 클래스이다.

 
즉 이런식의 구조로 되어있네요. 
 
그렇다면 간단하게 jpa Repostory의 findAll을 보자 
prodocts->finaAll();
 
SimpleJpaReopository .findAll()

 public List<T> findAll() {
        return this.getQuery((Specification)null, (Sort)Sort.unsorted()).getResultList();
    }

finAll()->GetQuery(spec,sort)

protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
        return this.getQuery(spec, this.getDomainClass(), sort);
    }

finAll()-> GetQuery( spec,sort )->getQuery( spec,domainClass,sort );

protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<S> query = builder.createQuery(domainClass);
        Root<S> root = this.applySpecificationToCriteria(spec, domainClass, query);
        query.select(root);
        if (sort.isSorted()) {
            query.orderBy(QueryUtils.toOrders(sort, root, builder));
        }

        return this.applyRepositoryMethodMetadata(this.em.createQuery(query));
    }

 
보시면 EntityManger가 가지고 있는 Criteria api 를 이용해서 쿼리문을 작성해서 

query.select(root);
        if (sort.isSorted()) {
            query.orderBy(QueryUtils.toOrders(sort, root, builder));
        }

데이터를 불러옵니다. 
 
applySpecificationToCriteria // check 용
applyRepositoryMethodMetadata // check 용
 
이런식으로 대략적으로 흘러갑니다.
 
다음에는 데이터를 조회할때나 저장할때 어떻게 흘러가는지 디버깅 모드로 한번 확인해보겠습니다.
 
 

'프로그래밍언어 > JAVA' 카테고리의 다른 글

Virtual Thread(가상 스레드)  (0) 2024.09.01
hashcode와 equals  (0) 2024.08.05
순수 JAVA JPA  (0) 2024.03.17
getDeclaredConstructor().newInstance()?  (0) 2024.03.16
Reflection API란?  (0) 2024.03.16

+ Recent posts