JPA PROXY

XingXiยท2024๋…„ 1์›” 3์ผ
0

JPA

๋ชฉ๋ก ๋ณด๊ธฐ
15/23
post-thumbnail

๐Ÿ• Reference

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ : ๊ต๋ณด๋ฌธ๊ณ 
์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ : ์ธํ”„๋Ÿฐ

JPA Proxy

์‹ค์ œ Entity ๋Œ€์‹  DB ์กฐํšŒ๋ฅผ ์ง€์—ฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋งํ•œ๋‹ค.

Proxy ๊ฐ์ฒด


proxy ๊ฐ์ฒด๋Š” ์‹ค์ œ Entity ๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด์ด๋‹ค.
์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ Entity ์ธ์ง€ Proxy ๊ฐ์ฒด์ธ์ง€ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•œ๋‹ค.
Proxy ๊ฐ์ฒด๋Š” ์‹ค์ œ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ณด๊ด€ํ•˜๋Š”๋ฐ ์ฒ˜์Œ Proxy ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด null ์ด ํ• ๋‹น๋œ๋‹ค.
์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ Entity ์˜ Method ํ˜ธ์ถœํ•œ๋‹ค.

SUMMARY
1. proxy ๊ฐ์ฒด๋Š” ์‹ค์ œ Entity ๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด
2. ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๋ณด๊ด€ํ•˜๋ฉฐ ์ฒ˜์Œ ์ƒ์„ฑ์‹œ null ํ• ๋‹น
3. Entity ์˜ method ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด Proxy ๊ฐ์ฒด์— ์‹ค์ œ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ฅผ ๋ณด๊ด€
4. ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ์‹ค์ œ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ๋Œ€์‹  ํ˜ธ์ถœ


Proxy ์ดˆ๊ธฐํ™”

์—…๋กœ๋“œ์ค‘..

  1. Proxy ๊ฐ์ฒด ์ถ”๊ฐ€
  2. ์‚ฌ์šฉ์ž๊ฐ€ Entity Method ํ˜ธ์ถœํ•˜๋ฉด Proxy ๊ฐ์ฒด๊ฐ€ Persistence Context ์— ์ดˆ๊ธฐํ™” ์š”์ฒญ
  3. DB ์—์„œ Persistence Context 1์ฐจ cache ๋กœ Entity ์ƒ์„ฑ
  4. ์š”์ฒญํ•œ method ๋ฅผ Proxy ๊ฐ์ฒด๊ฐ€ ๋Œ€์‹  ์ˆ˜ํ–‰

Proxy ๊ฐ์ฒด ํŠน์ง•

1. Proxy ๊ฐ์ฒด๋Š” ํ•œ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™” ๋œ๋‹ค.

Entity ์˜ Method ํ˜ธ์ถœ ์‹œ Proxy ๊ฐ์ฒด์— ์‹ค์ œ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ณด๊ด€ํ•œ๋‹ค.

2. ์ดˆ๊ธฐํ™” ๋˜์–ด๋„ ํƒ€์ž…์€ ๊ทธ๋Œ€๋กœ Proxy ๊ฐ์ฒด ํƒ€์ž…์ด๋‹ค.
์ดˆ๊ธฐํ™” ์ดํ›„ ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ์— ์ ‘๊ทผ

            /**
             * ์˜์†์„ฑ context ์— proxy ๊ฐ์ฒด๋ฅผ ๋จผ์ € ํ• ๋‹น ๋ฐ›๊ณ  ๊ทธ ํ›„์—
             * find ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ ์‹œ ํƒ€์ž… ๋น„๊ต
             * ( em.find ์‹œ์ ์— ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ์กฐํšŒ๊ฐ€ ๋œ๋‹ค )
             */
            Member refMember = em.getReference(Member.class, member.getId());
            System.out.println("Before refMember : "+refMember.getClass());

            /**
             *  DB ์— Entity ์กฐํšŒ
             */
            refMember.getName();
            System.out.println("After refMember : "+refMember.getClass());

RESULT

