Статьи

Спящий режим на примере — часть 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, связанной с основным объектом-владельцем, который является объектом Лиги справедливости. Итак, давайте посмотрим, как классы доменов создаются с помощью аннотаций;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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, о которых вы можете прочитать здесь . В этом случае мы использовали этот тип.

Хорошо, теперь, когда у нас есть наш класс для представления Супергероев, давайте посмотрим, как выглядит наш класс доменов Лиги Справедливости, который отслеживает всех супер героев, которые пообещали преданность Лиге.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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 & Service:

Чтобы соответствовать хорошим стандартам проектирования, я разделил уровень DAO (объекта доступа к данным) и уровень обслуживания. Итак, давайте посмотрим интерфейс и реализацию DAO. Обратите внимание, что у меня есть
использовала HibernateTemplate через HibernateDAOSupport, чтобы исключить любые специфичные для Hibernate детали и получить доступ ко всему унифицированно с помощью Spring.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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. Но в реальном приложении у вас, вероятно, будут другие проверки, связанные с безопасностью процедуры и т. Д., Выполняемые на уровне обслуживания.

01
02
03
04
05
06
07
08
09
10
11
12
package com.justice.league.service;
  
import com.justice.league.domain.JusticeLeague;
  
public interface JusticeLeagureService {
  
 public void handleJusticeLeagureCreateUpdate(JusticeLeague justiceLeague);
  
 public JusticeLeague retrieveJusticeLeagueById(Long id);
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 для приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>
 xsi:schemaLocation=" 
  
  
 <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 создавать таблицы для вас.

Итак, теперь, когда мы увидели строительные блоки приложения, давайте посмотрим, как все это работает, сначала создав несколько супергероев в рамках Лиги справедливости.

Простой основной класс, чтобы показать, как все это работает:

В качестве первого примера давайте посмотрим, как мы собираемся сохранить Лигу справедливости с парой супергероев;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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;
 }
  
}

И если мы пойдем в базу данных и проверим это, мы увидим следующий результат;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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 работает с примером ниже;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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. Поскольку мы определили удаление сироты, любой Супергерой, которого нет в списке, который находится в базе данных, будет удален.

Опять же, если мы сделаем запрос к базе данных, мы увидим, что Бэтмен был удален сейчас согласно следующему;

1
2
3
4
5
6
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 использовала Критерии гибернации для создания гибких запросов с целью обнаружения возможных врагов. Осторожно!!!!

Всем хорошего дня и спасибо за чтение !!!!

Если у вас есть какие-либо предложения или комментарии, пожалуйста, оставьте их.

Ссылка: Hibernate на примере — часть 1 (удаление сирот) от нашего партнера по JCG Динуки Арурилератне в блоге My Journey By IT

Статьи по Теме :