`
kylinsoong
  • 浏览: 240093 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Hibernate OneToMany 单向和双向配置对数据存取性能的比较

阅读更多

1. 开篇说明:今天是春节长假的最后一天,春节过后博客将继续,这篇博客主要用来总结年前的研究结果,研究的主要Hibernate OneToMany 单向和双向配置对数据存取性能的问题。本文按照我测试实验的过程,最后得出结论。

 

2. 本文实验是基于之前博客EJB 学习阶段总结:JBoss下发布一个Toy企业应用,在此工程基础上,在实体中添加一对独立的一对多关系如下图:

 如上图Man和Lover是一对多关系,一个Man可以有多个Lover,为了简单我们设定Man和Lover都只有Id和name属性,我们在com.home.po中添加Entity Man和Lover的代码如下:

@Entity(name="Man")
@Table(name="k_man")
public class Man {

	private Long id;	
	private String name;
	private List<Lover> lovers;
	
	@Column
	@Id
	@GeneratedValue
	public Long getId() {
		return id;
	}
	
	public void setId(Long id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public List<Lover> getLovers() {
		return lovers;
	}
	
	public void setLovers(List<Lover> lovers) {
		this.lovers = lovers;
	}
}

 

@Entity(name="Lover")
@Table(name="k_lover")
public class Lover {

	private Long id;
	private String name;
	
	@Column
	@Id
	@GeneratedValue
	public Long getId() {
		return id;
	}
	
	public void setId(Long id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
}

 我要做的测试是像数据库中插入Man和Man对应的Lover,我们通过一个独立的EJB来完成,EJB中SessionBean和接口代码如下:

public interface ManService {
	public void insertManListUni(Integer num, Integer loverNum);
	public void insertManListDul(Integer num, Integer loverNum);
}

 

@Stateless
@Remote(ManService.class)
public class ManServiceSession implements ManService {

	@PersistenceContext(unitName="com.home.po") 
	protected EntityManager em;
	
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void insertManListUni(Integer num, Integer loverNum) {
		List<Lover> lovers = getLoverList(loverNum);
		for(int i = 0 ; i < num ; i ++) {
			
		}
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void insertManListDul(Integer num, Integer loverNum) {
		List<Lover> lovers = getLoverList(loverNum);
		for(int i = 0 ; i < num ; i ++) {
			
		}
	}
	
	public List<Lover> getLoverList(Integer loverNum) {
		List<Lover> lovers = new ArrayList<Lover>();
		for(int i = 0 ; i < loverNum ; i ++) {
			Lover l = new Lover();
			l.setName("kylin-test-lover-" + i);
			lovers.add(l);
		}
		return lovers;
	}

}

 

 

3 配置JBoss的日志文件,让其输出Hibernate数据库操作语句

Hibernate日志输出文件配置在JBoss_Home\server\production\conf下jboss-log4j.xml文件中,要输出Hibernate的SQL语句只需在jboss-log4j.xml的配置文件中添加Category和相应的Appender,如下:

<appender name="SWFILE" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.log.dir}/FFTrace.log"/>
      <param name="Encoding" value="UTF-8"/>
      <param name="Append" value="false"/>

      <param name="DatePattern" value="'.'yyyy-MM-dd"/>

      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
      </layout>
   </appender>

<category name="org.hibernate.SQL" additivity="false">
   		<priority value="debug"/>
		<appender-ref ref="SWFILE" />
   	</category>

 

 

4 一对多单向配置下插入一个Man查看日志

在Man中添加单向配置:

@OneToMany (
			targetEntity=com.home.po.Lover.class,
			fetch=FetchType.LAZY,
			cascade = { CascadeType.ALL })
	@Cascade( { org.hibernate.annotations.CascadeType.ALL } )  
	@ForeignKey(name="MAN_TO_LOVER_FK")
	@JoinColumn(name = "MAN_ID")
	public List<Lover> getLovers() {
		if(lovers == null) {
			lovers = new ArrayList<Lover>();
		}
		return lovers;
	}

修给ManServiceSession的insertManListUni方法如下:

public void insertManListUni(Integer num, Integer loverNum) {	
		for(int i = 0 ; i < num ; i ++) {
			List<Lover> lovers = getLoverList(loverNum);
			Man m = new Man();
			m.setName("kylin-test-man-" + i);
			em.persist(m);
			for(Lover l : lovers) {
				m.getLovers().add(l);
			}
		}
	}

插入一个Man一个Man对应两个Lover后 查看日志如下:

2011-02-08 15:31:58,562 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 15:31:58,750 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 15:31:58,765 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 15:31:58,781 DEBUG [org.hibernate.SQL] insert into k_man (name, id) values (?, ?)
2011-02-08 15:31:58,781 DEBUG [org.hibernate.SQL] insert into k_lover (name, id) values (?, ?)
2011-02-08 15:31:58,781 DEBUG [org.hibernate.SQL] insert into k_lover (name, id) values (?, ?)
2011-02-08 15:31:58,781 DEBUG [org.hibernate.SQL] update k_lover set MAN_ID=? where id=?
2011-02-08 15:31:58,781 DEBUG [org.hibernate.SQL] update k_lover set MAN_ID=? where id=?

如上是插入一个Man,一个Man对应两个Lover,SQL语句统计如下:

3 select语句,1 insert Man语句,2 insert lover语句, 2 update lover语句,总共:8 SQL语句

依次推断得出计算SQL语句公式:假设插入Man的个数用 m表示,一个Man对应的Lover个数用 l表示,SQL总数用s表示:给出公式:S=(m + m*n)*2 + m*n,用此公式

插入1个Man,一个Man对应2个Lover SQL总数:(1+1*2)*2+1*2 =8
插入100个Man,一个Man对应1000个Lover SQL总数:(100+100*1000)*2+100*1000=300200

插入100个Man,一个Man对应1000个Lover 3次,记录操作时间如下:

 即完成插入100个Man,一个Man对应1000个Lover 需要时间大概是110秒

 

5 一对多双向下插入Man及对应的Lover查看日志

修改实体类

Man实体如下:

@OneToMany (
			targetEntity=com.home.po.Lover.class,
			fetch=FetchType.LAZY,
			cascade = { CascadeType.ALL },
			mappedBy = "man")
	@Cascade( { org.hibernate.annotations.CascadeType.ALL } )  
	@ForeignKey(name="MAN_TO_LOVER_FK")
	public List<Lover> getLovers() {
		if(lovers == null) {
			lovers = new ArrayList<Lover>();
		}
		return lovers;
	}

Lover实体添加Man属性如下:

private Man man;
	
	@ManyToOne
	public Man getMan() {
		return man;
	}

	public void setMan(Man man) {
		this.man = man;
	}

 修给ManServiceSession的insertManListDul方法如下

public void insertManListDul(Integer num, Integer loverNum) {
		for(int i = 0 ; i < num ; i ++) {
			List<Lover> lovers = getLoverList(loverNum);
			Man m = new Man();
			m.setName("kylin-test-man-" + i);
			em.persist(m);
			for(Lover l : lovers) {
				l.setMan(m);
				em.persist(l);
			}
		}
	}

 同样插入一个Man一个Man对应两个Lover后 查看日志如下:

2011-02-08 16:40:11,859 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 16:40:12,031 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 16:40:12,031 DEBUG [org.hibernate.SQL] select hibernate_sequence.nextval from dual
2011-02-08 16:40:12,046 DEBUG [org.hibernate.SQL] insert into k_man (name, id) values (?, ?)
2011-02-08 16:40:12,062 DEBUG [org.hibernate.SQL] insert into k_lover (man_id, name, id) values (?, ?, ?)
2011-02-08 16:40:12,062 DEBUG [org.hibernate.SQL] insert into k_lover (man_id, name, id) values (?, ?, ?) 

3 select语句,1 insert Man语句,2 insert lover语句, 总共:6 SQL语句

依次推断得出计算SQL语句公式:假设插入Man的个数用 m表示,一个Man对应的Lover个数用 l表示,SQL总数用s表示:给出公式:S=(m + m*n)*2 ,用此公式

插入1个Man,一个Man对应2个Lover SQL总数:(1+1*2)*2=6
插入100个Man,一个Man对应1000个Lover SQL总数:(100+100*1000)*2=200200

插入100个Man,一个Man对应1000个Lover 3次,记录操作时间如下:


  即完成插入100个Man,一个Man对应1000个Lover 需要时间大概是90秒

 

6 结论:比较步骤4和步骤5,可以看到同样是插入100个Man,一个Man对应1000个Lover 用双向配置节约了20秒时间,即结论:一对多关系一般推荐使用双向配置

  • 大小: 1.9 KB
  • 大小: 5.3 KB
  • 大小: 5.1 KB
0
0
分享到:
评论
1 楼 mojunbin 2012-05-30  
呵呵..好.

相关推荐

    HIBERNATE 一对多 onetomany

    在Java持久化框架Hibernate中,"一对一"(one-to-one)和"一对多"(one-to-many)是两种常见的关联关系映射。本教程将详细讲解如何在Hibernate中实现"一对多"关联,并通过实际例子加深理解。 首先,让我们了解什么...

    hibernate一对多关联映射(单向关联)

    这篇博客文章“hibernate一对多关联映射(单向关联)”将深入讲解如何配置和使用这种映射关系。 在单向关联中,只有一个实体知道另一个实体的存在,也就是说,只有父实体("一"的一端)有对子实体("多"的一端)的...

    Hibernate-单向关系Hibernate-单向关系

    在Java的持久化框架Hibernate中,单向关系是一种常见的实体...总结,理解并合理运用Hibernate的单向关系对于优化数据库设计和提高应用程序性能至关重要。在实际开发中,应根据业务需求和性能考虑来选择合适的关联类型。

    Hibernate ORM - 一对多双向关联关系

    描述部分为空,但我们可以根据标题推测,这篇博客可能详细解释了如何在Hibernate中配置和管理这种一对多双向关联,包括XML配置、注解方式,以及如何在代码中进行操作和查询。 **Hibernate ORM简介** Hibernate是一...

    hibernate多对多双向关联

    总结来说,理解并能正确使用Hibernate中的多对多双向关联是Java开发中的重要技能,涉及到实体设计、映射配置、数据操作和性能优化等多个方面。通过学习提供的博客和相关代码示例,开发者可以深入掌握这一主题,并将...

    hibernate单向一对多关联映射(注解版)

    在Java的持久化框架Hibernate中,单向一对多关联映射是常见的数据关系处理方式,尤其是在处理数据库中的实体类和表之间的关系时。本主题主要关注如何使用注解来实现这种映射。Hibernate通过注解使得对象关系映射...

    Hibernate双向一对多经典实例

    **标题:“Hibernate双向一对多经典实例”** 在Java开发中,Hibernate是一个强大的对象关系映射(ORM)框架,它简化了数据库操作,使得开发者能够用面向对象的方式处理数据。本实例将聚焦于Hibernate中的一对多关系...

    hibernate03:多对一单向关联、多对一双向关联

    本文主要探讨的是Hibernate中的两种关联关系:多对一单向关联和多对一双向关联。通过理解这两种关联方式,我们可以更好地设计和实现复杂的数据库模型。 首先,我们来看**多对一单向关联**。这种关联意味着一个实体...

    一对多单向和双向映射

    本篇将详细探讨"一对多单向和双向映射"这一主题,结合标签中的"源码"和"工具",我们将深入理解这些概念,并可能涉及到具体的代码实现。 首先,映射是ORM框架的核心,它允许开发者将数据库表与Java类之间的关系进行...

    hibernate一对多,多对一,一对多双向关联

    1. **关联类型:** Hibernate支持四种基本的关联类型,包括一对一(OneToOne)、一对多(OneToMany)、多对一(ManyToOne)和多对多(ManyToMany)。本主题将主要聚焦在一对一和一对多关联。 2. **关联的方向性:**...

    hibernate双向一对多关联映射(注解版)

    在Java的持久化框架Hibernate中,双向一对...理解并正确实现双向一对多关联映射对于优化数据访问性能和简化代码结构至关重要。在实际项目中,根据业务需求选择合适的映射策略和级联类型,可以有效提高程序的运行效率。

    Hibernate双向一对多

    通过这个项目,学习者可以深入理解Hibernate双向一对多关系的配置、使用及其实现细节,从而提升数据库操作和对象持久化的技能。实践中遇到的问题和解决方法也会帮助巩固理论知识,提升实际开发能力。

    onetomany-hibernate

    需要注意的是,由于一对多关系可能会导致数据冗余,因此在设计数据库和业务逻辑时要考虑到性能和数据一致性的问题。 总的来说,"onetomany-hibernate"涉及的关键知识点包括: 1. Hibernate框架的基本概念和工作...

    Hibernate 系列教程 单向一对多

    理解并熟练掌握Hibernate的单向一对多关联,能够帮助开发者更高效地处理复杂的数据库操作,减少不必要的数据库交互,提高应用程序的性能。在实际项目中,应根据业务需求灵活选择关联类型,并合理优化查询策略,以...

    Hibernate ORM - 一对多双向连接表关联关系

    9. **最佳实践**:在实际应用中,应考虑数据量、性能需求和业务逻辑来选择合适的一对多双向关联实现方式,避免过度设计或性能瓶颈。 10. **示例代码**:通常会包含创建实体类、配置关联、进行CRUD操作的代码示例,...

    Hibernate Annotation 基于外键的一对多双向关联

    在实现基于外键的一对多双向关联时,理解注解的含义和作用至关重要,同时还需要考虑性能优化和潜在的问题,确保数据的正确性和一致性。通过阅读源码和实践,我们可以更深入地掌握Hibernate的内在机制。

    JAVA数据类型与Hibernate的类型映射

    在实际应用中,Hibernate还提供了一些高级映射机制,如一对一(OneToOne)、一对多(OneToMany)、多对一(ManyToOne)和多对多(ManyToMany)的关系映射。这些映射通过@OneToOne、@OneToMany、@ManyToOne和@...

    Hibernate基于外键的一对多单向关联

    **标题解析:** ...总之,理解并正确配置Hibernate的一对多单向关联,可以帮助我们更高效地进行数据库操作,提高代码的可读性和维护性。实际操作时,应结合具体业务场景和性能需求进行合理设计和优化。

Global site tag (gtag.js) - Google Analytics