Before refMember : class org.example.entity.Member$HibernateProxy$8oxssjRD
Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.createDate as createDa2_0_0_,
        member0_.createUser as createUs3_0_0_,
        member0_.modifyDate as modifyDa4_0_0_,
        member0_.modifyUser as modifyUs5_0_0_,
        member0_.name as name6_0_0_,
        member0_.TEAM_ID as TEAM_ID7_0_0_,
        team1_.id as id1_1_1_,
        team1_.createDate as createDa2_1_1_,
        team1_.createUser as createUs3_1_1_,
        team1_.modifyDate as modifyDa4_1_1_,
        team1_.modifyUser as modifyUs5_1_1_,
        team1_.name as name6_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.id 
    where
        member0_.id=?
After refMember : class org.example.entity.Member$HibernateProxy$8oxssjRD

refMember๋กœ Proxy ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ›„
refMember.getName(); ๋ฅผ ํ†ตํ•ด Proxy ๊ฐ์ฒด ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ–ˆ์Œ์—๋„ ๋™์ผํ•˜๊ฒŒ PROXY ๊ฐ์ฒด์ด๋‹ค

3. ์˜์†์„ฑ Context ์กฐํšŒํ•˜๋Š” ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด
Proxy ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•ด๋„ Entity ๊ฐ์ฒด ํƒ€์ž…์ด ๋ฐ˜ํ™˜๋œ๋‹ค.

            Member m1 = em.find(Member.class, member.getId());
            System.out.println("m1 = "+m1.getClass());

            Member reference = em.getReference(Member.class, member.getId());
            System.out.println("reference = "+reference.getClass());

RESULT

Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.createDate as createDa2_0_0_,
        member0_.createUser as createUs3_0_0_,
        member0_.modifyDate as modifyDa4_0_0_,
        member0_.modifyUser as modifyUs5_0_0_,
        member0_.name as name6_0_0_,
        member0_.TEAM_ID as TEAM_ID7_0_0_,
        team1_.id as id1_1_1_,
        team1_.createDate as createDa2_1_1_,
        team1_.createUser as createUs3_1_1_,
        team1_.modifyDate as modifyDa4_1_1_,
        team1_.modifyUser as modifyUs5_1_1_,
        team1_.name as name6_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.id 
    where
        member0_.id=?
m1 = class org.example.entity.Member
reference = class org.example.entity.Member

getReference ๋ฅผ ํ†ตํ•ด Proxy ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ–ˆ์ง€๋งŒ Entity ๊ฐ์ฒด ํƒ€์ž…์ด ๋ฐ˜ํ™˜ ๋˜์—ˆ๋‹ค.
m1 = class org.example.entity.Member
reference = class org.example.entity.Member

1. Proxy ๊ฐ์ฒด๊ฐ€ ์ฐพ๋Š” ๊ฐ์ฒด๊ฐ€ Persistence Context ( 1์ฐจ Cache ) ์— ์ด๋ฏธ ์กด์žฌํ•˜๋ฉด
Proxy ๊ฐ์ฒด๊ฐ€ ํ•ด๋‹น ๊ฐ์ฒด ์ฐธ์กฐ๊ฐ’์„ ๊ฐ€์งˆ ํ•„์š”๊ฐ€์—†๋‹ค.
2. JPA ๋Š” ๋™์ผํ•œ Transaction ์— ๋™์ผํ•œ ์กฐ๊ฑด์œผ๋กœ ์กฐํšŒ๋˜๋Š” ๊ฐ’๋“ค์€ ์ „๋ถ€ ๋™์ผํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—
๊ฐ์ฒด ํƒ€์ž…์„ ๋ฐ˜ํ™˜

4. ์ค€์˜์† ์ƒํƒœ์ผ๋•Œ Proxy ์ดˆ๊ธฐํ™” ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ

            Member beforeDetach = em.getReference(Member.class, member.getId());
            System.out.println("reference : "+reference.getClass());
            em.detach(beforeDetach);
            beforeDetach.getName();

result

             *reference : class org.example.entity.Member$HibernateProxy$WC3xU0Il
             * org.hibernate.LazyInitializationException: could not initialize proxy [org.example.entity.Member#2] - no Session
             * 	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
             * 	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
             * 	at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
             * 	at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
             * 	at org.example.entity.Member$HibernateProxy$WC3xU0Il.getName(Unknown Source)
             * 	at org.example.ProxyDetachPersistence.main(ProxyDetachPersistence.java:52)
             * 1์›” 03, 2024 3:05:26 ์˜คํ›„ org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
             * INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/test;MODE=MySQL]

