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

对Hibernate属性(CascadeType、JoinColumn、JoinTable、ForeignKey等)的研究

阅读更多

本文列出几个“EJB 学习阶段总结:JBoss下发布一个Toy企业应用”开发测试过程中遇到的几个问题。

1. Hibernate 懒加载有一定局限性:EJB远程调运时Hibernate懒加载Session失效

通过实例说明:给Entity类中添加Transformer类,Transformer与UserCard存在一对一的单向关联,如下:

@Entity(name="Transformer")
@Table(name="k_transformer")
public class Transformer implements Serializable{
	
	private Long id;
	private UserCard userCard;
	@Column
	@Id
	@GeneratedValue
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	@OneToOne(
		targetEntity = com.home.po.UserCard.class, 
    		fetch = FetchType.LAZY, 
    		cascade = { CascadeType.ALL })
    @Cascade( { org.hibernate.annotations.CascadeType.ALL } )    		
	@JoinColumn(name = "UserCard_id")
	@ForeignKey(name = "TRANSFORMER_TO_USERCARD_FK") 
	public UserCard getUserCard() {
		return userCard;
	}
	public void setUserCard(UserCard userCard) {
		this.userCard = userCard;
	}
}

注意OneToOne属性设定FetchType必须是LAZY,因为我们测试的是Hibernate懒加载

 添加一个HibernateTest Session Bean,如下:

public interface TransformerService {
	public void persist(Transformer t);
	public void analysis(Long id);
	public Transformer analysisRemote(Long id);
}

  

public interface TransformerServiceLocal extends TransformerService {
}

  

@Stateless
@Remote(TransformerService.class)
@Local(TransformerServiceLocal.class)
public class TransformerServiceSession implements TransformerServiceLocal {
	
	@PersistenceContext(unitName="com.home.po") 
	protected EntityManager em;

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void persist(Transformer t) {
		em.persist(t);
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void analysis(Long id) {
		Transformer t = em.find(Transformer.class, id);
		analysisEntity(t);
	}

	private void analysisEntity(Transformer t) {
		System.out.println(t.getUserCard());
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public Transformer analysisRemote(Long id) {
		return em.find(Transformer.class, id);
	}

}

 

在客户端先向数据库中插入一条数据,在运行如下代码段:

public void analysis() throws NamingException {
       ……
      TransformerService service = (TransformerService) ctx.lookup("home-test-all/TransformerServiceSession/remote");
        service.analysis(new Long(1));
        Transformer tra = service.analysisRemote(new Long(1));
        analysisEntityInRemote(tra);
}
	
private void analysisEntityInRemote(Transformer t) {
        System.out.println(t.getUserCard());
}

  注意上述加红倾斜的代码段描述的方法analysisEntity,analysisEntityInRemote作用都是相同的,取出Transformer中UserCard属性,但是运行结果却如下,TransformerServiceSession 中的analysisEntity运行良好,Jboss Console控制台打印输出如下信息:

 而Remote端Eclipse Console口抛出Session无效的异常:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:62)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:116)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:166)
	at com.home.po.UserCard_$$_javassist_0.toString(UserCard_$$_javassist_0.java)
	at java.lang.String.valueOf(Unknown Source)
	at java.io.PrintStream.println(Unknown Source)
	at com.home.ear.test.HibernateTestClient.analysisEntityInRemote(HibernateTestClient.java:41)
	at com.home.ear.test.HibernateTestClient.analysis(HibernateTestClient.java:37)
	at com.home.ear.test.HibernateTestClient.main(HibernateTestClient.java:47)

 具体原因,继续研究中……

2 hibernate.jdbc.batch_size与 hibernate.jdbc.fetch_size初始值大小对Hibernate工作效率的影响:

修改Persistence Entity EJB模块中persistence.xml中Properties属性可以改变hibernate.jdbc.batch_size与 hibernate.jdbc.fetch_size的值,我做了如下两组测试,如下:

如下一,改变hibernate.jdbc.batch_size的大小,插入1000条User连续三次,记录每次插入时间,并计算出三次平均时间:

 如下二改变Change hibernate.jdbc.fetch_size大小,从数据库中取出2000条和4000条数据,记录取出时间,如下:

 如上两组数据,可以得出结论,在这个应用中hibernate.jdbc.batch_size设置为20-30之间Hibernate工作效率最好;而hibernate.jdbc.fetch_size是值设置为40左右Hibernate的工作效率最好

 

3  比较@OneToMany下@JoinColumn和@JoinTable的差别(对性能的影响)

@JoinColumn不产生级联表,将一方的主键存放在另一方的表中,如下,为JoinColumn的Entity Bean配置

以User与Friend为例:

@OneToMany (
	targetEntity=com.home.po.Friend.class,
	fetch=FetchType.LAZY,
	cascade = { CascadeType.ALL })
	@Cascade( { org.hibernate.annotations.CascadeType.ALL } ) 
	@JoinColumn(name="userId")  
	@ForeignKey(name="USER_TO_FRIEND_FK")
public List<Friend> getFriends() {
		return friends;
}

 这种配置下 产生表如下图:



 @JoinTable产生级联表,将双方的主键存放在一张独立的表中,如下为@JoinTable的配置

	@OneToMany (
              targetEntity=com.home.po.Friend.class,
			fetch=FetchType.LAZY,
			cascade = { CascadeType.ALL })
	@Cascade( { org.hibernate.annotations.CascadeType.ALL } ) 
	@JoinTable(name="k_user_friend", 
			joinColumns = @JoinColumn(name = "USER_ID"), 
			inverseJoinColumns = @JoinColumn(name = "FRIEND_ID"))
	@ForeignKey(name = "k_user_friend_FK", 
			inverseName = "k_user_friend_FK_R")
	public List<Friend> getFriends() {
		return friends;
	}

 这种配置下 产生表如下图:



 

 如上用直线标出的5张表就是5对一对多关系产生的级联表,它里面存储两个表的主键。

