오류 해결
- 오류: 페이징 오류
- 원인: 메서드 실행 순서 오류
- 해결 방법: 실행 순서를 변경합니다.
참조) BeanUtils.복사 속성(A, B): 동일한 값을 가진 필드에 대해서만 A를 B로 복사
- 문제 코드
- 페이징 인스턴스를 만들고 조건과 일치하는 데이터 수를 계산합니다.
- 페이지에서 결과 값을 설정한 후 모델 정보를 페이징 인스턴스에 복사합니다.
- 그런데 이렇게 하고 나서 검색을 하면 페이지 수가 totalPages 수로 설정되기 때문에 찾고자 하는 데이터를 보여주는 페이지가 2개라도 최대 4개의 페이지( 전체 목록)이 검색됩니다. (3,4를 누르시면 데이터가 없다고 나올수도 있습니다.)
- 문제: 페이징 인스턴스와 모델 인스턴스 사이. searchedModelCount 변수가 다른 값을 갖는 것은 정상입니다.다만, 동일하므로 전체 리스트의 개수가 포함되어 있어 문제가 된다.
- 그럼에도 불구하고 모델과 페이징에 대해 검색 결과 수가 똑같이 작은 것이 정상이 아닙니까?
<hide/>
// Model 목록 조회 (전체 조회, 검색 조회)
public Object getModelList(Model model, HttpServletRequest request) {
PagingVO page = new PagingVO();
long totalCount = query.getSearchedModelCount(model);
page.setTotalListSize(totalCount);
BeanUtils.copyProperties(model, page);
...
Map<String, Object> resultMap = new HashMap<>();
...
return resultMap;
}
- 일반 코드
- 먼저 계산하십시오.
- 그런 다음 페이징 인스턴스를 만듭니다. 새로운 페이징 사례모델의 동일한 속성에 대한 정보를 에 복사합니다.
- 그럼 드디어 페이징 인스턴스에 매개변수로 전달됨 모델에 대한 페이징 정보들어간다
- 따라서 페이지 인스턴스와 모델 인스턴스는 searchedModelCount에 대해 서로 다른 값을 가져야 합니다.
<hide/>
// Model 목록 조회 (전체 조회, 검색 조회)
public Object getModelList(Model model, HttpServletRequest request) {
long totalCount = query.getSearchedModelCount(model);
PagingVO page = new PagingVO();
BeanUtils.copyProperties(model, page);
page.setTotalListSize(totalCount);
...
Map<String, Object> resultMap = new HashMap<>();
...
return resultMap;
}
스프링 데이터 JPA 메소드
- 특정 조건을 충족하는 저장소의 모든 항목을 삭제할 수 있는 방법이 있습니까?
예) 동일한 ModelId를 가진 모든 Params를 삭제합니다.
1) @Query 추가 IN 절사용하는 방법
- 많은 양의 데이터를 조회할 때 IN 절을 사용하는 것이 OR을 연속적으로 사용하는 것보다 훨씬 빠릅니다.
- cf) 질의 실행계획을 보면 OR절과 IN절의 사용 쿼리 실행 계획차이가 있습니다
- 오르절 유형 = ALL, IN 절 유형 = 범위
- type = ALL: 인덱스 없이 처음부터 끝까지 테이블 읽기 전체 테이블 스캔사용
- 유형 = 범위: 인덱스 범위 스캔 방식사용하는 접근법
<hide/>
@Modifying
@Query(nativeQuery = true, value = "DELETE FROM MemberParam m WHERE m.member_Id=:memberId")
void deleteAllParamByMemberId(@Param("memberId") String memberId);
메모)
- 이 메소드는 member_param(created entity) 테이블에서 메소드에 매개변수로 입력된 “memberId”에 해당하는 모든 매개변수를 찾아 삭제합니다.
- 관련 주석
- @Query를 사용하면 내부에 쿼리를 직접 작성할 수 있어 편리합니다.
- 매개변수로 입력할 문자열 앞에 @Param을 입력합니다.
- param이 첨부된 memberId는 쿼리문에 사용된 변수 이름과 일치해야 합니다.
- nativeQuery = true: JPQL 및 SQL 구문의 차이로 인해 필요합니다. 복잡한 쿼리를 JPQL만으로 작성할 수 없는 경우 네이티브 SQL을 사용하여 DB로 데이터를 보낼 수 있습니다.
- @Modifying: 데이터베이스를 수정할 때 사용합니다. 수정, 삭제, 등록때 사용
- @Query를 사용하면 내부에 쿼리를 직접 작성할 수 있어 편리합니다.
참조
인덱스 범위 스캔: https://oranthy.443
2) OR 장사용 방법: deleteAllInBatch()
- deleteAllInBatch()를 구현하는 메서드 내부에 탑승하면 다음을 볼 수 있습니다. 어디 “절의 조건또는“와 같이 연결되어 있는 것을 확인할 수 있습니다.
<hide/>
public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
...
String alias = detectAlias(queryString);
StringBuilder builder = new StringBuilder(queryString);
builder.append(" where");
int i = 0;
while(iterator.hasNext()) {
iterator.next();
Object() var10002 = new Object(){alias, null};
++i;
var10002(1) = i;
builder.append(String.format(" %s = ?%d", var10002));
if (iterator.hasNext()) {
builder.append(" or");
}
}
...
return query;
}
주) 일괄처리는 JPA 방식
- deleteAll() deleteAllInBatch() 차이
- deleteAll(entities) : DELETE 쿼리가 하나씩 날아갑니다. 따라서 1000개의 경우를 삭제할 때 1000개의 DELETE 문이 실행됩니다. 일괄 삭제 시 성능이 저하됩니다.
- deleteAllInBatch(엔티티): 여러 엔터티를 한 번에 삭제합니다. 이는 DELETE 문이 한 번만 실행되기 때문에 효율적입니다. 엔터티 수가 많은 경우 deleteAll()보다 성능이 훨씬 좋습니다. 내부에 구현된 로직을 보면 어디 “절의 조건또는“와 연결된다.
- 엔터티의 전체 세트대상을 삭제합니다.
- 모든 엔터티를 삭제한 다음 지속성 컨텍스트 지우기. (즉, DB와 내용을 일치시키는 작업을 합니다.)
- deleteInBatch(엔티티)
- 매개변수로 전달 수집 또는 반복 가능에 포함된 항목만 삭제됩니다.
- 지속성 컨텍스트깁스 비우지 마십시오 그러므로 반드시 거래사용하여 엔티티 정보 업데이트해야한다.
참조) https://velog.io/@hssarah/JPA-deleteAll-vs-deleteAllInBatch-vs-Query-%EC%82%AC%EC%9A%A9
메모
부울 빌더, BooleanExpression 리팩토링
- 이전에 회사에서 만든 코드는 BooleanBuilder를 사용했습니다.
- 과거에 Builder를 사용한 코드
- 매개변수로 중요한 값(null 또는 “” 이외)이 있는 경우에만 if() 문으로 들어가서 WHERE 절에 AND 조건을 추가합니다.
- 그러나 특정 값이 필요하지 않은 경우에는 search.and() 문을 추가할 필요가 없습니다.
<hide/>
if (StringUtil.isNotEmpty(modelVo.getUseYn())) {
search.and(model.useYn.equalsIgnoreCase(modelVo.getUseYn()));
}
- 리팩토링 시도
- 3번째 줄에 return null을 넣어야 search.and(null)이 들어가고 where절은 형식적이지만 실제로는 어떤 조건도 들어가지 않는다.
<hide/>
private BooleanExpression eqUseYn(String useYn){
if(StringUtil.isEmpty(useYn)){
return null;
}
return model.useYn.eq(useYn);
}
...
public BooleanBuilder predicate(Model modelVo) {
BooleanBuilder search = new BooleanBuilder();
...
return search.and(eqUseYn(modelVo.getUseYn()));
...
}
}
프런트 엔드 전체 구조
- index.js
- Spring의 경우 여러 컨트롤러 클래스가 모여있는 통합 컨트롤러 클래스처럼 느껴졌습니다.
- vue 파일: 페이지별로 각 기능에 대한 vue 파일을 만들 수 있습니다.
- 각 vue 파일은 구성 요소입니다.
- 예를 들어, 상세 조회, 목록 조회, 등록, 편집 기능을 위한 기능 단위 컴포넌트를 생성하고 뷰 파일로 정의합니다.
- Vue 파일은 기능 단위로 생성되거나 vue는 화면 단위로 생성됩니다.
- 라우터
- 각 라우터의 경로, 이름, 자식 설정 어린이들 여러 내부 어린이들이것은 겹칠 수 있습니다.
- 봄의 컨트롤러에서 컨트롤러 내부의 메소드로 라우터를 생각했습니다.
- 경로에 URL을 지정하면 해당 주소에 대해 구성 요소 페이지가 하나씩 매핑됩니다.
- 경로: 현재 라우터의 경로
- 이름: 현재 라우터의 이름을 정의합니다. 중복 불가
- children: 현재 라우터의 자식 라우터를 정의하는 영역
- CommonLayout.vue 파일
- 전체 레이아웃을 지정합니다.
- 이미 생성된 CommonLayoutFooter 및 CommonLayoutHeader를 가져와서 전체 레이아웃을 지정할 수 있습니다. 홈페이지의 메뉴 목록 등의 내용이 정의되어 있습니다.
Vue의 수명 주기 후크
- Vue 객체는 여러 단계를 거쳐 사용되며, 각 단계에서 hook을 사용하여 추가 처리를 생성할 수 있습니다.
- 라이프 사이클Vue.js 구성 요소의 생성 및 소멸에서 단계말한다
- 각 단계의 특정 지점에서 실행됩니다. 기능두번째 수명 주기 후크그것은 말한다.
- 라이프사이클: 생성 => 마운트 => 업데이트 => 마운트 해제
- 생성: 구성 요소 UI 렌더링 전에 데이터를 구성하는 단계
- 마운트: UI 렌더링 단계
- 업데이트: Vue의 상태(Data())가 변경될 때
- 마운트 해제: 구성 요소 종료 단계
- Vue 인스턴스는 beforeCreated()에서 unmounted()에 이르기까지 여러 단계를 통해 사용됩니다.
- 응용 프로그램의 시점코드를 실행할 수 있는 기능을 제공합니다.
- Vue의 수명 주기 후크는 구성 요소 또는 내부 구성 요소에서 직접 정의됩니다.
- Spring의 @EventListener 어노테이션도 애플리케이션이 시작될 때마다 실행될 특정 메서드를 정의할 수 있는데, 나는 이와 비슷한 느낌을 받는다.
- 생성: beforeCreated(), created(), beforeMount(), mounted()
- beforeCreated(): 이 후크가 먼저 실행됩니다. 데이터와 이벤트가 아직 설정되지 않은 단계입니다. 생성 단계 직전에 호출됩니다.
- 허락: beforeUpdate(), update(), beforeUnmount(), unmounted()
참조)
https://goodteacher.543
https://velog.io/@yeyo0x0/Vue.js-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81% B4-%ED%9B%85
JavaScript 명령 또는 키워드
- 참조()
- ref() 함수는 Vue.js3에서 사용되는 함수 중 하나입니다.
- ref()를 사용하는 경우 기본값이 있는 변수만들 수 있습니다 ref() 함수를 통해 생성된 변수는 “value”를 통해 접근할 수 있습니다.
- ref() 함수는 기본적으로 값을 감싸는 객체를 생성합니다. 이 객체는 Vue의 반응성 시스템과 함께 사용됩니다.
- 이 변수의 값은 ‘value’ 속성에 저장됩니다.
- ref() 함수로 생성된 변수의 값을 변경하면 Vue.js가 구성 요소의 보기를 자동으로 업데이트합니다.
- DOM 요소에 액세스하는 데 사용됩니다.
- 인스턴스 또는 배열은 ref를 통해 액세스할 수도 있습니다.