วิธีแก้ไข Hibernate LazyInitializationException: ล้มเหลวในการเริ่มต้นชุดบทบาทอย่างเกียจคร้านไม่สามารถเตรียมใช้งานพร็อกซีได้ - ไม่มีเซสชัน


108

ใน AuthenticationProvider แบบกำหนดเองจากโครงการฤดูใบไม้ผลิของฉันฉันกำลังพยายามอ่านรายชื่อหน่วยงานของผู้ใช้ที่เข้าสู่ระบบ แต่ฉันพบข้อผิดพลาดต่อไปนี้:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.horariolivre.entity.Usuario.autorizacoes, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
    at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
    at com.horariolivre.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:45)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

อ่านหัวข้ออื่น ๆ จากที่นี่ใน StackOverflow ฉันเข้าใจว่าสิ่งนี้เกิดขึ้นเนื่องจากกรอบการทำงานของ atribute ประเภทนี้จัดการ แต่ฉันไม่สามารถหาวิธีแก้ปัญหาใด ๆ สำหรับกรณีของฉัน ใครบางคนสามารถชี้ว่าฉันทำอะไรผิดและฉันจะแก้ไขอะไรได้บ้าง?

รหัสของ Custom AuthenticationProvider ของฉันคือ:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UsuarioHome usuario;

    public CustomAuthenticationProvider() {
        super();
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        System.out.println("CustomAuthenticationProvider.authenticate");

        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        Usuario user = usuario.findByUsername(username);

        if (user != null) {
            if(user.getSenha().equals(password)) {
                List<AutorizacoesUsuario> list = user.getAutorizacoes();

                List <String> rolesAsList = new ArrayList<String>();
                for(AutorizacoesUsuario role : list){
                    rolesAsList.add(role.getAutorizacoes().getNome());
                }

                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                for (String role_name : rolesAsList) {
                    authorities.add(new SimpleGrantedAuthority(role_name));
                }

                Authentication auth = new UsernamePasswordAuthenticationToken(username, password, authorities);
                return auth;
            }
            else {
                return null;
            }
        } else {
            return null;
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

คลาสเอนทิตีของฉันคือ:

UsuarioHome.java

@Entity
@Table(name = "usuario")
public class Usuario implements java.io.Serializable {

    private int id;
    private String login;
    private String senha;
    private String primeiroNome;
    private String ultimoNome;
    private List<TipoUsuario> tipoUsuarios = new ArrayList<TipoUsuario>();
    private List<AutorizacoesUsuario> autorizacoes = new ArrayList<AutorizacoesUsuario>();
    private List<DadosUsuario> dadosUsuarios = new ArrayList<DadosUsuario>();
    private ConfigHorarioLivre config;

    public Usuario() {
    }

    public Usuario(String login, String senha) {
        this.login = login;
        this.senha = senha;
    }

    public Usuario(String login, String senha, String primeiroNome, String ultimoNome, List<TipoUsuario> tipoUsuarios, List<AutorizacoesUsuario> autorizacoesUsuarios, List<DadosUsuario> dadosUsuarios, ConfigHorarioLivre config) {
        this.login = login;
        this.senha = senha;
        this.primeiroNome = primeiroNome;
        this.ultimoNome = ultimoNome;
        this.tipoUsuarios = tipoUsuarios;
        this.autorizacoes = autorizacoesUsuarios;
        this.dadosUsuarios = dadosUsuarios;
        this.config = config;
    }

    public Usuario(String login, String senha, String primeiroNome, String ultimoNome, String tipoUsuario, String[] campos) {
        this.login = login;
        this.senha = senha;
        this.primeiroNome = primeiroNome;
        this.ultimoNome = ultimoNome;
        this.tipoUsuarios.add(new TipoUsuario(this, new Tipo(tipoUsuario)));
        for(int i=0; i<campos.length; i++)
            this.dadosUsuarios.add(new DadosUsuario(this, null, campos[i]));
    }

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "login", nullable = false, length = 16)
    public String getLogin() {
        return this.login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    @Column(name = "senha", nullable = false)
    public String getSenha() {
        return this.senha;
    }

    public void setSenha(String senha) {
        this.senha = senha;
    }

    @Column(name = "primeiro_nome", length = 32)
    public String getPrimeiroNome() {
        return this.primeiroNome;
    }

    public void setPrimeiroNome(String primeiroNome) {
        this.primeiroNome = primeiroNome;
    }

    @Column(name = "ultimo_nome", length = 32)
    public String getUltimoNome() {
        return this.ultimoNome;
    }

    public void setUltimoNome(String ultimoNome) {
        this.ultimoNome = ultimoNome;
    }

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "tipo_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_tipo") })
    @LazyCollection(LazyCollectionOption.TRUE)
    public List<TipoUsuario> getTipoUsuarios() {
        return this.tipoUsuarios;
    }

    public void setTipoUsuarios(List<TipoUsuario> tipoUsuarios) {
        this.tipoUsuarios = tipoUsuarios;
    }

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "autorizacoes_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_autorizacoes") })
    @LazyCollection(LazyCollectionOption.TRUE)
    public List<AutorizacoesUsuario> getAutorizacoes() {
        return this.autorizacoes;
    }

    public void setAutorizacoes(List<AutorizacoesUsuario> autorizacoes) {
        this.autorizacoes = autorizacoes;
    }

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "dados_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_dados") })
    @LazyCollection(LazyCollectionOption.TRUE)
    public List<DadosUsuario> getDadosUsuarios() {
        return this.dadosUsuarios;
    }

    public void setDadosUsuarios(List<DadosUsuario> dadosUsuarios) {
        this.dadosUsuarios = dadosUsuarios;
    }

    @OneToOne
    @JoinColumn(name="fk_config")
    public ConfigHorarioLivre getConfig() {
        return config;
    }

    public void setConfig(ConfigHorarioLivre config) {
        this.config = config;
    }
}

