💻
Albert's Til
GitHub
  • 매일매일 조금씩 성장하기
    • README
    • CS
      • Network
      • HTTP
        • NO-CACHE
      • 오류 코드
      • ORM 도구
      • Design Pattern
        • CQRS Pattern
          • Event Sourcing and CQRS pattern
        • Builder Pattern
    • DB
      • MySQL
        • Timeline
        • Pagination
        • Index
        • Database Performance Optimization Strategies
        • B+ tree
        • MySQL Connectors VS MySQL Shell(Scripting) VS MySQL Workbench
        • MySQL Storage Engine Architecture
      • Normalization & Denormalization
      • JPA
        • @Transactional
        • Why JPA?
        • About JPA
        • N+1 Issue
        • Index
        • ElementCollection&CollectionTable
        • orphanRemoval
        • CascadeType
        • Use Subselect
        • Dynamic Instance Creation
        • Paging
        • Order
        • Spefication
        • mappedBy
      • MongoDB
        • ObjectId
      • Why MySQL?
      • ACID properties of transactions
      • Between JPA and JDBC
      • Identifiers in Hibernate/JPA
    • Java
      • Jackson de/serialize
      • Collections.singletonList() vs List.of()
      • Manage dependencies in Gradle
      • Logging Level
      • Bean Validation
      • JVM Internals
        • Threads
          • Frame
        • Shared Between Threads
          • Classloader
            • Class Loader Hierarchy
            • Loading Linking Initialization
      • Java Collection Framework
      • Annotation
      • Generic
      • 디미터 법칙
    • Spring
      • Caching
      • Spring Integration Overview
        • ThreadPollTaskExecutor
        • Messaging Bridge
        • Channel Adapter
        • Poller
        • Configuration and @EnableIntegration
        • Message Endpoints
        • Message Channels
      • HATEOAS
      • @Autowired vs Constructor Dependency Injection
      • Spring Security
        • JWT 토큰 사용한 인가
        • OAuth 2 Login
        • OAuth 2 인증
        • 인가
        • 인증
        • PasswordEncoder
      • IoC Container
      • Filter,Interceptor,AOP,Argument Resolver
      • Spring Annotation
      • About Spring
    • Kafka
      • Error Channel
    • Infra
      • Scale Up || Scale Out
      • Docker
        • Dockerfile
        • Docker Hub Deploy
        • Command
      • Cloud 유형
        • Infrastructure as a Service
        • Platform as a Service
        • Software as a Service
      • 무중단 배포
        • 엔진엑스(Nginx)
      • 코드 자동 배포
        • Technical
      • AWS EC2
        • PEM(Privacy Enhanced Mail) 키
      • AWS RDS
      • AWS S3
    • CodeSquad
      • Spring Boot Project 1주차 회고
      • Spring Boot Project 2주차 회고
      • Spirng Boot Project 3주차 회고
      • Spring Boot Project 4주차 회고
    • Foody Moody 프로젝트
      • Query Performance Comparison
      • HeartCount Asynchronous Issue
      • DeferredResult
      • ResponseBodyEmitter
      • SseEmitter (Spring)
      • Server-Sent Events (SSE)
      • 기술 스택 적용 이유
      • NO-CACHE(HTTP)
      • Transactional
    • DDD
      • AggregateId
    • Test
      • RestAssured
    • Coding and Algorithmic Problems
      • 819. Most Common Word
      • 344. Reverse String
      • 125. Valid Palindrome
      • 937. Reorder Data in Log Files
    • Node
      • Async... Await...
      • Custom Transactional Decorator Challenger
    • Python
      • Python Basic Grammar
        • Comments and Input/Output
        • Variable
        • Data type
        • Operations and syntax
        • List,Tuple,Dictionary,Set
        • Function
        • Conditional statement
        • Loop
    • HTML
      • HTML Basic
      • HTML Basic Tags
      • HTML Form Tags
      • HTML Table Tags
    • CSS
      • CSS Basic
      • CSS Practice
