您的位置:首页 > 其它

O/R映射框架 反射技术

2010-09-24 13:21 141 查看
O/R映射框架 反射技术

优点: 1.提高生产力,不用再写sql语句,不用遍历结果集,代码量减少,
2.使开发更对象化了,只要操纵session对象save方法就保存数据了
3.移植性好,也就是方言的配置,适配器的配置,
4.支持透明持久化,实体没有侵入性,可以复用,
试用hibernate先建立对象模型,也就是领域模型,再建立映射关系,都是一对象为中心

注意:这里是斜杠啊<mapping resource="com/landy/hibernate/User.hbm.xml"/>

hibernate的映射工具:
1.Configuration(根启动) cfg=new Configuration.configure();------>读取hibernate的配置文件hibernate.cfg.xml,加入内存
2.SessionFactory factory=cfg.bulidSessionFactory();存储sql语句和映射源数据(连接池) ,SessionFactory适合数据库绑定的,一个数据库对应一个Sessionfactory,他是重量级的对象,就是创建比较耗时,消耗资源,最好只创建一次,他是线程安全的,可以对个线程用它,SessionFactory和二级缓存相关,
3.Session 存放当前工作单元所加载的对象,他不同于Connection,是有SessionFactory创建出来的,他对Connection进行了封装,Session他管理了缓存,对实体对象生命周期管理,一般是一个业务对应一个Session, Session用完后必须关闭,是非线程安全的,Session和一级缓存相关

hibernate核心接口:
1.JNDI Java名称和目录接口,统一管理,不依赖具体实现,解决了耦合
2.JDBC Java数据库连接,它处理本地事务,单一数据库,能保证原子性,但是跨数据库,跨资源,JDBC就不能保证了,
3.JTA Java事务API,保证跨数据库,跨资源的事务处理,他是两阶段数据处理,先是日志再更新,JTA是个容器,
4.Query 查询接口,支持hql和sql
5.Interceptor 拦截器,没有浸入性,他能将我们对实体类进行保存,删除前后的事件能侦听到,
6.UserType 转换器的概念,用户可自定义类,

持久化对象的生命周期:Transient(瞬时的),Persistent(持久的),Detached(离线的)

1.Transient *在数据库中没有与之匹配的数据
*没有纳入Session的管理

2.Persistent *在数据库中有与之匹配的数据
*纳入了Session的管理
*在清理缓存(脏数据检查)的时候,会和数据库同步

3.Detached *在数据库中有与之匹配的数据---------->只有数据库中有了才能update处理
*没有纳入Session管理

Session的load()方法 实现了lazy,懒加载或延迟加载,按OID检索,只有正真使用这个对象时才加载(发出sql语句),hibernate延迟加载实现原理是代理方式,
正真使用时对象就是persistent状态了,hibernate会自动和数据库同步,采用load在加载数据时,如果数据库中没有相应的数据,那么抛ObectNotFoundException异常,

Session的get()方法 在加载时马上发出sql语句,加载对象,不会有延迟,当查询数据不存在的数据时,返回null,并不抛出异常

一般是先加载在修改,删除,也就是不要手动构造detached状态,

有许多的批量的处理就不太试用hibernate

域对象之间的关系
1.关联:类之间的引用关系,以属性申明体现 ------>一对一,一对多,多对一,多对多
2.依赖:类之间访问关系,类中的方法
3.聚集:生命周期(逻辑上的约束)
4.一般化(泛化)继承

主键生成策略:
assigned 自然主键:手动赋值
native 动态的选择合适的标示符生成器,OREACL用到的序列hibernate_sequence
sequence
identity SQLServer,MYSQL
hilo 加一取走
increment:拿来加一

access=“property|filed”(访问级别,默认property)

inverse 让缓存忽略set集合的变化,只关心one方,在双向关联时通常都会更新两次,inverse=true
在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,one方有集合,这可以提高性能。在建立两个对象的关联时,
应该同时修改关联两端的相应属性:
Customer.getOrders().add(order);
Order.setCustomer(customer);这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码不受Hibernate实现类的影响。
同理,当删除双向关联的关系时,也应该修改关联两端的对象的相应属性:
Customer.getOrders().remove(order);
Order.setCustomer(null);

级联关系 cascade="save-update" 关联关系的级联程度,主体改变后客体按照级联程度也进行保存更新,
双向关联时两方同时进行,防止数据的不一致,关联关系的维护hibernate自动做了,所以在进行保存更新时只保存一方就行了,而和她关联的hibernate
机动保存更新了,这就是级联,级联操作在开发中慎用,
级联删除,利用jdbc删除有外键约束,利用程序删除就会被级联一起删除(更新),hibernate执行update语句将外键置为null来解除关联,
如想删除不再关联的对象,就将cascade="all-delete-orphan"

父子关系:cascade="all-delete-orphan" 子代不能删除父代,只能删除和父代关联的子代;更强的约束,将非法数据删除,关联关系的级别就不是更新了,就直接删除操作
就是没有对应的客户的订单也删除,对应的是删除操作,但原来是null的,他不会删除

多对一关联关系:
1.cascade属性为save-update的话,可实现自动持久化所关联的对象。
2.<many-to-one>

一对多关联关系:
1.<set name=“orders” cascade=“save-update”>
<key column=“CUSTOMER_ID” />
<one-to-many class=“..Order” />
</set>
name:设定待映射持久化类的属性名。
cascade:设定级联操作的程度。
key子属性:设定与所关联的持久化类对应的标的外键。one-to-many子属性:设定所关联的持久化类。