AutorizacoesUsuario.java

@Entity
@Table(name = "autorizacoes_usuario", uniqueConstraints = @UniqueConstraint(columnNames = "id"))
public class AutorizacoesUsuario implements java.io.Serializable {

    private int id;
    private Usuario usuario;
    private Autorizacoes autorizacoes;

    public AutorizacoesUsuario() {
    }

    public AutorizacoesUsuario(Usuario usuario, Autorizacoes autorizacoes) {
        this.usuario = usuario;
        this.autorizacoes = autorizacoes;
    }

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @OneToOne
    @JoinColumn(name = "fk_usuario", nullable = false, insertable = false, updatable = false)
    public Usuario getUsuario() {
        return this.usuario;
    }

    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }

    @OneToOne
    @JoinColumn(name = "fk_autorizacoes", nullable = false, insertable = false, updatable = false)
    public Autorizacoes getAutorizacoes() {
        return this.autorizacoes;
    }

    public void setAutorizacoes(Autorizacoes autorizacoes) {
        this.autorizacoes = autorizacoes;
    }

}

Autorizacoes.java

@Entity
@Table(name = "autorizacoes")
public class Autorizacoes implements java.io.Serializable {

    private int id;
    private String nome;
    private String descricao;

    public Autorizacoes() {
    }

    public Autorizacoes(String nome) {
        this.nome = nome;
    }

    public Autorizacoes(String nome, String descricao) {
        this.nome = nome;
        this.descricao = descricao;
    }

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "nome", nullable = false, length = 16)
    public String getNome() {
        return this.nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Column(name = "descricao", length = 140)
    public String getDescricao() {
        return this.descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }
}

โครงการเต็มมีอยู่ใน github

-> https://github.com/klebermo/webapp_horario_livre


เรียกเจ้าหน้าที่ของคุณอย่างกระตือรือร้นหรือใช้ OpenSessionInViewFilter
บาร์ต

ก็ตรงที่ฉันพยายามดูวิธีการทำ สิ่งที่ฉันได้ลองคือ: List <Autorizacoes> authority = user.getAutorizacoes ()ภายในฟังก์ชันเดียวกันจากการจัดสรร UsernamePasswordAuthenticationToken แต่ก็ยังไม่ได้ผล
Kleber Mota

2
@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
บาร์ต

โอเคฉันลองแล้ว แต่ก็ยังไม่ได้ผล อัปเดตคลาสเอนทิตีของฉันแล้ว: github.com/klebermo/webapp_horario_livre/blob/master/src/com/… , My current AuthenticationProvider: github.com/klebermo/webapp_horario_livre/blob/master/src/com/…
Kleber Mota

คำตอบ:


140

คุณต้องเพิ่มfetch=FetchType.EAGERคำอธิบายประกอบ ManyToM จำนวนมากภายในเพื่อดึงเอนทิตีลูกกลับโดยอัตโนมัติ:

@ManyToMany(fetch = FetchType.EAGER)

ตัวเลือกที่ดีกว่าคือการใช้ spring transactionManager โดยเพิ่มสิ่งต่อไปนี้ในไฟล์คอนฟิกูเรชัน spring ของคุณ:

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />

