Я создал отношение «многие ко многим» пользователей к проектам в базе данных MySQL и использовал hbm2java (инструмент гибернации для генерации классов Java из таблиц базы данных).Поскольку я использую плагин gradle org.hibernate.gradle.tools.Schema, у меня нет файла hibernate.cfg.xml.
. Я могу получить и правильно распечатать список пользователей из моего потомка CrudRepository<User,Long>
(см. Мой код ниже), и каждый пользовательский объект имеет функцию getProjects()
.Когда я пытаюсь выполнить итерации проектов, принадлежащих пользователю, я получаю эту ошибку:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.xyz.dbmodel.orm.User.projects, could not initialize proxy - no Session
Я хочу придерживаться подхода ленивой загрузки по умолчанию, используемого Java-кодом, сгенерированным hbm2java.
Я пытался позвонить Hibernate.Initialize(user.getProjects())
(как обсуждено на https://howtodoinjava.com/hibernate/use-hibernate-initialize-to-initialize-proxycollection/), но я все еще получаю ту же ошибку, когда пытаюсь выполнить
for(Project project : user.getProjects()) {... }
Все примеры, которые я могнайти, кажется, предположить, что я мог бы выполнить выше для цикла и разархивировать каждый проект. Я не могу.
Вот мой репозиторий:
import org.springframework.data.repository.CrudRepository;
import com.xyz.dataservice.dbmodel.orm.User;
public interface UserRepository extends CrudRepository<User, Long> {}
Здесь я создаю репозиторий:
@Autowired com.xyz.repository.UserRepository userRepository;
Здесь я успешно извлекаю список пользователей
Iterable<User> users = userRepository.findAll();
for(User user : users) {
log.info("User="+user.getName()); // this works!
Set<Project> projects = user.getProjects();
for(Project p : projects) // Error happens here!
{
log.info(" project="+p.getName());
}
}
Ожидаемые результаты: я получаю список проектов для каждого пользователя. Фактические результаты являются исключением org.hibernate.LazyInitializationException
.
Спасибо!
Фев 02 2019 Утреннее обновление
Относительно конфигурации Hibernate
Я не уверен, что вы имеете в виду. Мой плагин gradle генерирует этот файл hibernate.cfg.XML-файл:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306</property>
<property name="hibernate.connection.username">searchapp_user</property>
<property name="hibernate.connection.password">secret</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
</session-factory>
</hibernate-configuration>
…
Добавление транзакции
Я добавил org.springframework.transaction.annotation.Transactional
к новой функции, которую я вызываю
@Transactional
public int fetchUsers() {
Iterable<User> users = userRepository.findAll();
return listUsers(users, "");
}
Когда это не помогло, я попытался расширить свой репозиторий с помощью атрибута Transactional:
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
@Transactional
public List<User> findAll();
}
Черт, это тоже не помогло.Я заметил эту странную запись в акрах записей журнала.Что это значит?
2019-02-01 10:50:42.285 INFO 5096 --- [ restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$6c9c1be1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Еще раз спасибо!
Фев 02 2019 Обновление во второй половине дня
Ой, я забыл проверить эту ссылку в отношении транзакционной документации.
I 'Я не уверен, как использовать @Bean и @Transactional для одной и той же функции.
Можете ли вы показать мне пример?
Примеры @Bean, которые я видел, возвращают лямбду, которая затем загадочно вызывается позже.Нужно ли лямбда быть объявленным транзакционным?Это возможно?Если нет, нужно ли заменить лямбду потомком java.util.function.Consumer <>, функция принятия которого объявлена с @Transactional?
Фев 05 2019 Обновление: решение найдено!
Я использовал новый лямбда-синтаксис Java8 и мне пришлось отказаться от него в пользу более старого синтаксиса внутреннего класса, чтобы я мог объявить функцию @Transactional.
@Transactional
class InitSpecialCommandLineRunner implements org.springframework.boot.CommandLineRunner{
@Transactional // this is important!
@Override
public void run(String[] args) {
int count = listProjectsForEachUser(); // this works!
}
}
@org.springframework.context.annotation.Profile("initialize")
@org.springframework.context.annotation.Bean
@Transactional
public org.springframework.boot.CommandLineRunner initSpecial() {
return new InitSpecialCommandLineRunner(); // this works
// How to declare this transactional?
// return args ->
// {
// int count = fetchUsers();
// Iterable<User> users;
// };
}
Надеюсь, это когда-нибудь поможет кому-то еще.