一、Hibernate原理及应用:
(四)Domain Object限制:引入:
(一)模型不匹配(阻抗不匹配):
Java是面向对象语言,属于对象模型,其主要概念有封装、继承、多态、关联等;而数据库是属于关系模型,其主要概念有:表、主键、外键、索引等。
(二) 解决办法
l 使用使用JDBC手工转换
l 使用ORM(Object Relation Map对象关系映射)框架来解决,当今主流的框架技术有:Hibernate、OJB等。
(三)hibernate的开发流程:
l 由Domain object-->mapping-->db(官方推荐);
l 由DB开始,用工具生成mapping和Domain object 使用较多的开发模式;
l 由映射文件开始;
① 必须有默认的构造方法;(必须);
② 有 无意义的id属性(在数据库中表示主键)可选(为发挥hibernate的最大效率推荐需在Java bean类中使用);
③ 非final ,对于懒加载有影响(可选);
2、Hibernate映射文件的作用:Hibernate映射文件就是用于说明Java对象与哪个表中的记录对应,以及Java对象中的各个属性分别对应表中的哪一列,不同性质的属性(例如,主键和普通属性用不同的标签来映射),如果java对象中的某个属性不需要存储在数据库中,那么在Hibernate映射文件就不需要配置这个属性!(把关系模型与对象模型连接起来,是Hibernate运行的一个核心文件)
(五)Session、SessionFactory
1、Session的几个主要方法:
Sava、persist保存数据,persist在事物外不会产生insert语句
Delete,删除对象
Update,更新对象,
Get,根据ID查询,会立刻访问数据库Session.get(Class,id)的解析:
(由于Session可以管理多个数据库表所对应的多个实体对象,如果要查询id为1的实体对象,Session.get方法需要知道去从哪数据库表中查询id为1的记录,所以,除了给get方法传递所要查询的实体对象的id值外,还必须给get方法传递实体对象的类型,get方法才能知道去哪个数据库表中进行查询)
1.1、 Load,根据ID查(返回的是代理,不会立刻访问数据库)
(使用load方法去获取数据库表中的数据,如果在session链接期间没有调用数据,load方法不会与数据库进行交互,一旦Session.Close();则再取数据就会出现抛出懒加载异常)
1.2、savaOrUpdate,merge(根据ID和Version的值来确定是sava还是Update),调用merge你的对象还是托管。
1.3、Lock(把对象变成持久对象,但不会出现同步对象的状态)
2、区分Session和SessionFactory:
(2.1)配置主意事项:
n 在设置hibernate.xml以及和***.hbm.xml一定要注意在设置一元素的属性值时不要出现属性值前后有空格
(六)实体对象的三种对象状态以及savaOrUpdate方法:
瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来且与session没有关联的对象。
持久(persistent):数据库中有数据与之对应,但前与session有关联,并且相关联的session没有关闭,事物没有提交,持久对象状态发生改变时,在事物提交时会影响到数据库中的数据(hibernate会检测的到);
脱管(detached):数据库中有数据与之对应,但当前没有与session与之关联,托管对象状态发生改变时,hibernate不能检测到。对象状态示意图:
(七)hql查询(Hibernate Query language):
hql面向对象的查询语言,与sql不同的是hql中的对像名是区分大小写的(除了JAVA类和属性其他部分不区分大小写);HQL中查询的是对象而不是表,并且支持多态;hql主要通过Query来操作,Query的创建方式:
Query q=session.createQuery(hql);
当确定查询结果只有一个时可以使用:query.uniqueResult()
From Person;
From 类名 别名 where 别名.属性=?;
From 类名 别名 where 别名.属性:=属性 And 别名.属性:=属性;
主意:如果映射文件中的类名以及属性名和数据库中的关键字相冲突的话就在映射文件中修改表名和属性 ---》加单引号‘’
(八)sql查询方式(Criteria):
1、非动态查询:
此查询方式更接近与面向对象实例代码如下:
//sql查询所有信息
public static void selectAll(String name)
{
Session s=HibernateUtil.getSession();
org.hibernate.Criteria cri=s.createCriteria(Students.class);
cri.add(org.hibernate.criterion.Restrictions.eq("name", name));
cri.add(org.hibernate.criterion.Restrictions.lt("birthday", new Date()));
cri.setFirstResult(0);
cri.setMaxResults(1);
Students students1=(Students)cri.uniqueResult();
System.out.println("sql uniqueResult结果集:"+students1.getName());
List<Students> list=cri.list();
for(Students students:list)
{
System.out.println("ID:"+students.getId()+"\tname"+students.getName()+"\t"+students.getBirthday());
}
主意:无论是hql对象查询还是sql对象查询,其所查询的都是对象 因此 在在hql语句以及增加Criteria约束时所使用的字段需与所查询的类属性名一致,而不是与数据库表中的字段一致
(九)动态查询:
DetachedCriteria dc=DetachedCriteria.forClass(CLass);
dc.add(Restrictions.xxxx);
Criteria c=dc.getExecutableCriteria(session);
List list=c.list();
(十)Iterator:查询的效率很低它是一条记录一条记录的查询的
(十一)多对一关联关系的映射与原理分析:
在映射文件中,增加标签<many-to-one name="" column="" not-null="true/false" property-ref="">去实现
(十二)一对多关联关系的映射与原理分析:
<set name="listEmp">
<key column="depart_id"></key>
<one-to-many class="Employee"/>
</set>
(十三)一对一关联关系的映射与原理分析:
基于主键的(one-to-one)的映射:
<id name="id">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<property name="userfullDate" column="userfullDate"/>
<one-to-one name="person" constrained="true"/>
基于外键的(one-to-one)的隐射:
查询总结:通过主对象、或者是从对象,都可以查询出 主从对象的数据
(十二)多对多关联关系的映射与原理分析:
(十三)Hibernate中使用的集合类型:
集合映射(set【集合中不允许有重复】、list、map、Array[]、bag)
l 这些集合类都是Hibernate实现的类和JAVA中的集合类不完全一致,set,list,map分别对应java类中的Set,List,Map接口,bag映射成java类中的List;这些集合的使用和JAVA集合中对应的接口基本一致;在JAVA的实体类中集合只能定义成接口不能定义成具体类,因为集合在运行的时候会被替换成Hibernat的e实现;
l 集合的简单使用规则:大部分情况下使用set,需要保证集合中的顺序就用list,想用java.util.List又不需要保证顺序用bag;
l 主意:在实体化类中定义的哪些集合类,定义成接口不要定义为实体类。
(十四)关联关系中 级联关系(cascade):
所谓关联关系就是用来说明当主对象进行某种操作时,是否其关联的从对象也进行同样的操作;常用的cascade有:none, all, save-update, delete, lock, refresh, delete-orphan(one-to-many) 。一般对多对一、多对多不会设置级联关系;
(十五)关联关系的维护:属性值(inverse)
Inverse表示“是否放弃维护关联关系”(在JAVA里两个对象产生关联时,对数据库表的影响),在one-to-many和many-to-many的集合定义中使用,inverse=“true”表示该对象不维护关联关系,该属性的值一般在使用有序集合时设置成false(主意hibernate的缺省值是false)。One-to-many维护关联关系就是更新外键,many-to-many维护关联就是在中间表中增减记录。
注:配置成one-to-one的对象不维护关联关系
(十六)继承关系的映射:
l 继承关系__整个继承树映射到一张表上。
<!-- 鉴别器 -->
<discriminator column="type" type="int"/>
<subclass name="Skiller" discriminator-value="1">
<property name="skill"></property>
</subclass>
l 继承关系__每个类映射到一张表上(每个子类一张表)
<joined-subclass name="Skiller">
<key column="emp_id"></key>
<property name="skill"></property>
</joined-subclass>
l 每个具体类一张表:(union--subclass)
<joined-subclass name="Skiller">
<key column="emp_id"></key>
<property name="skill"></property>
</joined-subclass>
(十七)懒加载:
进行懒加载的目的是为了提高性能,尽量避免没必要的数据库查询,其工作的基本原理是延迟与数据库进行交互。
(十八)缓存的原理及分析:
缓存:缓存就是处于应用程序和物理数据源之间,其作用就是降低应用程序访问物理数据源的频率,以至于提高系统的性能。
什么样的数据适合存放到第二级缓存中?
1、很少被修改的数据
2、不是很重要的数据,允许出现偶尔并发的数据
3、不会被并发访问的数据
4、参考数据
不适合存放到第二级缓存的数据?
1、经常被修改的数据
2、财务数据,绝对不允许出现并发
3、与其他应用共享的数据。
要使用Map集合进行缓存的处理,以此来提高系统的性能:
主意事项:Query不能读取缓存的数据,能够读取缓存中的数据有get、load、list、iterator、
一级缓存和二级缓存的区别:
一级缓存中数据的生命周期很短,仅限于持久层,而二级缓存生命周期很长
(十九)事物:
(二十)OpsessionInview:
Open Session in view 在request把session绑定到当前thread期间一直保持Hibernate session在 open状态,使得session在request期间都可以使用。
ThreadLocal其实是Thread中的一个局部变量
可以解决事物边界管理、以及懒加载问题,但是引入了两个问题那就是Session以及事物时间的延长
(二十一)事务中的悲观锁与乐观锁:
悲观锁:是由数据库产生的,当从数据库读取一条数据的时就会把这条数据给锁住,等到修改后再释放它,读取的这条数据才解锁,不然 别人读取不了。
乐观锁Hibernate是由version和timeStamp来实现(推荐使用version)
(二十二)、
一对多配置文件
一对多中的一对象:
<id name="id" column="id" unsaved-value="-1">
<generator class="native"/>
</id>
<property name="" column=""/>
<set name="">
<key name=""/>
<one-to-many class="">
</set>
多对一中的多对象:
<id name="id" column="" unsaved-value="">
<generator class="native"/>
</id>
<property name="" column=""/>
<many-to-one name="" column="" not-null="true/false">
多对多的映射文件配置:
<id name="" column="">
<generator class="native"/>
</id>
<property name="" not-null="true/false"/>
<set name="" table="">
<key column=""/>
<many-to-many class="" column="" />
</set>