จากนั้นคุณสามารถเพิ่มคำอธิบายประกอบ @Transactional ในวิธีการพิสูจน์ตัวตนของคุณได้ดังนี้:

@Transactional
public Authentication authenticate(Authentication authentication)

จากนั้นจะเริ่มต้นธุรกรรม db ในช่วงเวลาของวิธีการพิสูจน์ตัวตนที่อนุญาตให้ดึงคอลเล็กชัน lazy จากฐานข้อมูลและเมื่อคุณพยายามใช้


1
จริงๆแล้วฉันมีการกำหนดค่า transactionManager ในแอปพลิเคชันของฉันและฉันใช้มันในคลาส DAO ของฉัน ถ้าฉันลองใช้วิธีพิสูจน์ตัวตนจาก AuthenticationProvider อย่างที่คุณแนะนำฉันได้รับข้อผิดพลาดที่เกิดจาก: java.lang.IllegalArgumentException: ไม่สามารถตั้งค่า com.horariolivre.security.CustomAuthenticationProvider ฟิลด์ com.horariolivre.security.SecurityConfig.authenticationProvider เป็น $ Proxy36 . ฉันได้รับข้อผิดพลาดเดียวกันถ้าฉันใช้เพิ่ม fetchType = FetchType.EAGER ภายในคำอธิบายประกอบ ManyToMany ของฉัน (และฉันสามารถใช้สิ่งนี้ได้ในองค์ประกอบเดียวเท่านั้น - ฉันมีสามประเภทเดียวกันในคลาสเอนทิตีของฉัน Usuario)
Kleber Mota

3
คุณต้องเดินเอนทิตีลูกที่คุณต้องการใช้ภายในธุรกรรมเพื่อหลีกเลี่ยง LazyInitializationException เนื่องจากคำอธิบายประกอบการทำธุรกรรมของคุณอยู่ในระดับ dao ในวิธีการทั่วไปคุณอาจไม่ต้องการทำเช่นนั้นดังนั้นคุณจะต้องใช้คลาสบริการที่ด้านหน้าของ dao ซึ่งมีขอบเขต @Transactional ซึ่งคุณสามารถเดิน เอนทิตีลูกที่ต้องการ
jcmwright80

1
ปกป้องคนที่พบเจอสิ่งนี้ในอนาคต @ การทำธุรกรรมต้องเป็นวิธีสาธารณะ หากไม่เป็นเช่นนั้นจะใช้ไม่ได้ อาจมีหรือไม่มีคำเตือนใด ๆ
Nicolas

ใช้ประเภทการดึงข้อมูลและทำงานได้อย่างสมบูรณ์ตั้งคำถามว่าอะไรคือความแตกต่างในการใช้การดึงข้อมูลอย่างกระตือรือร้นไปยังส่วนเคาน์เตอร์ @transactional
Austine Gwa

1
@AustineGwa ความแตกต่างที่สำคัญคือการเพิ่ม fetchType ที่กระตือรือร้นในการเข้าร่วมจะหมายความว่ารายการของเอนทิตีลูกจะถูกดึงกลับจากฐานข้อมูลเสมอเมื่อใดก็ตามที่เอนทิตีหลักถูกโหลดดังนั้นจึงมีประสิทธิภาพที่เป็นไปได้หากมีพื้นที่ของฟังก์ชันที่ต้องการเท่านั้น ข้อมูลจากเอนทิตีหลักดังนั้นการใช้ธุรกรรมและการโหลดแบบขี้เกียจช่วยให้คุณควบคุมปริมาณข้อมูลที่ดึงกลับได้มากขึ้น แต่ทั้งนี้ขึ้นอยู่กับแอปพลิเคชันและกรณีการใช้งานของคุณว่าแนวทางใดเหมาะสมกับคุณ
jcmwright80

36

วิธีที่ดีที่สุดในการจัดการLazyInitializationExceptionคือใช้JOIN FETCHคำสั่งสำหรับเอนทิตีทั้งหมดที่คุณต้องการดึงข้อมูล

อย่างไรก็ตามอย่าใช้ Anti-Patterns ต่อไปนี้ตามที่คำตอบบางคำแนะนำ:

บางครั้งการฉาย DTOLazyInitializationExceptionเป็นทางเลือกที่ดีกว่าการเรียกหน่วยงานและวิธีนี้คุณจะไม่ได้รับใด ๆ


