2017-09-22 2 views
8

Kotlin에서 최대 절전 모드를 사용 중이고 @ManyToOneFetchType.LAZY과 관련된 문제가 있습니다. 다음 고려 :Kotlin으로 최대 절전 모드 : @ManyToOne (fetch = FetchType.LAZY)

@ManyToOne(fetch = FetchType.LAZY) 
open var event: Event? 

문제는 FetchType.LAZY 사용하는 경우, 인출 된 Event 그것에 JavaassistLazyInitializer와 클래스 Event_$$_jvst_...이 될 것입니다. 그러나 이벤트는 초기화되지 않으며 모든 것이 null 또는 비어 있습니다.

  1. FetchType.LAZY이 제거되면 모든 것이 올바르게 작동합니다.
  2. 자바에서는 이런 일이 발생하지 않았습니다.
  3. 이 올바르게 프록시 될 수 있도록 varopen을 추가하려고 시도했습니다. 효과가 없습니다.
  4. 모든 @Entity 클래스는 물론 open입니다. open 키워드가 제거되면 프록시가 작성되지 않으므로 게으르지 않습니다.

내 생각에 Hibernate는 이러한 기본 kotlin 게터를 쉽게 프록시 할 수 없다. 그것을 해결할 방법이 있습니까?

답변

0

당신은 당신의 문제를 확인하기 위해 내가 간단한 예제를 작성하여 법인

/** 
* Utility method that tries to properly initialize the Hibernate CGLIB 
* proxy. 
* @param <T> 
* @param maybeProxy -- the possible Hibernate generated proxy 
* @param baseClass -- the resulting class to be cast to. 
* @return the object of a class <T> 
* @throws ClassCastException 
*/ 
public static <T> T deproxy(Object maybeProxy, Class<T> baseClass) throws ClassCastException { 
    if (maybeProxy instanceof HibernateProxy) { 
     return baseClass.cast(((HibernateProxy) maybeProxy).getHibernateLazyInitializer().getImplementation()); 
    } 
    return baseClass.cast(maybeProxy); 
} 
0

을 deproxy이 정적 인 방법을 사용할 수 있으며, 모두 잘 작동합니다.

import org.hibernate.CacheMode 
import org.hibernate.Session 
import org.hibernate.SessionFactory 
import org.hibernate.Transaction 
import org.hibernate.boot.MetadataSources 
import org.hibernate.boot.registry.StandardServiceRegistryBuilder 
import org.hibernate.cfg.Environment 
import java.util.* 
import javax.persistence.* 


fun main(args: Array<String>) { 
    val standardServiceRegistryBuilder = StandardServiceRegistryBuilder() 

    val settings = HashMap<String, String>().apply { 
     put(Environment.DRIVER, "org.h2.Driver") 
     put(Environment.URL, "jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1") 
     put(Environment.USER, "sa") 
     put(Environment.PASS, "sa") 
     put(Environment.DIALECT, "org.hibernate.dialect.H2Dialect") 
     put(Environment.SHOW_SQL, "true") 
     put(Environment.HBM2DDL_AUTO, "create") 
    } 

    val sessionFactory = standardServiceRegistryBuilder.applySettings(settings) 
      .build() 
      .let { 
       MetadataSources(it).apply { 
        addAnnotatedClass(History::class.java) 
        addAnnotatedClass(Event::class.java) 
       } 
      } 
      .run { metadataBuilder.build() } 
      .run { sessionFactoryBuilder.build() } 

    sessionFactory.inSession { 
     inTransaction { session -> 
      session.save(Event(1, "event description")) 

      session.save(History(1, Event(1), "history description")) 
     } 
    } 

    sessionFactory.inSession { 
     inTransaction { session -> 
      val entity = session.get(Event::class.java, 1L) 

      println("=============1=============") 
      println(entity) 
     } 
    } 

    sessionFactory.inSession { 
     inTransaction { session -> 
      val entity = session.load(History::class.java, 1L) 

      println("=============2=============") 
      println(entity) 
     } 
    } 
} 

private fun SessionFactory.inSession(function: Session.() -> Unit) { 
    val session = this.openSession() 

    session.function() 

    session.close() 
} 

private fun Session.inTransaction(function: Transaction.(s: Session) -> Unit) { 
    val transaction = this.beginTransaction() 

    transaction.function(this) 

    transaction.commit() 
} 

@Entity 
open class History(
     @Id 
     open var id: Long? = null, 

     @ManyToOne(fetch = FetchType.LAZY) 
     @JoinColumn(name = "eventId") 
     open var event: Event? = null, 

     open var description: String = "" 
) { 
    override fun toString(): String { 
     return "History(id=$id, event=$event, description='$description')" 
    } 
} 

