使用JPA的时候,如果A B两个实体间是一对多,多对一的关系,如果不在@OneToMany里加入mappedBy属性会导致自动生成一个多余的中间表。比如:
这样写会只成生成表A和表B,B中会有一个到表A的外键。但是如果不加mappedBy=”a”, 那么就会再生成一张A_B表。
有两个实体Order和Customer,一个用户可以有多个订单,一个订单属于一个用户,所以Customer与Order是一对多的关系,那么在Order实体里可以有一个到Customer的引用customer,同时在Customer里有一个Order实体的集合orders。如果在只是如下这样写:
那么系统可能会自动生成一张Customer_Order关联表,可是事实上我们不需要这样的表,因为通过 Select order from Order order where order.customer.id=:id, 就可以找到某个Customer的Orders,而不需要另建一张表。要想去掉这个自动生成的表,要这样写:
多出一个mappedBy和JoinColumn, 就是告诉JPA实现者,orders是通过order里的customer映射来的,每次查找orders通过Order里的customer联接。这样就不会生成Customer_Order关联表了
j2ee难用,其中一个原因是jndi不好用,明明已经配置好名字为dataSource的数据源,但是在部署JPA时,老是抛异常说找不到数据源。今天在用jboss时,终于又明白了一些。
原来j2ee中的组件是有它自己独自的环境的,位于java:/comp/env这个jndi目录下。每个组件不能访问另外一个组件的私有环境,实现组件各自独立。同时,又有一些jndi目录和名字是公共的,如java:/下的其它一些名字,还有一些是只能给本地访问的,还有一些是能够给远程访问的,这个就不说了。
如果一个组件想要获得另外一个组件,那么需要在它的部署描述符里说明,比如:
这里说这个组件需要依赖于一个叫java:/comp/env/jdbc/mydatasource的数据源。但是这个数据源又从哪里来呢??!!注意了!原来是要在部署时写另外一个特定于服务器种类的数据源映射文件,如下面的jboss示例:
上面这一段可能位于jboss-web.xml等jboss特定的部署描述符里。目的就是告诉jboss,把全局的java:DefaultDS映射到这个组件的java:/comp/env/jdbc/mydatasource。就是这一步,很时候之所以部署失败,找不到jndi都是因为少了这样一个映射导致的。
如果不想写上面的特定于服务器的部署描述符,我估计可以通过指定一个公共的jndi来解决,如下:
问题虽然解决了,可是突然觉得好恶心,搞得这么复杂有必要吗?!!j2ee果然不是为了做小项目来的。
实体类(Entity Class):需要被持久化的类。为了使一个类能够被持久化,这个类需要满足一系列的约束。
持久化提供者(Persistence Provider):能够将实体类持久化的持久化功能提供者,比如hibernate, JDO, Toplink等。
对实体类的配置,不依赖于具体的持久化提供者,也就是说,在实体类配置好后,更换持久化提供者,不需要修改实体类。也就是说JPA提供了一个标准,实现了实体类标准的类,可以被任何一个实现在持久化提供者标准的框架持久化。所以在用JPA做持久化时,程序员可以集中注意力在实体类的实现上,而不必太关心具体的持久化提供者。
一个能够被持久化的实体类,必须有两部分,一是需要被持久的类,二是对于这个类的持久化配置信息。实 体类必须满足以下约束:
典型的持久化类如下所示:
持久化提供者有两种方式访问实体类,一是直接访问实体的实例变量(field access),二是通过实例变量的访问器(JavaBean 模式 property access)。当用annoation来标注实体类时,如果标注在实例变量上,那么将通过实例变量直接访问,如果标注在访问器(getter)上,则通过访问器以JavaBean属性的方式访问。如果既有标注在实例变量上的,又有标注在访问器上的,那么持久化提供者的访问方式将不可知,这是我们应该避免的情况。如果在XML里对已经标注过的实体类进行配置,指定了一种不同于标注所指定的访问方式,那么持久化提供者的访问方式也是不可知的。
下面所示的实体类的访问方式将不可知,因为属性product的getter上,和其它实例变量上都有标注:
如果持久化提供者以实例变量的方式访问实体,那么实体的所有未被标为java.persistence.Transient的非 transient 实例变量都会被持欠化,类似的,如果以访问器方式来访问,那么未被标注为java.persistence.Transient的Javabean 属性都会被持久化。
映射用的标注(javax.persistence.ManyToOne等)不能加在transient 或者javax.persistence.Transient的实例变量和属性上。
持久化实例变量或者属性,当为集合类型时,必须声明为如下接口或者其泛化:java.util.Collection, java.util.Set, java.util.List, java.util.Map。
当采用访问器方式访问时,应注意:
下面的实体类用访问器方式,而访问器setName被设置成依赖于访问顺序的,这将导致问题:
设计者希望setSex在setName之前被调用,但是访问器的调用顺序是不定的,可以会出现先setName后setSex的情况。
实体类的子类可以覆盖父类的访问器,但是不要覆盖父类里实例变量或者属性的持久化元数据。