1
การดึงเข้าร่วมเทียบเท่ากับการดึงข้อมูลอย่างกระตือรือร้น ซึ่งอาจไม่เป็นไปได้หรือมีประสิทธิภาพเสมอไป นอกจากนี้วิธีการดึงวัตถุตามปกติไม่ได้ใช้แบบสอบถาม jpql ความจริงที่ว่าเซสชันที่เปิดอยู่คือการดูเป็นปฏิปักษ์เป็นภาพที่ยาวนานและโดยสุจริตฉันไม่เห็นด้วย จะต้องใช้ด้วยความระมัดระวัง แต่มีกรณีการใช้งานที่ดีอย่างสมบูรณ์แบบมากมายที่ได้รับประโยชน์
fer.marino

4
ไม่มีก็ไม่ได้ Open Session in View คือการแฮ็กและเป็นสัญญาณว่ามีการดึงข้อมูลเอนทิตีมาใช้สำหรับการคาดการณ์แบบอ่านอย่างเดียว ไม่มีกรณีการใช้งานที่ดีอย่างสมบูรณ์แบบมากมายที่ได้รับประโยชน์จากมันไม่ว่าคุณจะพยายามแก้ตัวหนักแค่ไหนก็ตาม ไม่มีข้อแก้ตัวสำหรับการดึงข้อมูลได้มากขึ้นกว่าที่คุณไม่เป็นจริงๆต้องเช่นเดียวกับการมีข้อแก้ตัวสำหรับการรั่วไหลของข้อมูลที่เรียกนอกขอบเขตของชั้นบริการการทำธุรกรรมไม่
Vlad Mihalcea

HI Vlad คุณช่วยอธิบายได้ไหมว่าทำไม FETCH JOIN ไม่เทียบเท่ากับการโหลดอย่างกระตือรือร้น ฉันกำลังอ่านบทความนี้: blog.arnoldgalovics.com/2017/02/27/… . และมีข้อความระบุว่า "แนวคิดที่ดีกว่าคือการโหลดความสัมพันธ์ในเวลาที่คุณกำลังโหลดพาเรนต์ - บริษัท - เอนทิตีซึ่งสามารถทำได้ด้วยการดึงข้อมูลเข้าร่วม" ดังนั้นจึงเป็นการโหลดที่กระตือรือร้น ไม่ใช่เหรอ?
Geek

2
การเป็นผู้นำที่กระตือรือร้นหมายถึงการเพิ่มFetchType.EAGERความสัมพันธ์ของคุณ JOIN FETCH มีไว้สำหรับการFetchType.LAZYเชื่อมโยงที่ต้องดึงข้อมูลอย่างกระตือรือร้นในเวลาสืบค้น
Vlad Mihalcea

25

การเพิ่มคุณสมบัติต่อไปนี้ในpersistence.xmlของคุณอาจช่วยแก้ปัญหาของคุณได้ชั่วคราว

<property name="hibernate.enable_lazy_load_no_trans" value="true" />

ดังที่ @vlad-mihalcea กล่าวว่าเป็นแอนตี้แพตเทิร์นและไม่สามารถแก้ปัญหาการเริ่มต้นที่ขี้เกียจได้อย่างสมบูรณ์เริ่มต้นการเชื่อมโยงของคุณก่อนปิดธุรกรรมและใช้ DTO แทน


16

ฉันก็มีปัญหานี้เช่นกันเมื่อฉันทำการทดสอบหน่วย วิธีแก้ปัญหาที่ง่ายมากสำหรับปัญหานี้คือการใช้คำอธิบายประกอบ@Transactionalซึ่งจะเปิดเซสชันไว้จนกว่าจะสิ้นสุดการดำเนินการ


คุณใช้ Hibernate Transational หรือ JPA Transactional หรือไม่?
jDub9

1
ฉันใช้ Hibernate
KarthikaSrinivasan

11

เหตุผลก็คือเมื่อคุณใช้ lazy load เซสชันจะถูกปิด

มีสองวิธีแก้ปัญหา

  1. อย่าใช้ขี้เกียจโหลด

    ตั้งค่าlazy=falseใน XML หรือตั้งค่า@OneToMany(fetch = FetchType.EAGER)ในคำอธิบายประกอบ

  2. ใช้ขี้เกียจโหลด

    ตั้งค่าlazy=trueใน XML หรือตั้งค่า@OneToMany(fetch = FetchType.LAZY)ในคำอธิบายประกอบ

    และเพิ่มOpenSessionInViewFilter filterในไฟล์web.xml

รายละเอียดดูโพสต์ของฉัน

https://stackoverflow.com/a/27286187/1808417