Powered by GitBook
On this page
  • 1. CQRS pattern
  • 2.Test에서 @Transactional의 롤백
  • 3.Test에서의 하드코딩 개선
  • 4.Logging Level 에 대한 재고민
  • 5.initBeanPropertyAccess() 와 initDirectFieldAccess()
  • 6.@Valid와 @Validated의 차이
  • 7. jasypt를 통한 암호화
  • 사용전
  • 사용후
  • 사용방법
  • 8. 쿼리에서 *를 사용하는 것은 지양한다
  • 9.jdbcTemplate와 namedparameter
  • 10.exists 쿼리 성능 개선
  • 11.DB에 식별자(테이블 이름, 열 이름 등)로 사용할 수 없는 키워드 목록이 있습니다.
  • 12.SQLErrorCodeSQLExceptionTranslator

Was this helpful?

  1. 매일매일 조금씩 성장하기
  2. CodeSquad

Spring Boot Project 2주차 회고

Last updated 1 year ago

Was this helpful?

1.

  • 아직 깊게 이해는 못했지만 개념을 찾아서 한번 알아봤습니다.

2.Test에서 @Transactional의 롤백

  • Aoto Increment Column은 Roll Back 하지 않는다.

  • auto increment 자동 증가 값을 생성하는 데 사용되는 잠금 모드와 관련이 있습니다.

3.Test에서의 하드코딩 개선

존재 하지 않은 UserId에 대한 접근의 Test에서

