Предпосылки :
Чтобы опробовать следующий пример, вам понадобятся следующие 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"?> 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/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 создавать таблицы для вас.
Итак, теперь, когда мы увидели строительные блоки приложения, давайте посмотрим, как все это работает, сначала создав несколько супергероев в рамках Лиги справедливости.
Простой основной класс, чтобы показать, как все это работает:
В качестве первого примера давайте посмотрим, как мы собираемся сохранить Лигу справедливости с парой супергероев;
|
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
- Hibernate Gotchas, чтобы остерегаться
- Команды Hibernate autocommit заставляют MySQL чрезмерно использовать дисковый ввод-вывод
- DataNucleus 3.0 против Hibernate 3.5
- Проблемы с производительностью сопоставленных коллекций Hibernate
- Образец приложения Spring MVC3 Hibernate CRUD
- Список учебных пособий по Java и Android
