Di AuthenticationProvider kustom dari proyek musim semi saya, saya mencoba membaca daftar otoritas pengguna yang login, tetapi saya menghadapi kesalahan berikut:
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)
Membaca topik lain dari sini di StackOverflow, saya mengerti ini terjadi karena cara atribut jenis ini ditangani oleh kerangka kerja, tetapi saya tidak dapat menemukan solusi apa pun untuk kasus saya. Seseorang dapat menunjukkan kesalahan yang saya lakukan dan apa yang dapat saya lakukan untuk memperbaikinya?
Kode dari Custom AuthenticationProvider saya adalah:
@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);
}
}
Kelas Entitas Saya adalah:
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;
}
}
Proyek lengkap tersedia di github
java
spring
hibernate
spring-mvc
spring-security
Kleber Mota
sumber
sumber
@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
Jawaban:
Anda perlu menambahkan
fetch=FetchType.EAGER
di dalam anotasi ManyToMany Anda untuk secara otomatis menarik kembali entitas anak:@ManyToMany(fetch = FetchType.EAGER)
Opsi yang lebih baik adalah mengimplementasikan spring transactionManager dengan menambahkan berikut ini ke file konfigurasi spring Anda:
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driven />
Anda kemudian dapat menambahkan anotasi @Transactional ke metode autentikasi Anda seperti:
@Transactional public Authentication authenticate(Authentication authentication)
Ini kemudian akan memulai transaksi db selama durasi metode otentikasi yang memungkinkan setiap koleksi malas diambil dari db saat Anda mencoba menggunakannya.
sumber
Cara terbaik untuk menanganinya
LazyInitializationException
adalah dengan menggunakanJOIN FETCH
direktif untuk semua entitas yang perlu Anda ambil.Bagaimanapun, JANGAN gunakan Anti-Pola berikut seperti yang disarankan oleh beberapa jawaban:
hibernate.enable_lazy_load_no_trans
Terkadang, proyeksi DTO adalah pilihan yang lebih baik daripada mengambil entitas, dan dengan cara ini, Anda tidak akan mendapatkannya
LazyInitializationException
.sumber
FetchType.EAGER
asosiasi Anda. JOIN FETCH adalah untukFetchType.LAZY
pengaitan yang perlu diambil dengan penuh semangat pada waktu kueri.Menambahkan properti berikut ke persistence.xml Anda dapat menyelesaikan masalah Anda untuk sementara
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
Seperti yang dikatakan @ vlad-mihalcea itu antipattern dan tidak menyelesaikan masalah inisialisasi malas sepenuhnya, inisialisasi asosiasi Anda sebelum menutup transaksi dan sebagai gantinya gunakan DTO.
sumber
Saya juga mengalami masalah ini saat melakukan Pengujian unit. Solusi yang sangat sederhana untuk masalah ini adalah dengan menggunakan anotasi @Transactional yang membuat sesi tetap terbuka hingga akhir eksekusi.
sumber
Alasannya adalah saat Anda menggunakan lazy load, sesi ditutup.
Ada dua solusi.
Jangan gunakan lazy load.
Atur
lazy=false
dalam XML atau Atur@OneToMany(fetch = FetchType.EAGER)
dalam anotasi.Gunakan lazy load.
Atur
lazy=true
dalam XML atau Atur@OneToMany(fetch = FetchType.LAZY)
dalam anotasi.dan tambahkan
OpenSessionInViewFilter filter
Andaweb.xml
Detail Lihat posting saya.
https://stackoverflow.com/a/27286187/1808417
sumber
Kelas Custom AuthenticationProvider Anda harus dianotasi dengan berikut ini:
Ini akan memastikan kehadiran sesi hibernasi di sana juga.
sumber
Anda dapat menggunakan penginisialisasi malas hibernate.
Di bawah ini adalah kode yang bisa Anda referensikan.
Berikut
PPIDO
adalah objek data yang ingin saya ambilHibernate.initialize(ppiDO); if (ppiDO instanceof HibernateProxy) { ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer() .getImplementation(); ppiDO.setParentGuidObj(policyDO.getBasePlan()); saveppiDO.add(ppiDO); proxyFl = true; }
sumber
Bagi mereka yang memiliki masalah dengan kumpulan enum berikut adalah cara mengatasinya:
@Enumerated(EnumType.STRING) @Column(name = "OPTION") @CollectionTable(name = "MY_ENTITY_MY_OPTION") @ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER) Collection<MyOptionEnum> options;
sumber
Pertama-tama saya ingin mengatakan bahwa semua pengguna yang mengatakan tentang malas dan transaksi itu benar. Tetapi dalam kasus saya, ada sedikit perbedaan di mana saya menggunakan hasil metode @Transactional dalam pengujian dan itu di luar transaksi nyata jadi saya mendapat pengecualian malas ini.
Metode layanan saya:
@Transactional User get(String uid) {};
Kode tes saya:
User user = userService.get("123"); user.getActors(); //org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role
Solusi saya untuk ini adalah membungkus kode itu dalam transaksi lain seperti ini:
List<Actor> actors = new ArrayList<>(); transactionTemplate.execute((status) -> actors.addAll(userService.get("123").getActors()));
sumber
Saya yakin daripada mengaktifkan eager fetch, masuk akal untuk menginisialisasi ulang entitas Anda di tempat yang diperlukan untuk menghindari
LazyInitializationException
pengecualiansumber
Untuk mereka yang menggunakan JaVers , diberikan kelas entitas yang diaudit, Anda mungkin ingin mengabaikan properti yang menyebabkan
LazyInitializationException
pengecualian (misalnya dengan menggunakan@DiffIgnore
anotasi).Ini memberitahu kerangka kerja untuk mengabaikan properti tersebut saat menghitung perbedaan objek, sehingga kerangka tidak akan mencoba untuk membaca dari DB objek terkait di luar cakupan transaksi (sehingga menyebabkan pengecualian).
sumber
Praktik umum adalah menempatkan di
@Transactional
atas kelas layanan Anda.@Service @Transactional public class MyServiceImpl implements MyService{ ... }
sumber
Tambahkan anotasi
@JsonManagedReference
Sebagai contoh:
@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; }
sumber