Статьи

Спящий режим на примере — часть 1 (удаление сирот)

Поэтому я подумал сделать серию примеров гибернации, показывающих различные функции гибернации. В первой части я хотел показать, как удалить функцию «Сирота» и как ее можно использовать с сюжетной линией. Итак, давайте начнем 🙂

Предварительные условия :
Для того, чтобы попробовать следующий пример, вам понадобятся следующие 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