Hibernate and IBatis

来源:互联网 发布:淘宝产品短连接 编辑:程序博客网 时间:2024/05/29 15:24
  hibernate和IBatis是ORM框架,对象关系映射,就是对象与数据库中的表之间的映射。


1,模型的三种状态

瞬时态:刚new出一个model对象还没往数据库中存储时;

持久态:sessionFactory打开并往数据库中存储后,在session关闭之前为持久态,此事对数据更改会同步导数据库;

托管态:session关闭,数据不能同步时。

2,getCurrentSession()与openSession()的区别 
* 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession() 则会不断创建新的session。
* 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭

如果一个事物在同一个线程但垮了好几个类的话,第一种比较方便。但第一种方式在查询时也需要事物管理,所以效率低下。

openSession() :

   Configuration cfg = new Configuration();  // 获得配置信息对象
   SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
   Session session = sessionFactory.openSession(); // 打开Session
   
   session.beginTransaction();  // 看成一个事务,进行操作
   session.save(s);  // 会找到 Student 这个类,寻找set方法
   session.getTransaction().commit(); // 提交对数据的操作
   session.close();

   sf.close();

getCurrentSession():

 Configuration cfg = new Configuration();  // 获得配置信息对象
   SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
   Session session = sessionFactory.getCurrentSession(); // 打开Session
   
   session.beginTransaction();  // 看成一个事务,进行操作
   session.save(s);  // 会找到 Student 这个类,寻找set方法
   session.getTransaction().commit(); // 提交对数据的操作

   sf.close();


session线程安全问题:可以用ThreadLocal对session做一下本线程绑定即可。

getCurrentSession()已经和当前线程进行了本线程绑定,线程安全。opensession不断产生新的session,所以也是线程安全。

http://www.bitscn.com/pdb/java/200806/143941.html


sessionFactory是进程级别的单例,线程安全,buildSessionFactory方法已经为我们处理好;重量级接口,一个项目只需要一个。


3,Session接口:这里的Session并非指HttpSession,可以理解为基于JDBC的Connnection。

方法介绍:http://blog.csdn.net/haolongabc/article/details/38677881

1)get和load

①get方法会在调用之后立即向数据库发出sql语句(不考虑缓存的情况下),返回持久化对象;而load方法会在调用后返回一个代理对象,该代理对象只保存了实体对象的id,直到使用对象的非主键属性时才会发出sql语句。

②查询数据库中不存在的数据时,get方法返回null,load方法抛出异常:org.hibernate.ObjectNotFoundException。

2)merge和saveOrUpdate

Session类中saveOrUpdate方法与merge方法,都是让Hibernate自己判断某个对象是否是新加入的数据记录,还是对数据库中已有对象进行更新,区别就在于调用saveOrUpdate方法后,该对象会从瞬时或者托管状态变为持久状态,而调用merge之后,对象会保持托管状态,即内存中不存在。

3)clear和flush

clear方法清除缓存,flush将缓存中的数据与数据库同步,并不能清除缓存。


4,数据库表
1to1:外键
1tomany:多的一方外键
many2many:中间表,在中间表里设外键或双主键。
双向关联两定律:设好双方的导航,在一方中设定mappedby,只让一方控制他们的关系
mappedby:设定mappedby的一方为被控方。这是在你的两张表中有外键关联的时候用到的,比如你在A表中有一个外键,是B表的ID(主键),这时候A就是主控方,B就是被控方。所以A表可以通过外键控制双方的关系。

cascade属性的可选值:
all : 所有情况下均进行关联操作。
none:所有情况下均不进行关联操作。这是默认值。
save-update:在执行save/update/saveOrUpdate时进行关联操作。
delete:在执行delete时进行关联操作

fetch = FetchType.LAZY
fetch = FetchType.EAGER

继承映射:

http://blog.csdn.net/mzule/article/details/6194188    第三类相比于第二类运用了表关联,只存自己特有的内容。

缺点:

single:表中记录较多,而且存在大量null字段,还得需要冗余字段来区分;

per:子表之间id不能重复,当取出Person p=new Student()时,需要检查所有的子表。

join:必须用表连接才行,每添加一个新子类必须新建表


树状结构表:many2one的父节点和one2many的孩子们;

5,hibernate的查询方式
按功能排序:Native Sql(数据库方言)>Hql(hibernate所带的面向对象sql)>EJBQL(HQL的子集)>QBC>QBE(QBC的子集)
1)HQL:http://blog.csdn.net/aaa1117a8w5s6d/article/details/775709
在具有关联的两个对象中,使用HQL的join速度更快更灵活。
2)QBC和QBE:http://blog.csdn.net/javaloveiphone/article/details/8179358;能说出来就行

