veluxer62 / veluxer62.github.io

veluxer's blog
http://veluxer62.github.io
MIT License
1 stars 0 forks source link

7월 개발이슈 #675

Closed veluxer62 closed 10 months ago

veluxer62 commented 1 year ago

Motivation

Suggestion

1

veluxer62 commented 1 year ago

PostgreSQLEnumType 을 Type으로 정의하니 아래와같은 오류가 발생한다.

Caused by: java.lang.NullPointerException: Cannot invoke "org.hibernate.boot.spi.MetadataBuildingContext.getMetadataCollector()" because "this.metadataBuildingContext" is null
    at org.hibernate.type.spi.TypeConfiguration$Scope.getDialect(TypeConfiguration.java:459)
    at org.hibernate.type.EnumType$LocalJdbcTypeIndicators.getDialect(EnumType.java:516)
    at org.hibernate.type.descriptor.jdbc.VarcharJdbcType.shouldUseMaterializedLob(VarcharJdbcType.java:90)
    at org.hibernate.type.descriptor.jdbc.VarcharJdbcType.resolveIndicatedType(VarcharJdbcType.java:79)
    at org.hibernate.type.descriptor.java.BasicJavaType.getRecommendedJdbcType(BasicJavaType.java:33)
    at org.hibernate.type.descriptor.java.StringJavaType.getRecommendedJdbcType(StringJavaType.java:56)
    at org.hibernate.type.EnumType.configureUsingReader(EnumType.java:180)
    at org.hibernate.type.EnumType.setParameterValues(EnumType.java:142)
    at com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType.setParameterValues(PostgreSQLEnumType.java:46)
    at org.hibernate.mapping.MappingHelper.injectParameters(MappingHelper.java:109)
    at org.hibernate.mapping.BasicValue.setExplicitCustomType(BasicValue.java:836)
    at org.hibernate.boot.model.internal.BasicValueBinder.fillSimpleValue(BasicValueBinder.java:1363)
    at org.hibernate.boot.model.internal.SetBasicValueTypeSecondPass.doSecondPass(SetBasicValueTypeSecondPass.java:27)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1857)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1803)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:328)

https://github.com/vladmihalcea/hypersistence-utils/issues/519

com.vladmihalcea:hibernate-types-XXio.hypersistence:hypersistence-utils-hibernate-XX로 바뀌었다.

The project name was changed from Hibernate Types to Hypersistence Utils because the scope of the project is much broader now, offering Spring utilities as well.

https://github.com/vladmihalcea/hypersistence-utils

의존성을 io.hypersistence:hypersistence-utils-hibernate-62로 바꾸니 해결되는듯 했으나 아래와 같이 다른에러 발생

Caused by: org.hibernate.HibernateException: No type mapping for org.hibernate.type.SqlTypes code: 1111 (OTHER)
    at org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry.getTypeName(DdlTypeRegistry.java:205)
    at org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry.getTypeName(DdlTypeRegistry.java:184)
    at org.hibernate.mapping.Column.getSqlTypeName(Column.java:277)

https://github.com/vladmihalcea/hypersistence-utils/issues/625

columnDefinition 선언해주면 해결됨

veluxer62 commented 1 year ago

activemq에서 vm 문자열 파싱 에러가 발생한다. 더이상 인메모리 Queue를 지원하지 않는듯 5.9.0 버전에 다시 나온다는 얘기도 있다.

https://github.com/spring-projects/spring-boot/issues/34011

veluxer62 commented 1 year ago

group이라는 클래스를 쓰면서 querydsl로 pageable sort 매개변수를 넣으면 오류가 발생한다. 예약어때문에 그런듯하다. 클래스명을 바꿔주면 해결된다.

veluxer62 commented 1 year ago

querydsl에서 like를 쓰면 아래와 같이 syntax 에러가 발생한다.

