问题:模型不匹配(阻抗不匹配):
Java面向对象语言,对象模型:其主要概念有:继承、关联、多态等
数据库属于关系模型,其主要概念有:表、主键、外键等
解决办法:
1. 使用JDBC手工转换
2. 使用ORM(Object Relation Mapping,对象关系映射)框架来解决,主流的ORM框架有Hibernate、TopLink、OJB等
安装配置:
1. 全局配置文件有hibernate.cfg.xml和hibernate.properties两种,这两个文件的作用一样,提供一个即可,推荐XML格式,下载目录/etc下有示例配置文件。
可以在配置文件中指定:
l 数据库的URL、用户名、密码、JDBC驱动类、方言等
l 默认启动时Hibernate会在classpath里找这个配置文件
2. 映射文件(hbm.xml,对象模型和关系模型的映射)。在/eg目录下有完整的hibernate示例。
开发流程:
1. 由Domain ObjectàmappingàDB(官方推荐)
2. 由DB开始,用工具生成mapping和Domain Object(使用较多)
3. 由映射文件开始
Domain Object的限制:
1. 默认的构造方法(必须)
2. 无意义的标识符id(逻辑主键)(可选)
3. 非final的,否则对懒加载有影响(可选)
4. 规范:一般把映射信息放在不同的映射文件中,以便管理维护
重要接口:
l Session接口:org.hibernate.Session
1. load(Class, Serializable)à懒加载、生成代理(子类);
2. Session的几个主要方法:
1. save、persisit保存数据,save在事务外会产生insert语句最后回滚,persist在事务外不会产生insert语句(domain对象没有id值);
2. delete 删除对象;
3. update 更新对象,如果数据库中没有记录,会出现异常;
4. get 根据ID查,会立即访问数据库;
5. load 根据ID查,返回的是代理,不会立即访问数据库;
6. saveOrUpdate,merge(根据ID和version的值来确定是save或update),调用merge你的对象还是脱管的;
7. lock 把对象变成持久化对象,但不会同步对象的状态。
对象状态:
l 瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来且没有与session关联的对象;
l 持久(persistent):数据库中有数据与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交。持久对象状态发生改变,在事务提交时(多个状态的改变会延迟与数据库的交互,以减少交互次数,提高效率)会影响到数据库(Hibernate能检测到);
l 脱管(detached):数据库中有数据与之对应,但当前没有session与之关联,脱管对象状态发生改变,Hibernate不能检测到。
Hibernate查询:
1.HQL(Hibernate Query Language):
面向对象的查询语言,支持多态。与SQL不同,HQL中的对象名是区分大小写的(除Java类及其属性外的其他部分不区分大小写)。HQL中查的是对象不是表。HQL主要通过Query接口操作,Query的创建方式:
Query q = session.createQuery(hql);
l from Person
l from User as user where user.name=:name
l from User as user where user.name=:name and user.birthday<=:birthday
注:1.q.setXXX(index, value)的index从0开始,而JDBC中pstmt.setXXX从1开始
2.查出的是User对象
2.Criteria(条件查询,面向对象的查询方式)
Criteria的创建方式:
Criteria cri = session.createCriteria(Class);
cri.add(Restrictions.eq(“name”, name));
cri.add(Restrictions.lt(“birthday”, new Date()));
注:与Query相比,区别主要在构造查询条件的方式上。两者获得查询结果的方法调用基本相同。
Hibernate CRUD:(单表)
实验步骤:
1. 设计domain对象User;
2. 设计UserDAO接口;
3. 加入hibernate.jar和其依赖的包;
4. 编写User.hbm.xml映射文件,可以基于hibernate/eg目录下的
org/hibernate/auction/User.hbm.xml修改;
5. 编写hibernate.cfg.xml配置文件,可以基于hibernate/etc/hibernate.cfg.xml修改。必须提供的几个参数:connection.driver_class、connection.url、connection.username、connection.password、dialect、hbm2ddl.auto;
6. 编写HibernateUtils类,主要用来完成Hibernate初始化和提供一个获得Session对象的方法。(可选)
7. 实现UserDAO接口。
关联映射:(多表)
l 多对一(Employee-Department)
l 一对多(Department-Employee)
l 一对一(room-door)
1) 基于主键的one-to-one
2) 基于外键的one-to-one,可以描述为多对一,加unique=“true”约束
与1)相比在对象模型上没有变化,在映射文件和关系模型中(表结构)有变化。
Hibernate依赖hbm映射文件工作,忽略没有配置O/R映射的属性。
l 多对多(teacher-student)
1.在操作和性能方面都不太理想,所以多对多的映射使用较少。实际使用中最好转换成一对多的对象模型,Hibernate会为我们创建中间关联表,转换成两个一对多。
2.多对多关系不涉及update语句,而是通过在中间表中插入(insert)记录来建立关联;而一对多、多对一关系是通过更新多方的外键来建立关联的。
3.中间表使用联合主键(PK),并且两个主键有分别是外键(FK)。
注:关键是区别不同映射文件的写法。
在获得关联对象的查询中,一般情况下Hibernate是通过两次查询获得目标对象,只有在一对一的关联关系中且查询的目标对象是主对象的情况下才会一次完成查询。
l 组件映射(User-Name)
对象属性很小,没有必要以关系表保存(<component>)(不是实体),但该类的属性要持久保存。
l 集合映射(set,list,map,bag,array)
1.bag和List类型是对应的,特点是不保证List迭代器的返回顺序。
2.这些集合类都是Hibernate实现的类,和Java中的集合类不完全一样,set,list,map分别和Java中的Set,List,Map接口对应,bag映射Java的List。这些集合的使用和Java集合中对应的接口基本一致,在Java的实体类中集合只能定义成接口不能定义成具体类,因为集合会在运行时被替换成Hibernate的实现。
3.集合的简单使用原则:大部分情况下用set,需要保证集合中的顺序用list,想用java.util.List又不需要保证顺序用bag。
l inverse和cascade(Employee-Department)级联和关系维护
1. cascade用来说明当对主对象进行某种操作时是否对其从对象也作类似的操作。
常用的cascade:
none, all, save-update, delete, lock, refresh, evict, replicate, persist, merge, delete-orphan(one-many)。一般对many-to-one,many-to-many不设置级联,在one-to-one和one-to-many中设置级联。
2. inverse表示“是否放弃维护关联关系”(在Java里两个对象产生关联时,对数据库表的影响),在one-to-many和many-to-many的集合定义中使用,inverse=“true”表示该对象不维护关联关系。该属性的值一般在使用有序集合时设置成false(注意hibernate的缺省值是false)。one-to-many维护关联关系就是更新外键;many-to-many维护关联关系就是中中间表增减记录。
注:配置成one-to-one的对象不维护关联关系
3. cascade属性对所有映射属性都可以配置,inverse只有集合属性映射才能配置。
Hibernate本身是比较复杂的框架,但是为了降低开发难度,如今几乎不应用关联映射和继承映射,只是应用简单直接的一个实体类对应一张表的映射方式。由于去掉了关联和继承,剩下的基本是单表操作,所以单表操作一定要熟练掌握。