В пользовательском 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, я понимаю, что это происходит из-за того, как этот тип атрибута обрабатывается фреймворком, но я не могу найти никакого решения для своего случая. Кто-то может указать, что я делаю не так и что я могу сделать, чтобы это исправить?
Код моего 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);
}
}
Мои классы Entity:
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
java
spring
hibernate
spring-mvc
spring-security
Клебер Мота
источник
источник
@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
Ответы:
Вам нужно либо добавить
fetch=FetchType.EAGER
в свои аннотации ManyToMany, чтобы автоматически извлекать дочерние объекты:@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)
Затем это запустит транзакцию базы данных на время действия метода аутентификации, позволяя извлекать любую ленивую коллекцию из базы данных по мере того, как вы пытаетесь их использовать.
источник
Лучший способ справиться с этим
LazyInitializationException
- использоватьJOIN FETCH
директиву для всех сущностей, которые вам нужно получить.В любом случае НЕ ИСПОЛЬЗУЙТЕ следующие антипаттерны, как указано в некоторых ответах:
hibernate.enable_lazy_load_no_trans
Иногда проекция DTO - лучший выбор, чем получение сущностей, и таким образом вы ничего не получите
LazyInitializationException
.источник
FetchType.EAGER
к вашим ассоциациям. JOIN FETCH предназначен дляFetchType.LAZY
ассоциаций, которые необходимо быстро извлекать во время запроса.Добавление следующего свойства в ваш persistence.xml может временно решить вашу проблему
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
Поскольку @ vlad-mihalcea сказал, что это антипаттерн и не решает полностью проблему ленивой инициализации, инициализируйте свои ассоциации перед закрытием транзакции и вместо этого используйте DTO.
источник
У меня тоже была эта проблема, когда я проводил модульное тестирование. Очень простое решение этой проблемы - использовать аннотацию @Transactional, которая сохраняет сеанс открытым до конца выполнения.
источник
Причина в том, что при использовании отложенной загрузки сессия закрывается.
Есть два решения.
Не используйте ленивую загрузку.
Установить
lazy=false
в@OneToMany(fetch = FetchType.EAGER)
аннотации XML или Установить .Используйте ленивую загрузку.
Установить
lazy=true
в@OneToMany(fetch = FetchType.LAZY)
аннотации XML или Установить .и добавьте
OpenSessionInViewFilter filter
в свойweb.xml
Подробно см. Мой пост.
https://stackoverflow.com/a/27286187/1808417
источник
Вы можете использовать ленивый инициализатор гибернации.
Ниже приведен код, к которому вы можете обратиться.
Вот
PPIDO
объект данных, который я хочу получитьHibernate.initialize(ppiDO); if (ppiDO instanceof HibernateProxy) { ppiDO = (PolicyProductInsuredDO) ((HibernateProxy) ppiDO).getHibernateLazyInitializer() .getImplementation(); ppiDO.setParentGuidObj(policyDO.getBasePlan()); saveppiDO.add(ppiDO); proxyFl = true; }
источник
Ваш класс Custom AuthenticationProvider должен быть аннотирован следующим образом:
Это также обеспечит наличие сеанса гибернации.
источник
Для тех, у кого есть эта проблема со сбором перечислений, вот как ее решить:
@Enumerated(EnumType.STRING) @Column(name = "OPTION") @CollectionTable(name = "MY_ENTITY_MY_OPTION") @ElementCollection(targetClass = MyOptionEnum.class, fetch = EAGER) Collection<MyOptionEnum> options;
источник
Прежде всего, хочу сказать, что все пользователи, которые говорили о ленивости и транзакциях, были правы. Но в моем случае была небольшая разница в том, что я использовал результат метода @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()));
источник
Я считаю, что вместо включения активной выборки имеет смысл повторно инициализировать вашу сущность там, где это необходимо, чтобы избежать
LazyInitializationException
исключения.источник
Для тех, кто использует JaVers , учитывая проверенный класс сущности, вы можете игнорировать свойства, вызывающие
LazyInitializationException
исключение (например, используя@DiffIgnore
аннотацию).Это указывает инфраструктуре игнорировать эти свойства при вычислении различий объектов, поэтому она не будет пытаться читать из БД связанные объекты вне области транзакции (что вызывает исключение).
источник
Обычная практика - ставить
@Transactional
выше вашего класса обслуживания.@Service @Transactional public class MyServiceImpl implements MyService{ ... }
источник
Добавьте аннотацию
@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; }
источник