这两种处理对数据的插入和存取有什么影响,就这一问题做如下测试:

      1  分别在两种配置下通过EJB向数据库中插入2000个User 5次,记录每次时间,求出平均时间;

      2  分别在两种配置下通过EJB从数据库中取出10000条数据5次,记录每次时间,求出平均时间;

结果如下两组图分别是JoinTable和JoinColumn下的测试数据



 

 从上图比较可以得出结论:

      1 JoinTable下操作数据库花费的时间要长于JolinColumn;

      2 JolinColumn下节省的时间约为JoinTable下的2.5%;

分析原因:JoinTable花费时间多的原因是JoinTable下生成的中间表,要存取数据时都要查询中间的级联表,所以花费时间多;

 

4 测试建立外键与不建立外键两种情况下对存取数据库的影响

如上面3中都是设置外键的情况下测试的,下面我们在JoinColumn下做一组不设置外键的测试,不设置外键Annotation相当简单就是在原来的基础上去掉@ForeignKey标记,如下

@OneToMany (
	targetEntity=com.home.po.Friend.class,
	fetch=FetchType.LAZY,
	cascade = { CascadeType.ALL })
	@Cascade( { org.hibernate.annotations.CascadeType.ALL } ) 
	@JoinColumn(name="userId")  
public List<Friend> getFriends() {
		return friends;
}

 为了对比我们假设两种情况,一是JolinColumn下配置ForeignKey,二是JolinColumn下不配置ForeignKey,在两种情况下做如下测试:

      1  分别在两种配置下通过EJB向数据库中插入2000个User 5次,记录每次时间,求出平均时间;

      2  分别在两种配置下通过EJB从数据库中取出10000条数据5次,记录每次时间,求出平均时间;

测试结果如下面两张表所示:



 

  从上面两组图我们可以得出如下结论:

      1 ForeignKey对数据库的存取影响比较大,特别是数据库的查询

      2 设置ForeignKey可以减少数据库存取的时间

      3 设置ForeignKey插入数据库节省的时间是不设置ForeignKey的5.5%,查询时则可以节省6.5%

 

--------------------------------------------------------------------------------------------------

说明:以上时间有一定局限性,只是在当前这种情况下测试的结果,不过可以当做参考。

  • 大小: 1.5 KB
  • 大小: 17.9 KB
  • 大小: 12 KB
  • 大小: 2.9 KB
  • 大小: 4.7 KB
  • 大小: 11.2 KB
  • 大小: 9.6 KB
  • 大小: 11.3 KB
2
0
分享到:
评论
1 楼 blacklab 2011-11-02  

相关推荐

    hibernate的_CascadeType属性说明

    hibernate的_CascadeType属性说明

    详解Hibernate cascade级联属性的CascadeType的用法

    详解Hibernate cascade级联属性的CascadeType的用法 cascade(级联) 级联在编写触发器时经常用到,触发器的作用是当 主控表信息改变时,用来保证其关联表中数据同步更新。若对触发器来修改或删除关联表相记录,必须...

    Hibernate注释大全收藏

    Hibernate 可以对类的属性或者方法进行注解。属性对应field类别,方法的 getXxx()对应property类别。 定义表 通过 @Table 为实体Bean指定对应数据库表,目录和schema的名字。 @Entity @Table(name="tbl_sky") ...

    Hibernate_Annotation关联映射

    通过联接表处理单向一对多关联是首选方式,这种关联通过@JoinTable批注进行描述 @Entity Public class Trainer{ @OneToMany @JoinTable( name = "TrainedMonkeys", jonColumns = {@JoinColumn(name = "trainer_id...

    Hibernate注解

    很奇怪),分别是CascadeType.PERSIST(级联新建),CascadeType.REMOVE(级联删除),CascadeType.REFRESH(级联刷新),CascadeType.MERGE(级联更新),CascadeType.ALL(全部四项) * 方法一 * 主表: ?@OneToOne...

    javax.persistence.jar

    javax.persistence.JoinTable.class javax.persistence.Lob.class javax.persistence.LockModeType.class javax.persistence.LockTimeoutException.class javax.persistence.ManyToMany.class javax.persistence....

    JPA例子(里面有一对一,一对多的例子)

    JPA的几个例子,一对一,一对多。 @ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY) @JoinColumn(name = "personid", unique = false, nullable = true, insertable = true, updatable = true) ...

    EJB3.0开发之多对多和一对一

    在前面的例子中,我们演示了一对多和多对一的例子,在本章将演示多对多和一对一的关系。 学生和老师就是多对多的关系。一个学生有多个老师,一个老师教多个学生。 学生和档案就是一对一的关系(不知道国外的学生有...

    Java_EE_Udemy39:级联和传播持久性和删除操作

    @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE }) @JoinColumn(name= "airplane_fk") private Airplane airplaneDetail; 现在,这可以使排期列表自动更新。 这也意味着,如果将飞行员添加到...

    CascadeView级联组件实现思路详解(分离思想和单链表)

    本文介绍自己最近做省市级联的类似的级联功能的实现思路,为了尽...CascadeType. PERSIST 级联持久化 ( 保存 ) 操作 CascadeType. MERGE 级联更新 ( 合并 ) 操作 CascadeType. REFRESH 级联刷新操作,只会查询获取操作

Global site tag (gtag.js) - Google Analytics