@Entity 
open class Event(
     @Id 
     open var id: Long? = null, 
     open var description: String? = null, 

     @OneToMany(fetch = FetchType.LAZY, mappedBy = "event") 
     open var history: MutableSet<History>? = null 
) { 
    override fun toString(): String { 
     return "Event(id=$id, description='$description', history=${history?.size})" 
    } 
} 

는 로그는 다음과 같습니다

2017-12-05 18:43:03 [main] INFO org.hibernate.Version - HHH000412: Hibernate Core {5.2.12.Final} 
2017-12-05 18:43:03 [main] INFO org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found 
2017-12-05 18:43:03 [main] INFO o.h.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {5.0.1.Final} 
2017-12-05 18:43:04 [main] WARN o.hibernate.orm.connections.pooling - HHH10001002: Using Hibernate built-in connection pool (not for production use!) 
2017-12-05 18:43:04 [main] INFO o.hibernate.orm.connections.pooling - HHH10001005: using driver [org.h2.Driver] at URL [jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1] 
2017-12-05 18:43:04 [main] INFO o.hibernate.orm.connections.pooling - HHH10001001: Connection properties: {password=****, user=sa} 
2017-12-05 18:43:04 [main] INFO o.hibernate.orm.connections.pooling - HHH10001003: Autocommit mode: false 
2017-12-05 18:43:04 [main] INFO o.h.e.j.c.i.DriverManagerConnectionProviderImpl - HHH000115: Hibernate connection pool size: 20 (min=1) 
2017-12-05 18:43:04 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect 
2017-12-05 18:43:04 [main] INFO o.h.validator.internal.util.Version - HV000001: Hibernate Validator 5.3.5.Final 
WARNING: An illegal reflective access operation has occurred 
WARNING: Illegal reflective access by javassist.util.proxy.SecurityActions (file:/Users/evgenyzaharov/.gradle/caches/modules-2/files-2.1/org.javassist/javassist/3.20.0-GA/a9cbcdfb7e9f86fbc74d3afae65f2248bfbf82a0/javassist-3.20.0-GA.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) 
WARNING: Please consider reporting this to the maintainers of javassist.util.proxy.SecurityActions 
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations 
WARNING: All illegal access operations will be denied in a future release 
Hibernate: drop table Event if exists 
2017-12-05 18:43:04 [main] INFO org.hibernate.orm.connections.access - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.[email protected]56913163] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. 
Hibernate: drop table History if exists 
Hibernate: create table Event (id bigint not null, description varchar(255), primary key (id)) 
2017-12-05 18:43:04 [main] INFO org.hibernate.orm.connections.access - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.[email protected]e8e0dec] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. 
Hibernate: create table History (id bigint not null, description varchar(255), eventId bigint, primary key (id)) 
Hibernate: alter table History add constraint FK2yaqfgh2x1lsxcpbuifmd245k foreign key (eventId) references Event 
2017-12-05 18:43:04 [main] INFO o.h.t.s.internal.SchemaCreatorImpl - HHH000476: Executing import script 'org.hiber[email protected]6c15e8c7' 
Hibernate: select event_.id, event_.description as descript2_0_ from Event event_ where event_.id=? 
Hibernate: insert into Event (description, id) values (?, ?) 
Hibernate: insert into History (description, eventId, id) values (?, ?, ?) 
Hibernate: update History set description=?, eventId=? where id=? 
Hibernate: select event0_.id as id1_0_0_, event0_.description as descript2_0_0_ from Event event0_ where event0_.id=? 
=============1============= 
Hibernate: select history0_.eventId as eventId3_1_0_, history0_.id as id1_1_0_, history0_.id as id1_1_1_, history0_.description as descript2_1_1_, history0_.eventId as eventId3_1_1_ from History history0_ where history0_.eventId=? 
Event(id=1, description='event description', history=1) 
=============2============= 
Hibernate: select history0_.id as id1_1_0_, history0_.description as descript2_1_0_, history0_.eventId as eventId3_1_0_ from History history0_ where history0_.id=? 
Hibernate: select event0_.id as id1_0_0_, event0_.description as descript2_0_0_ from Event event0_ where event0_.id=? 
Hibernate: select history0_.eventId as eventId3_1_0_, history0_.id as id1_1_0_, history0_.id as id1_1_1_, history0_.description as descript2_1_1_, history0_.eventId as eventId3_1_1_ from History history0_ where history0_.eventId=? 
History(id=1, event=Event(id=1, description='event description', history=1), description='history description') 

Lazy 초기화는 명시 적 값을 얻기 후에 필드 데이터를로드하기 시작합니다.

희망이 도움이 될 것입니다.

관련 문제