hibernate数据操作,面向对象:
1.插入 save()
对象加入缓存,成为持久化对象
2.更新 update() 将游离对象转变为持久化对象。不论对象属性是否发生变化,该方法都会执行update操作。如果希望仅当属性变化时才执行update语句的话可进行如下配置:(还要看具体业务了,不一定打开就好)
<class name=“…”
table=“…”
select-before-update=“true”> ----------------------更新之前先查询,只更新改变了的,
Session的update操作方法盲目的激活触发器, 如果游离状态的对象的属性和数据库一致,则更新操作是多余的。为避免这种情况:
<class name=“” table=“” select-before-update=“true”>
……
</class>

3.查询 load(Class,id)
根据OID在缓存中查询,类型,OID

4.删除 delete()
如果参数是持久化对象,就执行一个delete语句,若为游离对象,先使游离对象被session关联,使他变为持久化对象,然后计划执行一个delete语句。

5.批量删除 **hibernate 3.0支持批量删除
//只是创建除了删除条件,还没有执行
Query c=s.createQuery("delete from Customer c where c.id < 4");-------->用到Hql
//执行
c.executeUpdate();

6. Transaction.commit(); //提交 先清理缓存,然后向数据库提交事务, 在提交前Session有个清理缓存的模式setFluseMode(FlushMode.AUTO/COMMIT/NEVER),
模式设置为NEVER时,只有再调用flush()方法时才会提交到数据库中,

7. Session.flush(); //清理 缓存,让数据库和缓存同步,将缓存的变化反应到数据库中,但不提交,不提交就可以回滚,

8. Session.refresh(); //刷新 缓存,让缓存和数据库同步,取数据库中变化来更新缓存,执行查询操作,

9. Session.clear() //清空 缓存,将缓存中的引用全销毁,但引用的对象不一定被销毁,要看对象是否还有其他的引用,

10. Session.delete(d):将对象从Session中和记录中删除,将对象变为临时态,
11. Session.evict(c):将持久态对象转变成游离的状态,将对象单纯的从缓存中删除,并不对应删除记录的操作,
12. Session.saveOrUpdate():调用此方法时oid为null时肯定是save操作,如果oid类型定义为基本数据类型,那默认值为0,就不能是save操作,那怎么让oid是基本数据类的数据有插入操作,在配置文件中将id有个属性unsaved-value=“0”,这样就将oid为基本数据类型的记录调用saveOrUpdate方法时可以是save操作。

Session的save,update,saveOrUpdate方法都是将非持久化对象与Session关联让他们变成持久化对象,

缓存里的对象根据快照来查看数据是否有变化,只有来自数据库时才做快照(load),

触发器:在服务器执行,(数据库中执行)
Session.save(c);
Session.flush(); //执行后,进行更新数据库操作,触发了触发器,在application端并不知道,
Session.refresh(c); //缓存与数据库同步
触发器的行为导致缓存与数据库中的数据不一致。解决办法是执行完操作后,立即调用session的flush方法和refresh方法,迫使缓存与数据库同步。

Session的update操作方法盲目的激活触发器,如果游离状态的对象的属性和数据库一致,则更新操作是多余的。为避免这种情况:
<class name=“” table=“” select-before-update=“true”>
……
</class>

select-before-update的作用 1.更新没有修改的数据
2.盲目更新激活触发器

映射组成关系:<compont name=“homeaddress” class=“mypack.Address”> 他是值类型, component可以嵌套,

持久化类的属性分为两种:值(value)类型和实体类型(entity)类型。值类型没有OID,不能被单独持久化,他的生命周期依赖于所属的持久化类的对象的生命周期,组件类型就是一种值类型;实体类型有OID,可单独持久化。

在组合类型中save时没有赋值,在数据库中将会存入null,当查询时就会报空指针异常,因此要判断如果null就new一个然后添加上

类级别的检索:当查询对象的时候hibernate什么时候查询对象所对应的表,load受影响
立即检索:查询表,也就是在缓存里没有,他马上就查询库

延迟检索:只有正真访问对象,在内存里创建代理对象, 他先检查缓存里,缓存里没有,他并不立即查询库
<class name="cn.itcast.hibernate.domain.Customer" table="hib_customers" lazy="true">

代理类是用反射技术动态生成的一个新类,他继承了客户类,代理对象他能够监控Session是否关闭,在Session关闭之前你访问代理对象的有效属性时,就会触发代理对象去访问数据库的事件,进行查询操作,将结果赋给代理对象的属性,这个过程就是初始化代理对象,只有延迟检索才会有代理对象的概念,
代理对象在Session持久化时并没有赋初值,Session关闭后再去初始化,去查库,然而连接已关闭了,报 延迟初始化异常,可以通过下面方法进行初始化:

关联级别的检索:当查询主体表的时候观察和他关联的表的相应, 有了主体才有客体
set: one-to-many
立即检索:get lazy=false,
延迟检索:load 延迟到正真访问关联元素的时候 fetch=select&lazy=true || size()/count(*)----->extra(特别懒)
迫切左外连:以外连接 fetch=join

Many-to-one:

两边都是外连接,理论是打印出一条里面有两次外连接的语句,这在2.0是符合的,但这样会降低性能,但在3.0打印出两条语句,目的优化,忽略了第二次迫切左外连接检索,采用和lazy保持一致的检索,lazy=flase就立即,lazy=true就延迟。

Hql语句忽略了迫切左外检索,他与lazy保持一致
set批量立即检索 批量的检索用batch-size,和lazy来设置,Hql语句忽略了迫切左外检索,他与lazy保持一致,降低和数据库的交互次数:<set batch-size=“ 条数”>设置一次检索的条数,一般在3-10之间

批量延迟检索: 用Hql语句查询,只要将lazy=true,就是延迟检索了
Many-to-one的批量检索,orders集合对应几个客户,一次查一个客户,要查询多次,设置一次可以查询多个客户,应该在orders对端(客户)的类级别进行设置:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: