- 浏览: 236130 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
akka_li:
学习了!但是为什么后续的没有了?!
EJB4:RMI和RMI-IIOP -
springaop_springmvc:
apache lucene开源框架demo使用实例教程源代码下 ...
Lucene学习笔记(一)Lucene入门实例 -
qepipnu:
求solr 客户端 jar包
Solr学习笔记(三)Solr客户端开发实例 -
zhangbc:
是这问题,赞!
Oracle Start Up 2 Oracle 框架构件、启动、解决一个问题 -
feilian09:
查询 select hibernate jdbc 那个效率快
Hibernate,JDBC性能探讨
2. 如何由PoJo类生成数据库中的表
首先可以根据实体间关系及对应关系设计表,写出相应建表SQL语句,执行生成表,或者可以用hibernate映射来生成表,在http://kylinsoong.iteye.com/admin/blogs/739502一开始说明怎样通过hibernate mapping生成表;
我们例子生成表如下图所示:
共生成11张表,7个实体对应7张表及5个一对多关联表(User和Event,User和Friend,Event和Property,Wife和Pet,Pet和Property)。
3. FetchType Lazy及Eager测试
一对一下FetchType Lazy
设定User和UserCard,Friend和UserCard,Wife和UserCard对应FetchType 设为lazy,User和Wife设为Eager,运行如下代码;
public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = em.find(User.class, new Long(1)); System.out.println(user.getFriends().get(0).getUserCard().getClass()); System.out.println(user.getUserCard().getClass()); System.out.println(user.getWife().getClass()); System.out.println(user.getWife().getUserCard().getClass()); t.commit(); em.close(); emf.close(); }
运行结果:
class com.tibco.hibernate.po.UserCard_$$_javassist_0 class com.tibco.hibernate.po.UserCard_$$_javassist_0 class com.tibco.hibernate.po.Wife class com.tibco.hibernate.po.UserCard_$$_javassist_0
从结果可以看到一对一下FetchType 设为Lazy,对应熟悉值为该属性的代理,当然设为Eager后就不为代理,下面代码通过反射对代理类进行研究
public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = em.find(User.class, new Long(1)); showProxyClass(user.getUserCard()); t.commit(); em.close(); emf.close(); } private static void showProxyClass(Object bean) throws Throwable { PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { System.out.println(propertyDescriptor.getDisplayName() + " " + propertyDescriptor.getReadMethod()); } }
运行结果:
cardNumber public final java.lang.String com.tibco.hibernate.po.UserCard_$$_javassist_0.getCardNumber() class public final native java.lang.Class java.lang.Object.getClass() handler null hibernateLazyInitializer public final org.hibernate.proxy.LazyInitializer com.tibco.hibernate.po.UserCard_$$_javassist_0.getHibernateLazyInitializer() id public final java.lang.Long com.tibco.hibernate.po.UserCard_$$_javassist_0.getId()
可以看出除去CardNumber属性cardNumber ,id 外,又多出了handler和hibernateLazyInitializer属性,且cardNumber ,id 对应的Get方法不是getId()和getCardNumber(),而是UserCard_$$_javassist_0.getId()和UserCard_$$_javassist_0.getCardNumber(),是其代理类中的Get方法;继续研究.UserCard_$$_javassist_0类:
private static void showProxyClass(Object bean) throws Throwable { PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { if(propertyDescriptor.getDisplayName().compareTo("hibernateLazyInitializer")== 0) { Class c = Class.forName("com.tibco.hibernate.po.UserCard_$$_javassist_0"); for(Class cl :c.getInterfaces()) { System.out.println(cl); } for(Method m : c.getMethods()) { if(m.getName().startsWith("get")){ System.out.println(m.getName()); } } Object obj = propertyDescriptor.getReadMethod().invoke(bean, new Object[]{}); System.out.println(obj.getClass()); } } }
运行结果:
interface org.hibernate.proxy.HibernateProxy interface javassist.util.proxy.ProxyObject getHibernateLazyInitializer getCardNumber getId getClass class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer
看到UserCard_$$_javassist_0实现了两个接口getHibernateLazyInitializer()方法可以获取
一对多下FetchType Lazy
User和Event,Event和Property,Wife和Pet,Pet和Property FetchType为Lazy,User和Friend FetchType为Eager,运行如下代码
public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = em.find(User.class, new Long(1)); System.out.println(user.getEvents().getClass()); System.out.println(user.getFriends().getClass()); System.out.println(user.getEvents().get(0).getProperties().getClass()); System.out.println(user.getWife().getPets().getClass()); System.out.println(user.getWife().getPets().get(0).getProperties().getClass()); t.commit(); em.close(); emf.close(); }
运行结果:
class org.hibernate.collection.PersistentBag class org.hibernate.collection.PersistentBag class org.hibernate.collection.PersistentBag class org.hibernate.collection.PersistentBag class org.hibernate.collection.PersistentBag
发现一对多和一对一以Lazy的处理方式是不一样的。
说明一个常见错误:
上述例子中总共有User和Event,User和Friend,Event和Property,Wife和Pet,Pet和Property 5对一对多关系,已经将User和Friend FetchType为Eager,此时在将剩余4对其中任何一项设为Eager,运行程序,会出现“Unable to build EntityManagerFactory”错误,错误的根本原因是“cannot simultaneously fetch multiple bags”
如下所示错误堆栈的打印输出:
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: com.tibco.hibernate.po] Unable to build EntityManagerFactory at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:677) at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:126) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:52) at com.tibco.hibernate.jpa.JPAUtil.createEMF(JPAUtil.java:20) at com.tibco.hibernate.jpa.JPAClient.main(JPAClient.java:26) Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:94) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:98) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:66) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:56) at org.hibernate.loader.entity.BatchingEntityLoader.createBatchingEntityLoader(BatchingEntityLoader.java:126) at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:1765) at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:1769) at org.hibernate.persister.entity.AbstractEntityPersister.createLoaders(AbstractEntityPersister.java:3002) at org.hibernate.persister.entity.AbstractEntityPersister.postInstantiate(AbstractEntityPersister.java:2995) at org.hibernate.persister.entity.SingleTableEntityPersister.postInstantiate(SingleTableEntityPersister.java:712) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:329) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1341) at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867) at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669) ... 4 more
错误的原因是:如果一个实体里要映射多个集合实体时,我们不能把两个集合的的FetchType设置为EAGER,此时只能设置为LAZY,否则会报:cannot simultaneously fetch multiple bags。
解决办法:将一个FetchType设置为Lazy
4 Lazy和Eager的主要区别在于效率,当效率要求高时必须用Lazy,但有些时候既要要求高效率(Lazy),但相应Lazy标记的属性不要是相关的代理,这时就需要把相关属性代理转换成原属性,下面是一个实现这个功能的类,主要思想是Java反射:
import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * * @author Kylin Soong * */ public class POPropertyUtil { public static Object setBeanProperty(Object bean) throws Throwable { PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { if(propertyDescriptor.getReadMethod() == null) { continue; } Object obj = propertyDescriptor.getReadMethod().invoke(bean, new Object[]{}); if(obj == null) { continue; } if(obj.getClass().getPackage().getName().compareTo("com.staffware.frameworks.po") == 0) { setBeanProperty(obj); } if(obj instanceof List) { List lists = (List) obj; for(Object o : lists) { setBeanProperty(o); } } if(isProxyProperty(obj)) { if(propertyDescriptor.getWriteMethod() != null) { Object invokeObj = clone(obj, propertyDescriptor); propertyDescriptor.getWriteMethod().invoke(bean, new Object[]{invokeObj}); } else { throw new RuntimeException(propertyDescriptor.getDisplayName() + "has a null getWriteMethod"); } } } return bean; } private static Object clone(Object obj, PropertyDescriptor propertyDescriptor) throws Throwable { if(obj instanceof List) { List lists = (List) obj; List newList = new ArrayList(); for(Object o : lists) { newList.add(o); } return newList; } else { Object newObj = propertyDescriptor.getPropertyType().newInstance(); return replication(newObj, obj); } } private static void invokeCollectionEntity(Object o) throws Throwable { PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { if(propertyDescriptor.getReadMethod() != null) { propertyDescriptor.getReadMethod().invoke(o, new Object[]{}); } } } private static Object replication(Object newObj, Object oldObj) throws Throwable { PropertyDescriptor[] newPropertyDescriptors = Introspector.getBeanInfo(newObj.getClass()).getPropertyDescriptors(); PropertyDescriptor[] oldPropertyDescriptors = Introspector.getBeanInfo(oldObj.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : newPropertyDescriptors) { if(propertyDescriptor.getWriteMethod() != null) { Method readMethod = getReadMethod(propertyDescriptor.getDisplayName(), oldPropertyDescriptors); propertyDescriptor.getWriteMethod().invoke(newObj, new Object[]{readMethod.invoke(oldObj, new Object[]{})}); } } return newObj; } private static Method getReadMethod(String displayName, PropertyDescriptor[] oldPropertyDescriptors) { for(PropertyDescriptor propertyDescriptor : oldPropertyDescriptors) { if(propertyDescriptor.getDisplayName().compareTo(displayName) == 0) { if(propertyDescriptor.getReadMethod() == null){ throw new RuntimeException("Get Read method return a null value: " + propertyDescriptor.getPropertyType() + " " + propertyDescriptor.getDisplayName()); } return propertyDescriptor.getReadMethod(); } } throw new RuntimeException("can not find read method in:" + oldPropertyDescriptors); } private static boolean isProxyProperty(Object obj) throws Throwable { String name = obj.getClass().getName(); return name.contains("_$$_javassist_") || name.contains("org.hibernate.collection.PersistentBag"); } }
对上述类进行测试,如下代码:
public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = em.find(User.class, new Long(1)); System.out.println(user.getEvents().getClass()); System.out.println(user.getUserCard().getClass()); System.out.println(user.getWife().getClass()); POPropertyUtil.setBeanProperty(user); System.out.println(user.getEvents().getClass()); System.out.println(user.getUserCard().getClass()); System.out.println(user.getWife().getClass()); // t.commit(); em.close(); emf.close(); }
运行结果:
class org.hibernate.collection.PersistentBag class com.tibco.hibernate.po.UserCard_$$_javassist_0 class com.tibco.hibernate.po.Wife_$$_javassist_3 class java.util.ArrayList class com.tibco.hibernate.po.UserCard class com.tibco.hibernate.po.Wife
既将相应的代理还原了;
5 说明一个常见的错误:“detached entity passed to persist”,先还原错误:
如上在获取User对象后给其设定ID值,然后保存如下代码
public static void main(String[] args) throws Throwable { EntityManagerFactory emf = JPAUtil.createEMF("oracle"); EntityManager em = emf.createEntityManager(); EntityTransaction t = em.getTransaction(); t.begin(); User user = JPAClient.getUser(); user.setId(new Long(1212)); em.persist(user); t.commit(); em.close(); emf.close(); }
运行代码抛出异常,异常堆栈信息如下:
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.tibco.hibernate.po.User at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614) at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:226) at com.tibco.hibernate.jpa.JPAClient.main(JPAClient.java:33) Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.tibco.hibernate.po.User at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102) at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:646) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:620) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:624) at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
错误原因是:实体的状态变化EntityManager是根据实体的ID来判断,一般一个实体Persist的过程就是给他分配一个ID的过程,当一个实体有唯一ID时,EntityManager就认为它已经处于游离(detached )状态,而游离态实例不能够持久化
发表评论
-
Oracle - Add Exist Validation Before Create Table
2011-11-07 13:49 1404Usually we need to check the ta ... -
JMX Architecture & "Hello Word" the JMX way
2011-10-25 20:07 1746JMX Architecture Overview: JMX ... -
Jboss-eap-5.1 Messaging
2011-08-02 21:50 2400This section I will concertate ... -
Jboss-eap-5.1 starting up note
2011-07-26 22:46 2543Jboss enterprise platform 5 hav ... -
EJB Security & JAAS Demo
2011-05-21 19:39 1575PROLOGUE: When deploying ... -
JBoss LoginInitialContext Factory Implementation
2011-05-15 16:05 1466Jboss has a series of imp ... -
Jboss Reference Exception Gallery
2011-04-27 14:08 28491. Unable to locate a login con ... -
Hibernate Annotation 的一个问题,给点意见
2011-03-10 12:43 22问题:org.hibernate.annotations. ... -
大家说说BBC的网站用的是什么技术做的
2011-02-22 05:01 1394最近在英国出差,发现这里的一些网站做的相当有特色,有些网站不是 ... -
Hibernate OneToMany 单向和双向配置对数据存取性能的比较
2011-02-08 17:06 22421. 开篇说明:今天是春 ... -
对Hibernate属性(CascadeType、JoinColumn、JoinTable、ForeignKey等)的研究
2010-12-26 15:45 16604本文列出几个“EJB 学习阶段总结:JBoss下发布一个Toy ... -
EJB 学习阶段总结:JBoss下发布一个Toy企业应用
2010-12-25 12:11 2548解释题目:为什 ... -
EJB7: Message Driven Bean
2010-12-21 22:42 2098在企业系统中需要使用 ... -
EJB6: EntityBean例子
2010-11-26 14:48 1441本例子描述向EJB容器(JBoss)部署http: ... -
JPA dev: 几个问题总结
2010-11-25 16:56 3350最近工作中遇到几个与JPA相关的问题,本文通过一个例子总结一下 ... -
JAXB学习
2010-11-24 22:35 01 什么是JAXB? JAXB全称Java Ar ... -
EJB5: JPA扩展-J2SE环境下使用EntityManager
2010-11-10 19:07 2641好久没有写博客了,最近比较忙,今天抽时间写点,最近 ... -
EJB4:RMI和RMI-IIOP
2010-11-02 21:14 4066计划提纲:引入→RMI概念→RMI HelloWorld程序→ ... -
EJB3: JBOSS 企业版、JBOSS服务器构架、EJB2.0 HelloWrold实例
2010-10-26 22:43 6414本文的研究基于jboss-eap- ... -
jboss-eap-4.3 启动停止在Configuring from URL: resource:jboss-log4j.xml 问题
2010-10-25 14:49 4006如题,我改用jboss-eap-4.3, 启动时停止在Conf ...
相关推荐
eladmin jpa版本:前端源码,项目基于 Spring Boot 2.1.0 、 Spring Boot Jp
管理系统系列--eladmin jpa 版本:项目基于 Spring Boot 2.6.4、 Jpa、 Spring
用SpringBoot + Spring Data JPA操作数据库 项目启动的时候 报了一个错 SpringBoot的版本是2.2.6.RELEASE org.springframework.beans.factory.BeanCreationException: Error creating bean with name '...
NULL 博文链接:https://wsc830719.iteye.com/blog/517167
Maven坐标:org.springframework.data:spring-data-jpa:2.0.9.RELEASE; 标签:springframework、data、spring、jpa、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,...
JpaRepository:belajar menggunakan JPA存储库
JPA研究:有关JPA的一些测试和研究
Jpa.doc
JPA Console是一个Eclipse插件,它允许执行JPQL和Criteria的JPA查询。
第一章:Spring Data JPA入门 包括:是什么、能干什么、有什么、HelloWorld等 第二章:JpaRepository基本功能 包括:代码示例JpaRepository提供的CRUD功能,还有翻页、排序等功能 第三章:JpaRepository的查询 ...
jpa入门案例:单表查询,包括分页查询 使用springboot来整合实现
Apress Pro JPA2 Mastering the Java Persistence API
spring-data-jpa知识。
1:JPA: : 2:对象数据库: ://www.objectdb.com/ 3:JPA 性能基准: ://www.jpab.org/All/All/All.html 支持功能 支持所有蓝图功能, 除外 支撑 支持 支持 Java 5、6 或 7 支持 JPA 你需要哪一个取决于你想用...
JPA核心知识总结 详解 spring JPA
JPA规范实现,用JPA来解决可移植问题
JPA示例 样例Spring Boot API服务器 依存关系 SpringData JPA 弹簧靴 LomBook Spring网 H2数据库 Spring安全
这是JPA网站的全部源代码,可以用作示例代码来确定我们处理项目的方式。 我们工作的所有网站都具有相同的质量,由于它们的特殊用法,可能或多或少配备了这些设备。 每个人都可以使用此源代码来限定我们的代码或用于...
'SpringDataJPA从入门到精通'分为12章 内容包括整体认识JPA、JPA基础查询方法、定义查询方法、注解式查询方法、@Entity实例里面常用注解详解、JpaRepository扩展详解、JPA的MVC扩展REST支持、DataSource的配置、乐观...