Im benutzerdefinierten AuthenticationProvider aus meinem Frühjahrsprojekt versuche ich, die Liste der Berechtigungen des angemeldeten Benutzers zu lesen, aber es tritt der folgende Fehler auf:
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)
Wenn ich andere Themen von hier in StackOverflow lese, verstehe ich, dass dies aufgrund der Art und Weise geschieht, wie diese Art von Attribut vom Framework behandelt wird, aber ich kann keine Lösung für meinen Fall finden. Jemand kann zeigen, was ich falsch mache und was ich tun kann, um es zu beheben?
Der Code meines benutzerdefinierten Authentifizierungsanbieters lautet:
@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);
}
}
Meine Entitätsklassen sind:
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;
}
}
Vollständiges Projekt auf Github verfügbar
java
spring
hibernate
spring-mvc
spring-security
Kleber Mota
quelle
quelle
@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
Antworten:
Sie müssen entweder
fetch=FetchType.EAGER
in Ihren ManyToMany-Anmerkungen hinzufügen, um untergeordnete Entitäten automatisch zurückzuziehen:@ManyToMany(fetch = FetchType.EAGER)
Eine bessere Option wäre die Implementierung eines Spring Transaction Manager, indem Sie Ihrer Spring-Konfigurationsdatei Folgendes hinzufügen:
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driven />
Anschließend können Sie Ihrer Authentifizierungsmethode eine @ Transactional-Annotation hinzufügen:
@Transactional public Authentication authenticate(Authentication authentication)
Dadurch wird eine Datenbanktransaktion für die Dauer der Authentifizierungsmethode gestartet, sodass jede verzögerte Sammlung aus der Datenbank abgerufen werden kann, wenn Sie versuchen, sie zu verwenden.
quelle
Der beste Weg, dies zu handhaben,
LazyInitializationException
besteht darin, dieJOIN FETCH
Direktive für alle Entitäten zu verwenden, die Sie abrufen müssen.Verwenden Sie auf keinen Fall die folgenden Anti-Patterns, wie in einigen Antworten vorgeschlagen:
hibernate.enable_lazy_load_no_trans
Manchmal ist eine DTO-Projektion die bessere Wahl als das Abrufen von Entitäten, und auf diese Weise erhalten Sie keine
LazyInitializationException
.quelle
FetchType.EAGER
, Ihre Assoziationen zu erweitern. JOIN FETCH ist fürFetchType.LAZY
Assoziationen gedacht , die zur Abfragezeit eifrig abgerufen werden müssen.Das Hinzufügen der folgenden Eigenschaft zu Ihrer persistence.xml kann Ihr Problem vorübergehend lösen
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
Wie @ vlad-mihalcea sagte, ist es ein Antimuster und löst das Problem der verzögerten Initialisierung nicht vollständig. Initialisieren Sie Ihre Zuordnungen, bevor Sie die Transaktion abschließen, und verwenden Sie stattdessen DTOs.
quelle
Ich hatte auch dieses Problem, als ich Unit-Tests durchführte. Eine sehr einfache Lösung für dieses Problem ist die Verwendung der Annotation @Transactional , die die Sitzung bis zum Ende der Ausführung geöffnet hält.
quelle
Der Grund dafür ist, dass die Sitzung geschlossen wird, wenn Sie Lazy Load verwenden.
Es gibt zwei Lösungen.
Verwenden Sie keine träge Ladung.
In
lazy=false
XML oder@OneToMany(fetch = FetchType.EAGER)
In Annotation festlegen.Verwenden Sie Lazy Load.
In
lazy=true
XML oder@OneToMany(fetch = FetchType.LAZY)
In Annotation festlegen.und fügen Sie
OpenSessionInViewFilter filter
in Ihreweb.xml
Detail Siehe meinen Beitrag.
https://stackoverflow.com/a/27286187/1808417
quelle
Sie können den Lazy-Initializer für den Ruhezustand verwenden.
Unten finden Sie den Code, auf den Sie verweisen können.
Hier
PPIDO
ist das Datenobjekt, das ich abrufen möchteHibernate.initialize(ppiDO); if (ppiDO instanceof HibernateProxy) { ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer() .getImplementation(); ppiDO.setParentGuidObj(policyDO.getBasePlan()); saveppiDO.add(ppiDO); proxyFl = true; }
quelle
Ihre benutzerdefinierte AuthenticationProvider-Klasse sollte mit folgenden Anmerkungen versehen sein:
Dadurch wird sichergestellt, dass auch dort die Ruhezustandssitzung vorhanden ist.
quelle
Für diejenigen, die dieses Problem mit der Sammlung von Aufzählungen haben, ist hier, wie man es löst:
@Enumerated(EnumType.STRING) @Column(name = "OPTION") @CollectionTable(name = "MY_ENTITY_MY_OPTION") @ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER) Collection<MyOptionEnum> options;
quelle
Zunächst möchte ich sagen, dass alle Benutzer, die über Faulheit und Transaktionen gesprochen haben, Recht hatten. In meinem Fall gab es jedoch einen kleinen Unterschied darin, dass ich das Ergebnis der @ Transactional- Methode in einem Test verwendet habe und dass dies außerhalb der tatsächlichen Transaktion lag, sodass ich diese faule Ausnahme bekam.
Meine Servicemethode:
@Transactional User get(String uid) {};
Mein Testcode:
User user = userService.get("123"); user.getActors(); //org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role
Meine Lösung bestand darin, diesen Code in eine andere Transaktion wie diese zu verpacken:
List<Actor> actors = new ArrayList<>(); transactionTemplate.execute((status) -> actors.addAll(userService.get("123").getActors()));
quelle
Ich glaube, anstatt eifriges Abrufen zu ermöglichen, ist es sinnvoll, Ihre Entität dort neu zu initialisieren, wo es erforderlich ist, um
LazyInitializationException
Ausnahmen zu vermeidenquelle
Wenn Sie JaVers verwenden und eine geprüfte Entitätsklasse angeben , möchten Sie möglicherweise die Eigenschaften ignorieren, die die
LazyInitializationException
Ausnahme verursachen (z. B. mithilfe der@DiffIgnore
Anmerkung).Dies weist das Framework an, diese Eigenschaften bei der Berechnung der Objektunterschiede zu ignorieren, damit nicht versucht wird, die zugehörigen Objekte außerhalb des Transaktionsbereichs aus der Datenbank zu lesen (wodurch die Ausnahme verursacht wird).
quelle
Es ist üblich, eine
@Transactional
über Ihre Serviceklasse zu stellen.@Service @Transactional public class MyServiceImpl implements MyService{ ... }
quelle
Fügen Sie die Anmerkung hinzu
@JsonManagedReference
Zum Beispiel:
@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; }
quelle