Поэтому я подумал сделать серию примеров гибернации, показывающих различные функции гибернации. В первой части я хотел показать, как удалить функцию «Сирота» и как ее можно использовать с сюжетной линией. Итак, давайте начнем ?
Предварительные условия :
Для того, чтобы попробовать следующий пример, вам понадобятся следующие JAR-файлы:
- org.springframework.aop-3.0.6.RELEASE.jar
- org.springframework.asm-3.0.6.RELEASE.jar
- org.springframework.aspects-3.0.6.RELEASE.jar
- org.springframework.beans-3.0.6.RELEASE.jar
- org.springframework.context.support-3.0.6.RELEASE.jar
- org.springframework.context-3.0.6.RELEASE.jar
- org.springframework.core-3.0.6.RELEASE.jar
- org.springframework.jdbc-3.0.6.RELEASE.jar
- org.springframework.orm-3.0.6.RELEASE.jar
- org.springframework.transaction-3.0.6.RELEASE.jar.
- org.springframework.expression-3.0.6.RELEASE.jar
- Обще-каротаж 1.0.4.jar
- log4j.jar
- aopalliance-1.0.jar
- dom4j-1.1.jar
- Hibernate-Викисклад аннотации-3.2.0.Final.jar
- Зимуют-ядро-3.6.4.Final.jar
- спящий режим JPA-2,0-апи-1.0.0.Final.jar-
- javax.persistence-2.0.0.jar
- JTA-1.1.jar
- Javassist-3.1.jar
- SLF4J-апи-1.6.2.jar
- MySQL-разъем-Java-5.1.13-bin.jar
- Викисклад коллекция-3.0.jar
Для тех, кто хочет, чтобы проект eclipse попробовал это, вы можете скачать его с вышеупомянутыми зависимостями JAR здесь .
Введение :
Его 2011 год. И Лига Справедливости выросла пропорционально и ищет разработчика, который поможет создать систему регистрации супергероев. Разработчик, компетентный в Hibernate и ORM, готов создать систему и обработать уровень персистентности с помощью Hibernate. Для простоты Он будет использовать простое отдельное приложение для сохранения супер героев. Вот как будет выглядеть этот пример:
- Дизайн стола
- Доменные классы и отображения Hibernate
- DAO & Сервисные классы
- Конфигурация Spring для приложения
- Простой основной класс, чтобы показать, как все это работает
Пусть путешествие начнется ………………….
Дизайн стола:
Конструкция состоит из трех простых таблиц, как показано на диаграмме ниже;
Как вы можете видеть, это простое отношение «один ко многим», связанное таблицей соединений. Таблица соединений будет использоваться Hibernate для заполнения списка супергероев, который находится в доменном классе, который мы продолжим видеть дальше.
Классы домена и отображения Hibernate:
В основном, существует только два класса доменов в виде таблицы Join, связанной с основным объектом-владельцем, который является объектом Лиги справедливости. Итак, давайте посмотрим, как классы доменов создаются с помощью аннотаций;
package com.justice.league.domain; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Type; @Entity @Table(name = "SuperHero") public class SuperHero implements Serializable { /** * */ private static final long serialVersionUID = -6712720661371583351L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "super_hero_id") private Long superHeroId; @Column(name = "super_hero_name") private String name; @Column(name = "power_description") private String powerDescription; @Type(type = "yes_no") @Column(name = "isAwesome") private boolean isAwesome; public Long getSuperHeroId() { return superHeroId; } public void setSuperHeroId(Long superHeroId) { this.superHeroId = superHeroId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPowerDescription() { return powerDescription; } public void setPowerDescription(String powerDescription) { this.powerDescription = powerDescription; } public boolean isAwesome() { return isAwesome; } public void setAwesome(boolean isAwesome) { this.isAwesome = isAwesome; } }
Поскольку я использую MySQL в качестве основной базы данных, я использовал стратегию GeneratedValue в качестве GenerationType.AUTO, которая будет выполнять автоматическое увеличение при создании нового супергероя. Все остальные сопоставления знакомы всем, за исключением последней переменной, в которой мы сопоставляем логическое поле с полем Char в базе данных.
Мы используем аннотацию @Type Hibernate, чтобы представлять истину и ложь как Y & N в поле базы данных. Hibernate имеет много реализаций @Type, о которых вы можете прочитать здесь . В этом случае мы использовали этот тип.
Хорошо, теперь, когда у нас есть наш класс для представления Супергероев, давайте посмотрим, как выглядит наш класс доменов Лиги справедливости, в котором отслеживаются все супергерои, которые пообещали преданность Лиге.
package com.justice.league.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "JusticeLeague") public class JusticeLeague implements Serializable { /** * */ private static final long serialVersionUID = 763500275393020111L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "justice_league_id") private Long justiceLeagueId; @Column(name = "justice_league_moto") private String justiceLeagueMoto; @Column(name = "number_of_members") private Integer numberOfMembers; @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true) @JoinTable(name = "JUSTICE_LEAGUE_SUPER_HERO", joinColumns = { @JoinColumn(name = "justice_league_id") }, inverseJoinColumns = { @JoinColumn(name = "super_hero_id") }) private List<SuperHero> superHeroList = new ArrayList<SuperHero>(0); public Long getJusticeLeagueId() { return justiceLeagueId; } public void setJusticeLeagueId(Long justiceLeagueId) { this.justiceLeagueId = justiceLeagueId; } public String getJusticeLeagueMoto() { return justiceLeagueMoto; } public void setJusticeLeagueMoto(String justiceLeagueMoto) { this.justiceLeagueMoto = justiceLeagueMoto; } public Integer getNumberOfMembers() { return numberOfMembers; } public void setNumberOfMembers(Integer numberOfMembers) { this.numberOfMembers = numberOfMembers; } public List<SuperHero> getSuperHeroList() { return superHeroList; } public void setSuperHeroList(List<SuperHero> superHeroList) { this.superHeroList = superHeroList; } }
Важный факт, на который следует обратить внимание, это аннотация @OneToMany (cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, orphanRemoval = true) . Здесь мы установили orphanRemoval = true .
Так что же это делает? Итак, скажем, что у вас есть группа супергероев в вашей лиге. И скажем, один супер герой сходит с ума. Таким образом, мы должны удалить Его / Ее из Лиги. С каскадом JPA это невозможно, поскольку он не обнаруживает записи «Сирот», и вы попадете в базу данных с удаленными супергероями, в то время как ваша коллекция все еще имеет ссылку на нее.
До JPA 2.0 у вас не было поддержки orphanRemoval, и единственный способ удалить потерянные записи состоял в том, чтобы использовать следующую специфичную для Hibernate аннотацию (или спецификацию ORM), которая теперь не рекомендуется;
@ org.hibernate.annotations.Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
Но с введением атрибута orphanRemoval мы теперь можем обрабатывать удаление потерянных записей через JPA. Теперь, когда у нас есть классы домена
DAO и классы обслуживания:
чтобы соответствовать хорошим стандартам проектирования, я разделил уровень DAO (объекта доступа к данным) и уровень обслуживания. Итак, давайте посмотрим интерфейс и реализацию DAO. Обратите внимание, что я использовал HibernateTemplate через HibernateDAOSupport, чтобы не допустить каких-либо специфических деталей Hibernate и получить доступ ко всему унифицированным способом с помощью Spring.
package com.justice.league.dao; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.justice.league.domain.JusticeLeague; @Transactional(propagation = Propagation.REQUIRED, readOnly = false) public interface JusticeLeagueDAO { public void createOrUpdateJuticeLeagure(JusticeLeague league); public JusticeLeague retrieveJusticeLeagueById(Long id); }
На уровне интерфейса я определил обработку транзакций как обязательную. Это сделано для того, чтобы всякий раз, когда вам не нужна транзакция, вы можете определить это на уровне метода этого конкретного метода, а в более сложных ситуациях вам понадобится транзакция, за исключением методов извлечения данных.
В соответствии со спецификацией JPA вам необходима действующая транзакция для функций вставки / удаления / обновления .
Итак, давайте посмотрим на реализацию DAO;
package com.justice.league.dao.hibernate; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.justice.league.dao.JusticeLeagueDAO; import com.justice.league.domain.JusticeLeague; @Qualifier(value="justiceLeagueHibernateDAO") public class JusticeLeagueHibernateDAOImpl extends HibernateDaoSupport implements JusticeLeagueDAO { @Override public void createOrUpdateJuticeLeagure(JusticeLeague league) { if (league.getJusticeLeagueId() == null) { getHibernateTemplate().persist(league); } else { getHibernateTemplate().update(league); } } @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = false) public JusticeLeague retrieveJusticeLeagueById(Long id){ return getHibernateTemplate().get(JusticeLeague.class, id); } }
Здесь я определил @Qualifier, чтобы сообщить Spring, что это Hibernate-реализация класса DAO. Обратите внимание на имя пакета, которое заканчивается на hibernate. Это, как я вижу, является хорошей концепцией дизайна, которой нужно следовать, когда вы разделяете ваши реализации на отдельные пакеты, чтобы сохранить дизайн в чистоте.
Хорошо, давайте перейдем к реализации сервисного уровня. Уровень обслуживания в этом случае просто действует как уровень передачи для вызова методов DAO. Но в реальном приложении у вас, вероятно, будут другие проверки, связанные с безопасностью процедуры и т. Д., Выполняемые на уровне обслуживания.
package com.justice.league.service; import com.justice.league.domain.JusticeLeague; public interface JusticeLeagureService { public void handleJusticeLeagureCreateUpdate(JusticeLeague justiceLeague); public JusticeLeague retrieveJusticeLeagueById(Long id); }
package com.justice.league.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.justice.league.dao.JusticeLeagueDAO; import com.justice.league.domain.JusticeLeague; import com.justice.league.service.JusticeLeagureService; @Component("justiceLeagueService") public class JusticeLeagureServiceImpl implements JusticeLeagureService { @Autowired @Qualifier(value = "justiceLeagueHibernateDAO") private JusticeLeagueDAO justiceLeagueDAO; @Override public void handleJusticeLeagureCreateUpdate(JusticeLeague justiceLeague) { justiceLeagueDAO.createOrUpdateJuticeLeagure(justiceLeague); } public JusticeLeague retrieveJusticeLeagueById(Long id){ return justiceLeagueDAO.retrieveJusticeLeagueById(id); } }
Несколько вещей, чтобы отметить здесь. Прежде всего, @Component связывает эту реализацию сервиса с именем JusticeLeagueService в контексте весны, чтобы мы могли ссылаться на bean-компонент как bean-компонент с идентификатором JusticeLeagueService.
И мы автоматически подключили JusticeLeagueDAO и определили @Qualifier, чтобы он был связан с реализацией Hibernate.
Значением Qualifier должно быть то же имя, которое мы дали Qualifier уровня класса в классе реализации DAO. И наконец, давайте посмотрим на конфигурацию Spring, которая соединяет все это вместе;
Конфигурация Spring для приложения:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.justice.league" /> <context:annotation-config /> <tx:annotation-driven /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="packagesToScan"> <list> <value>com.justice.league.**.*</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop> <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/my_test</prop> <prop key="hibernate.connection.username">root</prop> <prop key="hibernate.connection.password">password</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> </props> </property> </bean> <bean id="justiceLeageDAO" class="com.justice.league.dao.hibernate.JusticeLeagueHibernateDAOImpl"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
Обратите внимание, что я использовал HibernateTransactionManager в этом случае, так как я запускаю его отдельно. Если вы используете его на сервере приложений, вы почти всегда будете использовать менеджер транзакций JTA.
Я также использовал автоматическое создание таблиц в спящем режиме для простоты. Свойство packagesToScan предписывает сканировать все подпакеты (включая вложенные, упакованные в них) внутри корневого пакета com.justice.league. **. * Для сканирования на наличие аннотированных классов @Entity.
Мы также привязали фабрику сессий к JusticeLeagueDAO, чтобы мы могли работать с шаблоном Hibernate. Для целей тестирования вы можете использовать тег <prop key = «hibernate.hbm2ddl.auto»> create </ prop>изначально, если хотите, и позвольте hibernate создать таблицы для вас. Итак, теперь, когда мы увидели строительные блоки приложения, давайте посмотрим, как все это работает, сначала создав несколько супергероев в рамках Лиги справедливости
. Простой основной класс, чтобы показать, как все это работает.
В первом примере мы увидим, как мы собирается сохранить Лигу справедливости с парой супергероев;
package com.test; import java.util.ArrayList; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.justice.league.domain.JusticeLeague; import com.justice.league.domain.SuperHero; import com.justice.league.service.JusticeLeagureService; public class TestSpring { /** * @param args */ public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "spring-context.xml"); JusticeLeagureService service = (JusticeLeagureService) ctx .getBean("justiceLeagueService"); JusticeLeague league = new JusticeLeague(); List<SuperHero> superHeroList = getSuperHeroList(); league.setSuperHeroList(superHeroList); league.setJusticeLeagueMoto("Guardians of the Galaxy"); league.setNumberOfMembers(superHeroList.size()); service.handleJusticeLeagureCreateUpdate(league); } private static List<SuperHero> getSuperHeroList() { List<SuperHero> superHeroList = new ArrayList<SuperHero>(); SuperHero superMan = new SuperHero(); superMan.setAwesome(true); superMan.setName("Clark Kent"); superMan.setPowerDescription("Faster than a speeding bullet"); superHeroList.add(superMan); SuperHero batMan = new SuperHero(); batMan.setAwesome(true); batMan.setName("Bruce Wayne"); batMan.setPowerDescription("I just have some cool gadgets"); superHeroList.add(batMan); return superHeroList; } }
И если мы пойдем в базу данных и проверим это, мы увидим следующий результат;
mysql> select * from superhero; +---------------+-----------+-----------------+-------------------------------+ | super_hero_id | isAwesome | super_hero_name | power_description | +---------------+-----------+-----------------+-------------------------------+ | 1 | Y | Clark Kent | Faster than a speeding bullet | | 2 | Y | Bruce Wayne | I just have some cool gadgets | +---------------+-----------+-----------------+-------------------------------+ mysql> select * from justiceleague; +-------------------+-------------------------+-------------------+ | justice_league_id | justice_league_moto | number_of_members | +-------------------+-------------------------+-------------------+ | 1 | Guardians of the Galaxy | 2 | +-------------------+-------------------------+-------------------+
Итак, как вы можете видеть, мы сохранили двух супергероев и связали их с Лигой справедливости. Теперь давайте посмотрим, как это удаление orphan работает с примером ниже;
package com.test; import java.util.ArrayList; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.justice.league.domain.JusticeLeague; import com.justice.league.domain.SuperHero; import com.justice.league.service.JusticeLeagureService; public class TestSpring { /** * @param args */ public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "spring-context.xml"); JusticeLeagureService service = (JusticeLeagureService) ctx .getBean("justiceLeagueService"); JusticeLeague league = service.retrieveJusticeLeagueById(1l); List<SuperHero> superHeroList = league.getSuperHeroList(); /** * Here we remove Batman(a.k.a Bruce Wayne) out of the Justice League * cos he aint cool no more */ for (int i = 0; i < superHeroList.size(); i++) { SuperHero superHero = superHeroList.get(i); if (superHero.getName().equalsIgnoreCase("Bruce Wayne")) { superHeroList.remove(i); break; } } service.handleJusticeLeagureCreateUpdate(league); } }
Здесь мы сначала получаем запись Лиги Справедливости по ее первичному ключу. Затем мы проходим цикл и удаляем Бэтмена из Лиги и снова вызываем метод createOrUpdate. Поскольку мы определили удаление сироты, любой Супергерой, которого нет в списке, который находится в базе данных, будет удален.
Опять же, если мы сделаем запрос к базе данных, мы увидим, что Бэтмен был удален сейчас согласно следующему;
mysql> select * from superhero; +---------------+-----------+-----------------+-------------------------------+ | super_hero_id | isAwesome | super_hero_name | power_description | +---------------+-----------+-----------------+-------------------------------+ | 1 | Y | Clark Kent | Faster than a speeding bullet | +---------------+-----------+-----------------+-------------------------------+
Итак, это все. История о том, как Лига Справедливости использовала Hibernate для автоматического удаления Бэтмена, не пытаясь сделать это самостоятельно.
Далее рассмотрим, как Captain America использовала Критерии гибернации для создания гибких запросов с целью обнаружения возможных врагов. Осторожно!!!!
Всем хорошего дня и спасибо за чтение !!!!
Если у вас есть какие-либо предложения или комментарии, пожалуйста, оставьте их.
От http://dinukaroshan.blogspot.com/2011/09/hibernate-by-example-part-1-orphan.html