Я нахожусь в процессе переноса проекта из:
- Весна 4.2.1 -> 5.0.0
- Spring Data Гослинг -> Кей
- Гибернация 4.3.8 -> 5.8.0
И я получаю «org.hibernate.LazyInitializationException: не удалось инициализировать прокси — нет сеанса» при доступе к объекту, поступающему из моей базы данных в методе контроллера.
Вот урезанная версия моего кода:
// CustomUser.java
@Entity
@Access(AccessType.FIELD)
@Table(name = "users")
public class CustomUser implements Serializable {
...
@Id
@GeneratedValue//details omitted
@GenericGenerator//details omitted
@Column(name = "id", insertable = true, updatable = true, unique = true, nullable = false)
private Long id;
@Column(name = "name")
private String name;
public String getName() { return name; }
}
// UserController.java
@RequestMapping(value = "/user/{userId}/", method = RequestMethod.GET)
public String showUser(@PathVariable("userId") CustomUser user) {
System.out.println("user name is [" + user.getName() + "]");
return "someTemplate";
}
// UserService.java
@Service
public class UserServiceImpl implements UserService {
@Autowired UserRepository userRepository;
@Override
public User findUserById(Long userId) {
return userRepository.getOne(userId);
}
}
// UserRepository.java
public interface UserRepository extends JpaRepository<CustomUser, Long> { }
// UserConverter.java
@Component
public class UserConverter implements Converter<String, CustomUser> {
@Autowired UserService userService;
@Override
public CustomUser convert(String userId) {
CustomUser user = userService.findUserById(SomeUtilClass.parseLong(userId));
return user;
}
}
Существует также класс @Configuration WebMvcConfigurerAdapter, который автоматически связывает экземпляр UserConverter и добавляет его в FormatterRegistry.
Перед началом этого обновления я мог нажать: http://server:port/user/123/
и Spring возьмет строку «123», метод UserConverter::convert сработает и попадет в базу данных Postgres, чтобы найти пользователя с этим идентификатором, и я верну объект CustomUser в методе «showUser» моего контроллера.
Но теперь я получаю исключение org.hibernate.LazyInitializationException. Это происходит, когда я пытаюсь распечатать имя пользователя в методе «showUser» или даже просто «println(user)» без доступа к полю.
Большая часть информации, которую я смог найти в результате поиска, предполагает, что это исключение возникает из-за того, что объект имеет лениво загруженную коллекцию подобъектов (например, если бы у моего CustomUser была коллекция объектов Permission или что-то, что сопоставлено с другой базой данных Таблица). Но в данном случае я даже этого не делаю, это просто поле на объекте.
Мое лучшее предположение на данный момент заключается в том, что это связано с тем, что какой-то сеанс гибернации завершается после того, как преобразователь выполнит свою работу, поэтому, вернувшись в контроллер, у меня нет действительного сеанса. (хотя опять же, я не знаю, почему объект CustomUser становится непригодным для использования, я не пытаюсь получить подколлекцию).
Я добавил аннотацию Hibernate «@Proxy(lazy = false)» в свой CustomUser.java, и если я это сделаю, проблема исчезнет. Но я не уверен, что это хорошее решение - по соображениям производительности я действительно не думаю, что хочу идти по пути жадного извлечения ВСЕХ.
Я также пытался аннотировать различные вещи (метод службы, метод контроллера и т. д.) с помощью @Transactional; Я не заставил это работать, но я все еще достаточно новичок в Spring, и, возможно, я пытаюсь это сделать не в том месте или неправильно понимаю, что это должно делать.
Есть ли лучший способ справиться с этим, чем просто «@Proxy(lazy = false)» для всех моих классов Entity?