6:,N+1问题:
1+N问题也可以叫N+1问题,什么是1+N问题呢?
如果在一个对象里关联另一个对象,并且fetch = FetchType.EAGER。
比如说ManyToOne(OneToMany也存在这种问题)关联,本来只需要取Many里的对象属性,可是Many里关联的对象都会单独再发一条语句取关联对象的属性。
本来只用发一条就可以查出Many里的对象属性,可是它发了一条语句后,再发N条语句取关联对象的数据。

解决办法:
1、fetch = FetchType.LAZY:在合适的时候才发出语句(按需要发语句)。
2、BatchSize:在One对象设置Size后,取出Many里的数据后,再发N/Size条语句取关联对象的数据,从而达到少发语句的目的。
3、Join Fetch:将Many与One做join连接,因此只要发一条语句就可以查出Many与其相关联的One对象数据,Criteria默认就是这种做法。
如何选择解决办法:
如果只要用Many里的对象,不用关联对象的属性,那就用方法1解决;
如果要Many里的对象属性,也想要关联的对象属性就用方法3解决。

7,一级缓存,二级缓存,条件缓存
一级缓存:session级别的缓存,每个session中有个hash表存放,为防止内存溢出,要经常用clear清理缓存。
二级缓存:SessionFactory级别的缓存,生命周期随SessionFactory由于一级缓存无法跨session访问,设定开启一个session共享的缓存。二级缓存靠中间件实现,可以放在内存或者本地硬盘上。二级缓存查不到就访问数据库。load默认使用二级缓存(开启的情况下)。二级缓存适合存放不经常变化的数据。

 Hibernate的二级缓存策略的一般过程如下:
  1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
  2) 把获得的所有数据对象根据ID放入到第二级缓存中。
  3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
  4) 删除、更新、增加数据的时候,同时更新缓存。

查询缓存:当查询的sql一样的时候,会调用查询缓存。说明白了就是存放由list方法或者iterate方法查询的数据,我们在查询时很少出现完全相同的条件查询,所以命中率不高。依赖于二级缓存,二级缓存的一种特殊情况。

8,隔离级别和悲观锁、乐观锁
事务并发的问题:
1)脏读:读了另外一个事务没有提交的数据。T1和T2并发,T1操作后还未提交,这时T2读取了T1操作后的结果继续操作,随后T1回滚,则T2的操作失败,因为T2读取了T1的脏数据。
2)不可重复读:在同一个事务中,对同一个数据前后读两回值是不一样的。
T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
3)幻读:其他事务进行插入或者更新操作影响了我读的结果。(增添或者删除操作,使得先查一个总数,又查一个总数,结果不同)

数据库隔离级别:
8 - Serializable 串行化:不要轻易使用,禁止并发。
4 - Repeatable Read 可重复读:根据具体情况考虑,幻读还会出现,mysql默认
2 - Read Commited 可读已提交:优先考虑,不会出现脏读,但其他的还出现。oracle默认
1 - Read Uncommited 可读未提交:三种问题都会出现

悲观锁:借助于数据库的锁。本质类似于并发的lock和sync,用于数据竞争激烈的环境。
乐观锁:CAS无锁同步算法。解决了长事务加锁后效率低下的问题。
hibernate中可以进行参数设定来启动这两种锁机制。

9,IBATIS与Hibernate的比较
1). iBATIS非常简单易学,Hibernate相对较复杂,门槛较高。
2). 当系统属于二次开发,无法对数据库结构做到控制和修改,那iBATIS的灵活性将比Hibernate更适合。
3). 系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。在这种情况下iBATIS会有更好的可控性和表现。
4). iBATIS需要手写sql语句,Hibernate则基本上可以自动生成,偶尔会写一些Hql。同样的需求,iBATIS的工作量比Hibernate要大很多。类似的,如果涉及到数据库字段的修改,Hibernate修改的地方很少,而iBATIS要把那些sql mapping的地方一一修改。hibernate的O/R映射能力强。
5),hibernate文档和产品更加完善。
总之:hibernate属于一站式,ibatis属于半自动

10,IBatis与JDBC的比较
1)代码量大大减少
2)sql与控制程序分离
3)移植性强,比如更换数据库时只更改配置文件就可以。

11,IBatis的配置实例

http://www.cnblogs.com/ycxyyzw/archive/2012/10/13/2722567.html

上面文档有需要注意的是

1)

Hibernate and IBatis - Garfield - 张广辉的博客

如上图更新语句中,输入的是Student的一个对象,而往数据库中插入的是对象的各个字段的值,所以sql中字段占位符的名字无必要与Student对象中字段的名字一直,这样系统才会自动调用get方法提取,否则报错。 

2)域模型类需要有一个无参的构造方法,因为框架会自动调用参方法动态构造对象。
0 0
原创粉丝点击