1
OpenSessionInViewFilter ยังต่อต้านรูปแบบ ฉันขอแนะนำว่าอย่าตั้งค่าการแมปเป็น EAGER เนื่องจากจะมีหลายกรณีที่คุณไม่ต้องการข้อมูลนั้นในคอลเลคชัน EAGER และคุณจะดึงข้อมูลออกมามากกว่าที่กรณีการใช้งานเหล่านั้นต้องการและลดประสิทธิภาพลงอย่างมาก โปรดเก็บการแมปทั้งหมดไว้เฉยๆและเพิ่มการดึงการเข้าร่วมในการสืบค้นของคุณ
user1567291

7

คลาส Custom AuthenticationProvider ของคุณควรมีคำอธิบายประกอบดังต่อไปนี้:

@ การทำธุรกรรม

เพื่อให้แน่ใจว่ามีเซสชันไฮเบอร์เนตอยู่ที่นั่นด้วย


6

คุณสามารถใช้ hibernate lazy initializer

ด้านล่างนี้คือรหัสที่คุณสามารถอ้างอิงได้
นี่PPIDOคือออบเจ็กต์ข้อมูลที่ฉันต้องการดึง

Hibernate.initialize(ppiDO);
if (ppiDO instanceof HibernateProxy) {
    ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer()
        .getImplementation();
    ppiDO.setParentGuidObj(policyDO.getBasePlan());
    saveppiDO.add(ppiDO);
    proxyFl = true;
}

4

สำหรับผู้ที่มีปัญหาในการสะสม enumsนี่คือวิธีแก้:

@Enumerated(EnumType.STRING)
@Column(name = "OPTION")
@CollectionTable(name = "MY_ENTITY_MY_OPTION")
@ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER)
Collection<MyOptionEnum> options;

สิ่งนี้ใช้ได้กับฉัน ฉันยังทดสอบตัวเลือกในการเพิ่ม @Transactional และมันก็ใช้ได้เช่นกัน แต่ฉันเลือกตัวเลือกนี้
rick dana

2

ก่อนอื่นฉันอยากจะบอกว่าผู้ใช้ทุกคนที่พูดถึงเรื่องขี้เกียจและการทำธุรกรรมนั้นถูกต้อง แต่ในกรณีของฉันมีความแตกต่างเล็กน้อยที่ฉันใช้ผลลัพธ์ของ@Transactionalวิธีการในการทดสอบและนั่นเป็นการทำธุรกรรมนอกจริงดังนั้นฉันจึงได้รับข้อยกเว้นขี้เกียจ

วิธีการบริการของฉัน:

@Transactional
User get(String uid) {};

รหัสทดสอบของฉัน:

User user = userService.get("123");
user.getActors(); //org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role

วิธีแก้ปัญหาของฉันคือการตัดรหัสนั้นในธุรกรรมอื่นเช่นนี้:

List<Actor> actors = new ArrayList<>();
transactionTemplate.execute((status) 
 -> actors.addAll(userService.get("123").getActors()));

1

ฉันเชื่อว่าแทนที่จะเปิดใช้งานการดึงข้อมูลอย่างกระตือรือร้นควรเริ่มต้นเอนทิตีของคุณใหม่ในกรณีที่จำเป็นเพื่อหลีกเลี่ยงLazyInitializationExceptionข้อยกเว้น

Hibernate.initialize(your entity);

0

สำหรับผู้ที่ใช้JaVersซึ่งได้รับคลาสเอนทิตีที่ตรวจสอบแล้วคุณอาจต้องการละเว้นคุณสมบัติที่ทำให้เกิดLazyInitializationExceptionข้อยกเว้น (เช่นโดยใช้@DiffIgnoreคำอธิบายประกอบ)

สิ่งนี้บอกให้เฟรมเวิร์กละเว้นคุณสมบัติเหล่านั้นเมื่อคำนวณความแตกต่างของอ็อบเจ็กต์ดังนั้นจึงไม่พยายามอ่านอ็อบเจ็กต์ที่เกี่ยวข้องนอกขอบเขตธุรกรรมจากฐานข้อมูล (ทำให้เกิดข้อยกเว้น)


0

แนวทางปฏิบัติทั่วไปคือการให้บริการ@Transactionalเหนือชั้น

@Service
@Transactional
public class MyServiceImpl implements MyService{
...
}

-1

เพิ่มคำอธิบายประกอบ

@JsonManagedReference

ตัวอย่างเช่น:

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name = "autorizacoes_usuario", joinColumns = { @JoinColumn(name = "fk_usuario") }, inverseJoinColumns = { @JoinColumn(name = "fk_autorizacoes") })
@JsonManagedReference
public List<AutorizacoesUsuario> getAutorizacoes() {
    return this.autorizacoes;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.