Поэтому я подумал сделать серию примеров гибернации, показывающих различные функции гибернации. В первой части я хотел показать, как удалить функцию «Сирота» и как ее можно использовать с сюжетной линией. Итак, давайте начнем ?
Предварительные условия :
Для того, чтобы попробовать следующий пример, вам понадобятся следующие 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
