关于bean中属性作用域的问题。(隐藏 某些属性,同时希望能够通过hibernate抽上来)
有时候,我们不希望能够让某些属性暴露在外面,比方说书中的例子类Category。
public class Category {
private String name;
private Category parenteCategory;
private Set<Category> childCategories = new HashSet<Category>();
private Set<Item> items = new HashSet<Item>();
public void addChildCategory(Category childCategory){
if(childCategory==null){
throw new IllegalArgumentException("Null child category!");
}
if(childCategory.getParenteCategory()!=null){
//如果原父目录不为空,则在原副目录中删去子目录,
childCategory.getParenteCategory()
.getChildCategories()
.remove(childCategory);
}
childCategory.setParenteCategory(this);
this.childCategories.add(childCategory);
}
}
其不希望存放子目录的childCategories直接暴露给外面。就可以用把其get,set方法设为私有,或者删除。书上说可以直接的字段访问进行持久化,这一点我还是看不太明白。估计以后会说吧。
在这里他绝少一个不错的方法,返回只读的set和map。这个方法是Collections中的unmodifiableXXX,很不错的一个方法。
hibernate中的脏检查
对于在hibernate中,对于某一个对象的属性的改变,是判断它的值,而不是统一性。所以获取方法的时候,返回一个不同的对象比返回由hibernate传递到设置方法的对象来的安全。
比方说下面的方法(返回User类的firstname属性)就比较安全。
public String getFirstname(){
return new String(firstname);
}
这里我的理解是,如果要返回从hibernate抽上来的对象。那么如果这个返回对象改变。那么hibernate可能会自动的进行更新。比方说说这里的firstname。我返回出去之后,那么如果我改变这个值,hibernate也会更新。
但是对于集合,则只是判断其统一性,而不是值的改变。
比如说下面的代码需要尽量的避免。
public void setNames(List namesList){
names=(String[])namesList.toArray();
}
public List getNames(){
return Arrays.asList(names)
}
因为每次都会产生不同的对象,而使得统一性改变。
动态SQL语句生成。(SQL语句不显示所有的数据表的字段)
就是class标签中的dynamic-insert和dynamic-update语句。这个时候生成的sql语句,只会出现需要更新的字段。(估计这东西到时候看看api就能了解个大概。只是会看不懂。)
使查询返回的实体(类)不可变。
class标签中的mutable属性。设置成false
这个属性个人觉得有点比较大的限制。毕竟一旦设置,那么一切也就没了。这个就有点太严谨了一点。
给查询实体命名。(重命名类的实体)
标签是:
<hibernate-mapping>
<import class="auction.model.Auditable" rename="IAuditable"/>
</hibernate-mapping>
以后的HQL查询的时候,直接输入IAuditable就好了。不过这个觉得比较奇怪,因为import标签没有说明给。
实现命名约定
比方说一个类User,而规约约定的是数据库表的前缀是db。那么数据库中对应的表应该是db_user。那么用了这个就可以在配置文件中直接写对应的表为user。
具体的用法是写一个类,继承ImprovedNamingStrategy或者实现NamingStrategy接口。然后调用Configuration中setNamingStrategy方法
这个方法觉得有点鸡肋。唯一的用处就是相同的对象要进入不同的表中的时候用到。但是用这个方法感觉很原始,首先,需要不创建不同的SessionFactory。其次,用继承也能起到差不多的效果,而且继承更加的方便。唯一的用处就是写映射文件的时候,方便一点了吧。
属性访问,衍生属性(计算值),默认属性等
看具体api吧,比较清楚一点。
映射组建
使用的是Component标签来进行。我发现如果要使用到parent子标签时,组件类当中要有一个属性,指向包含它的类。
继承映射
继承映射书上介绍了4种方法。其实真正意义上的只有3种。因为第一种方法完全就是每个子类建一个不相关的映射文件。这样做对于多态来说,毫无意义。而且和基本的映射没有区别,这里也就不再复述了。
第一种方法的标签为union-subclass。中文的翻译很拗口,叫做每个带有联合的具体类一张表。我习惯称之为union。因为Hibernate内部,各个子类的关系就是一种联合的关系。
这种方法,每个具体的子类代表一张相应的表。各个表之间在数据库那层更本没有关系。只是在Hibernate内部,知道每张表代表的是不同子类的对应的不同的表。所以,在进行多态查询的时候,只通过union把各个表联合成一张大表,做为查询的表,进行查询的。
也就是因此,如果采用这种方法,不太适合那种需要经常进行多态查询的表。因为每次多态查询都需要把所有子类合并成一张大表。在这里书上有点错误。父类的id的生成器的生成策略是native。至少在mysql的环境下是不行的。其他服务器估计也会产生问题。因为native能保证一张表中的主键的连续。但是无法保证在多个表中主键的唯一。所以无法在这种,会生成多张表的,且需要多张表的主键都唯一,这显然不行。
第二种方法是得标签是subclass。叫做每个层次一张表。具体的说,就是所有单个类的数据都放在一张表上面。
打个比方来说,比方说主类A有a,b两个属性,子类B其特有c属性,C则有d属性,那么代表这个的表中,就会有a,b,c,d 4列。如果这样设计的优势就是查询不再需要多张表连接了。速度会快很多。同样的带来的问题就是,如果子类有很多,同时每个子类都有着其独特的属性,那么这个表就会很大,同时很多列会浪费掉。还有一个很头痛的问题就是子类的独有属性不能设置成unique。
所以这种办法,书上建议是最好的子类之间的区别是其行为,而不是属性的时候使用。这样生成的表就会精简很多。
第三种方法,标签是join-subclass。其数据库实现是主类的属性一张表,然后各个子类的信息一张表。且子表的主键参照记录在主表中记录的主键。
我觉得这种方法感觉很中性,因为第一种方法如果不考虑多态查询的话是很好的。而第二种呢,多态查询时方便。但是如果每个属性都有着自己的独特属性,就会一些数据库层次的东西。而这种方法则是一种平衡。
最后混合方法。其实就是一种嵌套。不过记住。没有subclass。如果用了subclass。则是子类的子类了。
Hibernate数据类型
这一些基本看书吧。基本上技术上那点东西。不过我就觉得要注意两点
其一,不同的string对应的值。其二,和Hbiernate无关,就是Calendar的月份起始是0。
(附件为自己根据书上写的例子,自定义类型由于书上例子写的很模糊,后来去网上找了一下原本的案例。看的一般懂,所以没有对例子中的代码改进)
集合映射
bag:这是一个java中没有的东西,如果概念上简单的来说,就是一个可以重复的set。书中在介绍的时候,基本就介绍了一个<idbag>标签来实现bag的。后来查了一下资料,知道还有一个<bag>标签。两者的却别就是前者有一个id的列。
无论对应的是哪一个。都是对应着Collection类
至少我觉得,<idbag>要比单单的<bag>要好很多。bag的定义是可以重复,无序的一个集合。听起来不错,但是在大多数情况下,对于数据一个重要的要求就是能够被区分。而一旦用了<bag>标签,存入数据库的时候,如果值相等,那么就没有了一点区别。
如果用<idbag>标签,那么就需要一个<collection-id>其中的generator不能使用native或者identity。我查了一下api。3.2不支持identity,而3.3的直接写不支持native。我觉得可能是不支持identity。因为选了native就是自动的在identity和sequence之间根据数据库进行选择。
List:基本上没什么好说的。就是标签要熟悉一点。其区分记录用的是<list-index>标签
map:<map-key>标签。map是一个对数据的存储。一个key。对应的就是<map-key>
set:觉得没什么好说的了。
其实从总体上来说,所有的集合标签都是相当死。没什么可以深究的。所有的代码都是那个样子。关键在于熟记和理解集合的概念。
映射父/子关系
不知道官方说法是怎么说的。反正我的觉得这个名字有点变扭。感觉和继承关系有点重名。具体的实现其实就是在集合的标签中加入了一些<one-to-many>之类的标签。从数据库的表的层面上来说没有任何实质上的变化。
但是从逻辑上来说,这种映射和集合的映射有着本质上的区别。集合的映射属于一种整体性的映射。而父子的映射属于对象与对象的映射。对于此,我也是在朦胧中摸索,也无法讲的很明白。
inverse
inverse表示的是告诉Hibernate哪边不用维护。就以书中的例子来说(具体可以看我附件中的例子,大体上是Item和Bid两个类)。在inverse为false的时候,Hibernate会发出5句语句。一句在Item表中加入一条语句,然后两句在Bid类中加入两条记录的两句语句。最后对更新刚才两条数据的ITEM_ID选项(就是和Item表关联的字段)。
因为在hibernate内部,每一个类中的字段都是被“监视”着的,默认情况下一有风吹草动就会更新。而在java中,双向关联需要两个的是在两个对象中设置不同的两个属性互相指向。但是在数据中,这种联系往往是一个外键就解决了问题。造成的结果就是一个数据库中的一列,被两个字段所所引用。所以当改变的时候,java中需要改变两个对象的相关属性,而数据库中则只需要改变一个就可以解决问题了,java的改变要比数据库多一次。hebiernate监视的java代码,而不是数据库,这也就是产生多余sql语句的原因。
而inverse就是告诉Hibernate,这里只是一个镜像,不用维护。从而达到了减少sql语句的作用。
不过在写inverse例子的时候,我发觉了对于值类型的类,一定要写好equals和hashcode方法,并且这些方法最好要用和业务逻辑相关的值。不然可能hibernate很容易会产生不必要的更新操作。
级联
这是很容易和inverse相混淆的一个概念。因为他们的区别很难用言语表达。我现在理解是inverse告诉hibernate什么不该做。而级联告诉的则是什么应该做。
级联分为传播,删除和孤儿。分别对应的是数据的更新(包括插入),父对象的删除和子对象从父对象中被删除来确定。
问题
其实书中的bids的集合是对外开放的。set和get方法都是public。当然如果在实际操作中都会知道这是很不保险的做法。我也就自己想着解决办法。
首先我想到了就是删除set方法。结果失败。然后就把代码改成了这个样子。
public Set<CPBid> getBids() {
return Collections.unmodifiableSet(bids);
}
SuppressWarnings("unused")
private void setBids(Set<CPBid> bids) {
this.bids = bids;
}
倒是运行过了。此时如果把setbids设成public。在读取item内部的bid时,则会报一个很奇怪的错误。org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: collection.parent.CPItem.bids。觉得很是奇怪。
首先我代码中并没有任何的删除语句。后来想想,可能是因为hibernate获取bids的时候也是调用这个get方法,而这方法的返回值肯定与原来其内部存储的不一样(因为是新建的)。而此时的bid指向的是原来那个的缘故吧?
但为什么把set设置成private就能跑过呢?很奇怪啊
心得:
一,hibernate关心的永远只是一个一个属性,而不是数据库当中的表。这也就是为什么inverse属性不放在多一方Item的时候,数据库更新的是Bid所代表的那张表。因为一旦建立了这种联系关系。Item和Bid有联系,在数据库当中,都是维护着Bid当中关于Item的外键。
但是数据库中的表和OO有着一些格格不入。因为OO对象与对象之间的关系是指针。比如书中的例子,一个Item,指向n个Bid。在java的世界里。有多少个Bag和Item。就会产生多少个对象。他们直接互相的指针标示着他们的关系。
但是在数据库中,则是完全另一幅景象。数据库中,对象与对象的关系通过的是通过外键来形成的。代表一个对象的一条记录有着另一个对象的记录的时候,就表示两个对象之间建立了联系。
Hibernate在处理这种关系的时候,往往会把这表示联系的关系外键放在一得一方。one-to-one是联合主键。而many-to-one则是把外键放在了one的一方。这点起初让我很混淆。因为方向也好,真的让我很糊涂。
双向和单向
这个概念可能有点困扰。因为在hibernate中,只要在类当中有着链接。那么一定一个找到另一个。比如说例子中的bid和item,item中的bid是map或者set存放,那么通过item,一定能够找到相应的bid。只是单向的导航只是无法确定或者说必须先获得整体的包含bid的map,然后通过代码进行查找特定的bid。而双向的可以直接找到相应的bid。
所以来说,如果说需要双向导航,在表示两者这件一对多或者多对一的关系的时候,只能使用<idbag>,<list>和<map>这样的标签。因为这些标签使得在多端,会产生一个和一端相关,和多端无关的标识。而set,bag这种标签,则不会有这种东西
<mang-to-one>之类的标签
开始的时候,我对于这些标签和迷惑。不知道其到底有着什么特别的作用。
慢慢的,明白了这只是一个代表着一个类中的属性。和property之类的标签有着一样作用的。表示这个属性对应着何种的值。只是有了这个标签,就告诉了Hibernate。这个属性和其他的属性不一样。不能够单独存在。其和其他类有着特殊的关系。
<many>端的unique
首先,从hibernate来说,其处理的是OR映射框架。而在操作层上面,其关心的只有在类当中的属性。在hibernate内部,只有属性和表中的关系应该是多对多的关系。但是从属性一端来理解hibernate的映射,将会是比较方便的方法。
所以来说,如果many一端设置了unique,就等于把这一端设定成了one端。因为属性对应的字段为唯一,那么一切就好办很多。
<many-to-many>标签
其实这个标签和上面的标签没什么本质上很大的区别。也是一种映射的表示。
至于中间件的处理,如果简单点,就是一个类的映射。当然复杂一点,就要深入讨论了。这里就不展开了。
继承
这里的继承的与前面不同的是外部调用多态的实现。很简单,就好像组件的组装了。
当然有一点复杂,但是书上也说了。这个复杂的东西被用的概率很少很少。所以我就知道,解决这些问题是通过一个叫做<any>的标签。
分享到:
相关推荐
《Hibernate学习笔记特别详细》 Hibernate,作为一款开源的Object-Relational Mapping(ORM)框架,为Java开发者提供了强大的数据库操作支持。它简化了数据库访问的复杂性,使得开发人员可以像操作对象一样操作...
在本篇《Hibernate学习笔记》中,我们将深入探讨Hibernate这一流行的Java对象关系映射(ORM)框架。Hibernate允许开发者以面向对象的方式处理数据库操作,极大地简化了数据存取的复杂性。以下是一些关键知识点: 1....
Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...
【Java相关课程系列笔记之十四Hibernate学习笔记】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。本笔记将详细阐述Hibernate的核心概念、使用方法和特性。 一、...
hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要
《Hibernate学习笔记——马士兵教程解析》 在Java开发领域,ORM(Object-Relational Mapping)框架的使用已经非常普遍,其中Hibernate作为一款优秀的ORM框架,因其强大的功能和易用性深受开发者喜爱。本文将根据马...
这套笔记是我学习Hibernate,进行相关技术点训练时记录下来的,其中包括技术点说明与相关事例,拿出来与大家分享。
### 马士兵Hibernate学习笔记知识点总结 #### 一、HelloWorld示例 - **目的**:通过简单的示例理解Hibernate的基本使用流程。 - **步骤**: - 创建Java项目`hibernate_0100_HelloWorld`。 - 建立库依赖,包括...
Hibernate是一款强大的Java持久...通过阅读这份“Hibernate API帮助文档”和“Hibernate学习笔记”,你将能够深入理解Hibernate的工作原理,掌握其API的使用,并能在实际项目中有效地利用Hibernate进行数据持久化操作。
**Hibernate学习笔记与总结** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库上操作对象数据的便捷方式。本文将深入探讨Hibernate的核心概念、配置、实体类、映射文件、...
### Hibernate 学习笔记知识点概览 #### 一、Hibernate 概述 - **定义**:Hibernate 是一款开源的对象关系映射(ORM)框架,它实现了将 Java 应用程序中的对象模型映射到关系型数据库中的记录。通过 ORM 技术,...
### JDBC与Hibernate学习笔记 #### 一、JDBC概述 **1.1 ODBC与JDBC的区别** - **ODBC(Open Database Connectivity)**: 开放式数据库连接是一种开放标准的应用程序接口(API),用于实现数据库应用程序与不同...
### 对象持久化与Hibernate学习笔记 #### 一、对象持久化的概念与重要性 - **定义**: 对象持久化是指将程序中的对象状态存储到持久化存储设备上的过程,以便在程序结束运行后仍然可以保留这些数据。 - **必要性**:...
《马士兵Hibernate学习笔记》是一份深入浅出的教程,旨在帮助初学者掌握Hibernate这一流行的Java持久化框架。Hibernate是一个对象关系映射(ORM)工具,它允许开发者用面向对象的方式来操作数据库,从而减少了传统...
【hibernate学习笔记】 在Java开发中,Hibernate是一个强大的对象关系映射(ORM)框架,它极大地简化了数据库操作。以下是对Hibernate的学习要点的详细解释: 1. **建立第一个Hibernate版本的HelloWorld** - **...
标题:Hibernate学习笔记3 描述:本篇笔记深入探讨了Hibernate框架中一对多关系的映射及持久化对象状态管理,结合个人理解与实践经验,旨在为读者提供一份详实的学习资料。 ### 一、一对多关系映射详解 在...