mockMvc.perform(put("/users/20/update")

20은 아직 존재하지 않는 UserId를 의미합니다. 개

개선후

private static final int NON_EXISTING_USER_ID = 20;
mockMvc.perform(put("/users/"+NON_EXISTING_USER_ID+"/update")

가독성 향상

4.Logging Level 에 대한 재고민

  • 아직 코드가 간단해서 다양한 레벨의 필요성을 느끼지 못하고 있다. 이해를 더 깊게 하려면 조금 더 복잡한 구조의 프로젝트로 만들고 이해를 하여야 할 것 같습니다.

5.initBeanPropertyAccess() 와 initDirectFieldAccess()

  • DataBinder 의 기본 설정은 initBeanPropertyAccess() 입니다. JavaBean property access로 객체를 초기화한다. 즉 setter 사용하여 초기화 한다.

// Some code
  • initDriectFiedlAccess()로 설정하면 직접 필드를 access하여 초기화 한다. 즉 setter를 사용하지 않고 초기화 한다.

  • 장점:

    1. 노출하고 싶은 부분만 외부에 노출

    2. 상태는 잘 캡슐화되어 있습니다.

  • 단점:

    • 컨테이너는 값 주입을 위해 게터와 세터를 사용하지 않습니다. injection-process는 direct field injection으로 디버깅할 수 없습니다.

  • Spring에서 설정방법(예시)

@ControllerAdvice
public class WebControllerAdvice {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.initDirectFieldAccess();
    }
}

6.@Valid와 @Validated의 차이

  • Spring에서는 JSR-303's @Valid annotation을 메서드 level 유효송 검사에 사용합니다. 또한 유효성 검사를 위해 member attribute를 표시하는데 사용합니다. 그러난 이 @Valid는 group 유효성 검사를 지원하지 않습니다.

  • 그룹 level의 경우 JSR-303의 @Valid의 변형인 Spring의 @Validated를 사용해야 합니다.

7. jasypt를 통한 암호화

사용전

spring.datasource.url=jdbc:h2:~/test
spring.datasource.username=testname
spring.datasource.password=testpassword

사용후

spring.datasource.url=ENC(+WCZeeCfIhwJETdywT8GZvPJIVNnVqqoeKf3NComOUSEc4YqJz3PpdaEAYnWDzF3ij73yn3GnjU=)
spring.datasource.username=ENC(flrTBReqIDeRl1zFOAKafA==)
spring.datasource.password=ENC(7pUsCOYOlr1Z8xSrPu6Ci2zufHayPbHW)

사용방법

Spring-boot 를 지원

  • dependencies 추가

implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'
  • application.properties 설정 추가

//이 IvGenerator 구현은 항상 길이가 0인 초기화 벡터(IV)를 반환합니다.
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator 
//암호화 알고리즘
jasypt.encryptor.algorithm=PBEWithMD5AndTripleDES 
//임의의 암호화 password(업로드 시 삭제,
//--jasypt.encryptor.password=dip3tH7IJrL 추가하여 Java 실행) 
jasypt.encryptor.password=dip3tH7IJrL
  • 테스트에서 암호화 할 내용을 출력

	@Autowired
	StringEncryptor stringEncryptor;

	@Test
	void contextLoads() {
		String encrypt = stringEncryptor.encrypt("jdbc:h2:~/test");
		System.out.println("encrypt = " + encrypt);
	}
  • 출력한 암호를 복사

  • properties에서 ENC추가하여 암호화 완성

spring.datasource.url=ENC(w8FSUhvvlH5YMHPkm6SI3O3fbE0Efb0+)
  • application.properties 설정에서 jasypt.encryptor.password 삭제하고 --jasypt.encryptor.password=dip3tH7IJrL 추가하여 Java 실행하면 끝

Spring Boot 내에서 사용

  • StringEncryptor를 @Autowired하여 사용하면 됩니다.

public class AppStartupRunner implements CommandLineRunner {

    @Autowired
    UserRepository userRepository;
    @Autowired
    StringEncryptor encryptor;


    @Override
    public void run(String... args) {
        User build = new User.Builder()
                .password(encryptor.decrypt("W5p8Dbc3f7sOjqaRc7WVp8inlukLB3LJ"))
                .email(encryptor.decrypt("R9gvxFpZK6xYikAdPrdy1mDtd3O+ag2L"))
                .nickname("admin")
                .role(Role.MANAGER).build();
        userRepository.save(build);
    }
}

8. 쿼리에서 *를 사용하는 것은 지양한다

  • 불필요한 IO

    • SELECT *를 사용하면 무시해야할 불필요한 데이터를 반환할 수 있습니다. 그러나 해당 데이터를 가져오는 데 비용이 발생한다. 이로 인해 페이지에서 해당 데이터를 모두 읽을 것이기 때문에 DB 측에서 일부 낭비적인 IO 주기가 발생합니다.

  • 네트워크 트래픽 증가

    • SELECT *는 클라이언트에 필요한 것보다 더 많은 데이터를 반환하므로 클라이언트는 더 많은 네트워크 대역폭을 사용합니다. 이러한 네트워크 대역폭의 증가는 또한 데이터가 클라이언트 애플리케이션(SSMS 또는 Java 애플리케이션 서버일 수 있음)에 도달하는 데 더 오랜 시간이 걸린다는 것을 의미합니다.

  • 더 많은 애플리케이션 메모리

    • 이러한 데이터 증가로 인해 응용 프로그램은 사용되지 않지만 Microsoft SQL 서버 또는 연결 중인 다른 데이터베이스에서 오는 불필요한 데이터를 보관하기 위해 더 많은 메모리가 필요할 수 있습니다.

  • ResultSet의 열 순서에 대한 의존성

    • 응용 프로그램에서 SELECT *쿼리를 사용하고 열 순서에 의존성이 있는 경우(그러면 안 됨) 새 열을 추가하거나 열 순서를 변경하면 결과 집합의 순서가 변경됩니다.

  • 테이블에 새 열을 추가하는 동안 보기 중단

    • 뷰에서 SELECT *를 사용할 때 새 열이 추가되고 이전 열이 테이블에서 제거되면 미묘한 버그가 생성됩니다. 왜? 보기가 중단되지 않고 잘못된 결과를 반환하기 시작하기 때문입니다.

    • 이를 방지하려면 뷰와 함께 항상 WITHSCHEMABINDING it을 사용해야 합니다. 이렇게 하면 뷰에서 SELECT *를 사용할 수도 없게 됩니다.

  • JOIN 쿼리 충돌

    • JOIN 쿼리에서 SELECT *를 사용하면 여러 테이블에 동일한 이름(예: 상태, 활성, 이름 등)의 열이 있을 때 복잡해질 수 있습니다

  • 한 테이블에서 다른 테이블로 데이터 복사

    • 한 테이블에서 다른 테이블로 데이터를 복사하는 일반적인 방법인 INSERT .. SELECT 문에 SELECT *를 사용할 때 두 테이블 간에 열 순서가 동일하지 않으면 잘못된 데이터를 잘못된 열에 복사할 가능성이 있습니다.

    • 일부 프로그래머는 쿼리 파서가 정적 값의 유효성을 검사하기 위해 추가 작업을 수행해야 하기 때문에 EXISTS 코드에서 SELECT * 대신 SELECT 1을 사용하는 것이 더 빠르다고 생각합니다.

    • 오래 전에는 사실이었을지 모르지만 요즘 파서는 SELECT 목록이 EXISTS 절 내에서 완전히 관련이 없다는 것을 알 만큼 똑똑해졌습니다.

9.jdbcTemplate와 namedparameter

  • Spring Boot JDBC에서 DataSource, JdbcTemplate 및 NamedParameterJdbcTemplate과 같은 데이터베이스 관련 bean은 시작 중에 구성되고 생성되어 이를 사용합니다. 예를 들어 원하는 bean을 @Autowired하면 됩니다.

10.exists 쿼리 성능 개선

  • select exists를 limit 1 로 대체해서 사용한다.

  • 단, JpaRepository의 메소드 쿼리에선 내부적으로 limit 1를 사용하고 있어서 성능상 이슈가 없다.

//지양
SELECT count(*) FROM users where id = :id
//추천
SELECT userName,.... FROM users where id = :id limit 1

11.DB에 식별자(테이블 이름, 열 이름 등)로 사용할 수 없는 키워드 목록이 있습니다.

  • 따옴표로 묶으면 사용가능하고 대소문자 구별합니다. 하지만 개인적으로 선호하지 않습니다. 회피는 결국 에러를 발생할 수 있다고 판단합니다.

12.SQLErrorCodeSQLExceptionTranslator

SQLExceptionTranslator 는 SQLExceptions와 Spring의 자체 org.springframework.dao.DataAccessException 사이에서 변환할 수 있는 클래스에 의해 구현되는 인터페이스입니다. 이는 인식불가능한 data access와 관련되여 있다. 구현은 일반(예: JDBC용 SQLState 코드 사용) 또는 특정상황(예: Oracle 오류 코드 사용)에 정밀도를 높일 수 있습니다.

  • SQLErrorCodeSQLExceptionTranslator는 다음 순서로 일치 규칙을 적용합니다.

    • 하위 클래스에 의해 구현된 모든 custom translation. 일반적으로 제공된 구체적인 SQLErrorCodeSQLExceptionTranslator가 사용되므로 이 규칙이 적용되지 않습니다. 실제로 하위 클래스 구현을 제공한 경우에만 적용됩니다.

    • SQLErrorCodes 클래스의 customSqlExceptionTranslatorproperty으로 제공되는 SQLExceptionTranslator 인터페이스의 custom 구현.

    • SQLErrorCodes 클래스의 customTranslations 속성에 대해 제공된 CustomSQLErrorCodesTranslation 클래스의 인스턴스 목록에서 일치 항목을 검색합니다.

    • 오류 코드 일치가 적용됩니다

    • fallback translator를 사용한다. SQLExceptionSubclassTranslator는 default fallback translator입니다. 이 변환을 사용할 수 없는 경우 다음 fallback translator는 SQLStateSQLExceptionTranslator입니다.

CQRS pattern
https://stackoverflow.com/questions/449346/mysql-auto-increment-does-not-rollback
https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
https://www.logicbig.com/tutorials/spring-framework/spring-core/direct-field-access.html
https://www.baeldung.com/spring-valid-vs-validated
https://www.baeldung.com/javax-validation-groups
https://mkyong.com/spring-boot/spring-boot-jdbc-examples/
https://jojoldu.tistory.com/516
http://www.h2database.com/html/advanced.html
https://docs.spring.io/spring-framework/docs/3.0.x/spring-framework-reference/html/jdbc.html#jdbc-SQLExceptionTranslator