em.detach(beforeDetach); ์ค€์˜์†ํ™” ์ดํ›„ beforeDetach.getName(); ๋ฅผ ํ†ตํ•ด
Proxy ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๋ฉด LazyInitializationException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
์ด๋Š” Proxy ๊ฐ์ฒด์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ์˜์†์„ฑ Context ๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง€๋Š”๋ฐ
์ค€์˜์†ํ™”๋กœ ์ธํ•œ ๊ฐ์ฒด Session ์ข…๋ฃŒ ๋•Œ๋ฌธ์ด๋‹ค.

5. Proxy ํƒ•๋น„ ์ฒดํฌ์‹œ instance of ์‚ฌ์šฉ ๊ถŒ์žฅ

            /**
             *:::::::::::::::::::::::::::::::
             * find ,reference !
             * :::::::::::::::::::::::::::::::
             */

            em.flush();
            em.clear();

            /**
             * find ๋กœ ์กฐํšŒ
             */
            Member mr1 = em.find(Member.class, member.getId());
            Member mr2 = em.getReference(Member.class, member1.getId());

            /**
             *  m1 , m2 ํƒ€์ž… ๋น„๊ต
             */
            System.out.println("m1 : "+mr1.getClass());
            System.out.println("m2 : "+mr2.getClass());
            System.out.println("m1 == m2 : "+(mr1.getClass() == mr2.getClass()));

            /**
             *:::::::::::::::::::::::::::::::
             * find ,reference Success !
             * :::::::::::::::::::::::::::::::
             */

            em.flush();
            em.clear();

            /**
             * find ๋กœ ์กฐํšŒ
             */
            Member mrs1 = em.find(Member.class, member.getId());
            Member mrs2 = em.getReference(Member.class, member1.getId());

            /**
             *  m1 , m2 ํƒ€์ž… ๋น„๊ต
             *  ์‹ค์ œ๋กœ๋Š” ์–ด๋Š ๋กœ์ง์œผ๋กœ ์˜ฌ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…๋น„๊ตํ• ๋•Œ
             *  == ๋ณด๋‹ค๋Š” instance of ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
             */
            System.out.println("mrs1 : "+mrs1.getClass());
            System.out.println("mrs2 : "+mrs2.getClass());
            System.out.println("mrs1  : "+(mrs1 instanceof  Member));
            System.out.println("mrs2  : "+(mrs2 instanceof  Member));

result

m1 : class org.example.entity.Member
m2 : class org.example.entity.Member$HibernateProxy$rOQSv1a1
m1 == m2 : false
Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.createDate as createDa2_0_0_,
        member0_.createUser as createUs3_0_0_,
        member0_.modifyDate as modifyDa4_0_0_,
        member0_.modifyUser as modifyUs5_0_0_,
        member0_.name as name6_0_0_,
        member0_.TEAM_ID as TEAM_ID7_0_0_,
        team1_.id as id1_1_1_,
        team1_.createDate as createDa2_1_1_,
        team1_.createUser as createUs3_1_1_,
        team1_.modifyDate as modifyDa4_1_1_,
        team1_.modifyUser as modifyUs5_1_1_,
        team1_.name as name6_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.id 
    where
        member0_.id=?
mrs1 : class org.example.entity.Member
mrs2 : class org.example.entity.Member$HibernateProxy$rOQSv1a1
mrs1  : true
mrs2  : true

equal ์ด๋‚˜ ==๋Š” ๊ฐ์ฒด์˜ ๋‚ด์šฉ์ด๋‚˜ ์ฐธ์กฐ๊ฐ€ ์™„์ „ํžˆ ๋™์ผํ•ด์•ผ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ํ•˜์ง€๋งŒ ์‹ค์ œ logic ์—์„œ Proxy ์™€ ์‹ค์ œ Entity ๊ฐ์ฒด๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด ํƒ€์ž…์„ ํ™•์ธํ•˜๋ ค๋ฉด instance of ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด