先决条件 :
为了尝试以下示例,您将需要以下提到的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
- commons-logging-1.0.4.jar
- log4j.jar
- aopalliance-1.0.jar
- dom4j-1.1.jar
- hibernate-commons-annotations-3.2.0.Final.jar
- hibernate-core-3.6.4.Final.jar
- hibernate-jpa-2.0-api-1.0.0.Final.jar
- javax.persistence-2.0.0.jar
- jta-1.1.jar
- javassist-3.1.jar
- slf4j-api-1.6.2.jar
- mysql-connector-java-5.1.13-bin.jar
- commons-collections-3.0.jar
对于希望eclipse项目进行尝试的任何人,您都可以在此处下载带有上述JAR依赖项的文件。
简介 :
成立于2011年。正义联盟(Justice League)的规模过大,正在寻找开发商来帮助创建超级英雄注册系统。 熟悉Hibernate和ORM的开发人员已准备好使用Hibernate来完成系统和处理持久层的工作。 为简单起见,他将使用一个简单的独立应用程序来保留超级英雄。 这是此示例的布局方式:
- 桌子设计
- 域类和Hibernate映射
- DAO和服务类
- 应用程序的Spring配置
- 一个简单的主类,展示所有工作原理
让旅程开始……………………。
表格设计:
设计由三个简单的表格组成,如下图所示;
如您所见,它是一个简单的一对多关系,由联接表链接。 Hibernate将使用Join Table来填充域类中的Super hero列表,我们将在下一步继续查看。
域类和Hibernate映射:
与主要拥有实体(正义联盟实体)链接的联接表主要只有两个域类。 因此,让我们继续看看如何使用注释构造域类。
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字段的最后一个变量。
我们在数据库字段中使用Hibernate的@Type批注将true&false表示为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处理孤立记录的删除。
现在我们有了Domain类
DAO和服务类:
为了保持良好的设计标准,我将DAO(数据访问对象)层和服务层分开。 因此,让我们看一下DAO的界面和实现。 请注意,我有
通过HibernateDAOSupport使用了HibernateTemplate ,从而避免了任何特定于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知道这是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称为ID为JusticeLeagueService的bean 。
并且我们已经自动连接了JusticeLeagueDAO并定义了一个@Qualifier,以便它将绑定到Hibernate实现。
Qualifier的值应与我们在DAO Implementation类中为类级别Qualifier赋予的名称相同。
最后,让我们看一下将所有这些连接在一起的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事务管理器。
为了简化起见,我还使用了由hibernate自动创建表的方法。 packagesToScan属性指示扫描根包com.justice.league。**。*下的所有子包(包括嵌套在其中的嵌套包)为
扫描@Entity注释的类。
我们还将会话工厂限制在了JusticeLeagueDAO上,以便我们可以使用Hibernate Template。
为了进行测试,您可以根据需要最初使用标签<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 |
+-------------------+-------------------------+-------------------+
如您所见,我们坚持了两位超级英雄,并将他们与正义联盟联系在一起。 现在,让我们看看下面的示例如何删除孤儿。
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 |
+---------------+-----------+-----------------+-------------------------------+
就是这样了。 正义联盟(Justice League)如何使用休眠模式自动删除蝙蝠侠而无需费心自己做的故事。
接下来,我们将期待美国队长如何使用休眠标准来构建灵活的查询,以便找到可能的敌人。 小心!!!!
祝大家有美好的一天,并感谢您的阅读!
如果您有任何建议或意见,请不要理会。
参考:“ 通过示例进行休眠–第1部分(除去孤儿)”,来自我们的JCG合作伙伴 Dinuka Arseculeratne,在“ My Journey Through IT”博客中
翻译自: https://www.javacodegeeks.com/2011/11/hibernate-by-example-part-1-orphan.html