Hibernate: select count(v1_0.id) from vendor v1_0 where v1_0.reg_num like ? escape !
2023-07-03T16:50:52.132+09:00  WARN 32056 --- [pool-1-thread-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 42601
2023-07-03T16:50:52.132+09:00 ERROR 32056 --- [pool-1-thread-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: syntax error at end of input
  Position: 75

JDBC exception executing SQL [select count(v1_0.id) from vendor v1_0 where v1_0.reg_num like ? escape !] [ERROR: syntax error at end of input
org.springframework.dao.InvalidDataAccessResourceUsageException: JDBC exception executing SQL [select count(v1_0.id) from vendor v1_0 where v1_0.reg_num like ? escape !] [ERROR: syntax error at end of input
  Position: 75] [n/a]; SQL [n/a]

다른 방법이 딱히 떠오르진 않아서 아래와 같이 likeIgnoreCase로 바꿔주었다.

// vendor.regNum.like("%$searchWord%")
vendor.regNum.likeIgnoreCase("%$searchWord%")
veluxer62 commented 1 year ago

hibernate 6으로 업그레이드하고 나서 아래 함수들이 안먹힌다.

fun <A, E> ArrayPath<A, E>.contains(element: E): BooleanExpression {
    return Expressions.booleanTemplate(
        "{0} = function('ANY', {1})",
        element,
        this,
    )
}

val <A, E> ArrayPath<A, E>.isEmpty: BooleanExpression
    get() = Expressions.booleanTemplate("{0} = '{}'", this)

그래서 아래와 같이 변경함

fun <A, E> ArrayPath<A, E>.contains(element: E): BooleanExpression {
    return Expressions.booleanTemplate(
        "ARRAY_POSITION({0}, {1}) IS NOT NULL",
        this,
        element,
    )
}

val <A, E> ArrayPath<A, E>.isEmpty: BooleanExpression
    get() = Expressions.booleanTemplate("COALESCE(array_length({0}, 1), 0) = 0", this)
veluxer62 commented 1 year ago

soft delete를 위해 @Where를 사용했는데 생각보다 기능구현이 잘되어있다. 연관관계 조회시에도 wehre절이 잘 동작한다. 하나하나 쿼리를 작성해주는것보다 훨씬 나아서 활용하기 좋아보인다.

@Entity
@Where(clause = "deleted_at is null")
class User
veluxer62 commented 12 months ago

active mq exclusive consumer 는 Queue에서 발송된 메시지를 특정 리스너만 처리하도록 고정할때 사용한다. 병렬 테스트할때 유용함

https://activemq.apache.org/exclusive-consumer

veluxer62 commented 12 months ago

spring boot 3에서 trailing slash를 명시적으로 구분하고 잇다.

https://www.baeldung.com/spring-boot-3-url-matching

veluxer62 commented 12 months ago

hibernate 6으로 업그레이드 되면서 querydsl에서 잘못된 one to one 사용에 대한 연관관계 로딩을 못하는 이슈가 발생했다.

잘못된 one to one이란 one to many - many to one으로 선언해야 할 테이블 관계를 억지로 one to one으로 선언해 사용하는 경우인데, 부모 Entity에 자식 Entity ID를 두는 형태로 해야함에도 부모 Entity를 더럽히고 싶지 않아 자식 Entity에서 부모 Entity ID를 가지도록 한것이었다.

일단 잘못된 사용방식이기 때문에 고쳐서 해결했지만....QueryDSL이 더이상 유지보수를 안하고 있다는 점에서 리스크가 점점 커지는것 같다.

veluxer62 commented 12 months ago

ldap을 동적으로 연결하려면 아래와 같이 afterPropertiesSet를 명시적으로 호출해주어야 한다.

LdapContextSource ctxSrc = new LdapContextSource();
    ctxSrc.setUrl("ldap://<url>");
    ctxSrc.setBase("dc=example,dc=local");
    ctxSrc.setUserDn("<user>@example.local");
    ctxSrc.setPassword("<pass>");

ctxSrc.afterPropertiesSet(); // this method should be called.

LdapTemplate tmpl = new LdapTemplate(ctxSrc);
setLdapTemplate(tmpl);
veluxer62 commented 12 months ago

spring boot 3으로 업그레이드하면서 Spring Security의 기본 password encoder의 알고리즘이 변경되었다. 기존에 사용하던 비밀번호를 모두 마이그레이션해줘야한다. 물론 비밀번호를 알고 있다는 전제에서 말이다. 만약 비밀번호를 알기 힘들다면 사용자에게 비밀번호를 다시 받아야한다.

veluxer62 commented 11 months ago

hibernate 6으로 올라가면서 기본적으로 타임존을 UTC로 설정한다. https://github.com/hibernate/hibernate-orm/blob/6.0/migration-guide.adoc#instant-mapping-changes

format 함수를 쓰면 timezone을 무시하니 원하는 형식으로 표현하려면 꼭 타임존을 바꾸고 format을 해줘야한다.

veluxer62 commented 11 months ago

spring boot 3.1.1 버전에서 사용하는 hibernate 6.2.5.final 버전에 몇가지 버그가 있다. 그래서 hibernate 6.2.6.final로 강제로 바꿔주는게 좋다.

하이버네이트 6.2.5.Final 기준 lazy 로드와 배치로드에 버그가 있어 버그가 수정된 6.2.6.Final 버전으로 고정 테스트 서버에서 확인해보니 조회 조건에 any 연산자가 계속 붙는것도 수정된거같네요.

https://in.relation.to/2023/06/30/hibernate-orm-626-final/

veluxer62 commented 11 months ago

jib 이미지 빌드 시간을 현재로 바꾸려면 아래와 같이 하면된다.

jib {
    val ecrRegistry = System.getenv("REGISTRY")

    from {
        image = "amazoncorretto:17.0.7"
    }
    to {
        image = ecrRegistry
        tags = setOf(getBuildVersion())
    }
    container {
        jvmFlags = listOf(
            "-XX:InitialRAMPercentage=65.0",
            "-XX:MaxRAMPercentage=65.0",
        )
        creationTime.set("USE_CURRENT_TIMESTAMP")
    }
}

https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#container-closure

veluxer62 commented 11 months ago

Hibernate 6.2.6에서 composite id 를 사용할때 기존에 사용하던 방식으로 하면 N+1 문제가 발생한다. IdClass를 사용하면 해결이 되는데...Batch loading 설정에서 복합키쪽에 메커니즘이 바꼇나보다 ㅠ

https://github.com/veluxer62/hibernate-6.2.6-batch-load-example

veluxer62 commented 11 months ago

kotlin 으로 마샬링 할때 xmlElement 속성이 매핑되지 않으면 @field:XmlElement로 정의해주자

https://stackoverflow.com/questions/47049867/xmlelement-does-not-work-when-used-in-kotlin

veluxer62 commented 11 months ago

주문서 일괄 점수 시 100개정도 접수를 하면 60개만 접수완료 메시지를 발생하는 이슈가 발생했다. 원인을 찾아보니 @TransactionalEventListener가 동시에 100개를 요청했을 때 60개만 전송하고 10개는 무시처리되는것이었다.

블로그에서 힌트를 좀 얻었는데, 아무래도 DB Connection Pool이 모자라서 이벤스 수신이 되지 않았나 예상이 되기는 하다.

ApplicationEventListener로 발행한 event를 @TransactionEventListener로 동기 처리를 할 때, 이벤트를 발행하는 쪽에서 Transaction이 commit 되었음에도 Connection은 놓지 않고 있는다.

일단 @EventListener로 변경하니 문제가 해결되어서 이슈는 해결하였지만 왜 그런일이 발생했는지 테스트를 해보아야 겠다.