Spring 4 MVC, Hibernate: ассоциация многие ко многим
Данный пост показывает отношение многие-ко-многим в Hibernate, на примере соединения таблиц в веб-приложении Spring 4 MVC. Мы будем обсуждать управление отношением многие-ко-многим в представлениях и в бэк-энд'ах. Мы выполним операции создания, обновления, удаления и запрос через веб-интерфейс.
Это приложение использует интерфейс org.springframework.core.convert.converter.Converter , который помогает нам в отображении ID' предметов в настоящих субъектах в базе данных.
Были использованы следующие технологии:
- Spring 4.1.7.RELEASE
- Hibernate Core 4.3.10.Final
- validation-api 1.1.0.Final
- hibernate-validator 5.1.3.Final
- MySQL Server 5.6
- Maven 3
- JDK 1.7
- NetBeans 8.0.2
APP_USER: Содержит пользователей. Пользователь может иметь несколько профилей [USER,ADMIN,DBA]. USER_PROFILE: Содержит профили пользователей. Профиль может быть связан с несколькими пользователями. APP_USER_USER_PROFILE: Это соединяющая таблица, которая связывает таблицы APP_USER и USER_PROFILE с отношением многие-ко-многим.
В демонстрационных целях, мы будем обсуждать отношение многие-ко-многим в однонаправленной установке [пользователь с профилем пользователя] в этом примере.
Шаг 2: Создаем структуру каталогаФинальная структура проекта будет выглядеть следующим образом.
Шаг 3: Обновление pom.xml, чтобы включить нужные зависимости Шаг 4: Подготовка модельных классовПосмотрите, как свойство userProfiles аннотируется c «многие-ко-многим».
@ManyToMany указывает, что есть отношение многие-ко-многим между пользователем и профилем пользователя. Пользователь может иметь несколько профилей [USER, ADMIN, DBA], в то время как, профиль может принадлежать нескольким пользователям. @JoinTable показывает, что есть ссылочная таблица, которая соединяет две таблицы, используя ограничения внешних ключей к их первичным. Эта аннотация в основном используется на стороне владеющей отношений. joinColumns ссылается к имени столбца на владеющей стороне (ID пользователя), а обратная joinColumns относится к колонке обратной стороны отношения (ID и профиль пользователя). Первичный ключ этой соединяющей таблицы есть сочетание USER_ID и USER_PROFILE_ID.
«Ленивая загрузка»
Обратите особое внимание на fetch = FetchType.LAZY .Здесь мы информируем Hibernate о «ленивой» загрузки коллекции userProfile. Данное поведение является основным. С такой установкой, запрос для загрузки коллекции будет удален, как только он впервые обратиться. Это хороший способ, чтобы избежать извлечения всех подключений объектов к графу, которая является «дорогой» операцией. Когда вы находитесь в транзакции / активной сессии, и будите пытаться получить доступ к коллекции, Hibernate будет отделять запросы для получения их.
Но если вы находитесь вне активной сессии (например сессия была закрыта / нет транзакций: вы находитесь на JSP странице), и попытались получить доступ к коллекции, вы встретитесь с org.hibernate.LazyInitializationException – could not initialize proxy – no Session . Чтобы избежать этого, вы должны инициализировать коллекцию по требованию вызовов Hibernate.initialize(user.getUserProfiles()); в активном сеансе.
Также обратите внимание, что мы не используем каскад. Это потому-что профиль пользователя не зависит от пользователя и может существовать отдельно.
Одно важное замечание: В случаи «много» ассоциаций, всегда переопределяйте методы hashCode() и equals(), которые наблюдаются Hibernate'ом при проведении сущностей в коллекции.
Класс UserProfile
Так как мы показываем однонаправленное отношение (пользователя к профилю пользователя), то нет необходимости ссылаться на пользователя в профиле пользователя.
UserProfileType
Шаг 5: Создания слоя DAOИнтерфейс UserDao
Интерфейс UserProfileDao
Абстрактный класс AbstractDao
Класс UserDaoImpl
Класс UserProfileDaoImpl
Шаг 6: Создание сервисного слояИнтерфейс UserProfileService
Интерфейс UserServiceКласс UserProfileServiceImpl
Класс UserServiceImpl
Шаг 7: Создание настроек HibernateКласс HibernateConfiguration
Настройки для Hibernate:
jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/таблица jdbc.username = пользователь jdbc.password = пароль hibernate.dialect = org.hibernate.dialect.MySQLDialect hibernate.show_sql = true hibernate.format_sql = true
Шаг 8: Создание контроллераСообщения, которые используются выше описаны в messages.properties файле: NotEmpty.user.firstName=Поле имя не может быть пустым. NotEmpty.user.lastName=Поле фамилия не может быть пустым. NotEmpty.user.email=Поле маил не может быть пустым. NotEmpty.user.password=Поле пароля не может быть пустым. NotEmpty.user.ssoId=Поле SSO ID не может быть пустым. NotEmpty.user.userProfiles=Как минимум необходимо выбрать один профиль. non.unique.ssoId=SSO ID уже существует. Пожалуйста, выберете другое значение.
Шаг 9: Создание конвертераЭто сердце это поста. Это заботится об отображение отдельных ID профилей пользователя к фактическим сущностям профилей пользователя в базе данных.
Класс RoleToUserProfileConverter
Шаг 10: Создание настроек SpringКласс AppConfig
Во-первых интересной вещью является регистрационный конвертер, который мы создали в предыдущих уроках с настройкой Spring'a c использованием addFormatters. Следующий метод configurePathMatch, который обеспечивает обходной путь (хотя существуют и другие обходные пути) для известного бага в Spring, который также присутствует в Spring 4.1.7.RELEASE.