Hibernate 是J2EE 持久层框架
何为框架?个人理解为底层技术不用程序员自己编写写代码实现,程序员只需要关注API的使用和配置文件的书写
HIbernate框架结构如下所示:
目前最新Hibernate版本4.3.5
Hibernate 的主要认识从API、映射文件、性能三方面
一、Hibernate的API
主要有:1、读取cfg配置文件 Configuration 主要通过configure读取总配置文件信息
2、得到SessionFatory对象 通过Configuration 对象的buildSessionFactory创建SessionFactory实例,4版本之前可以通过cfg.buildSessionFactory直接创建,但是4版本以后,需要创建ServiceRegistry 实例对象ServiceRegistry sr=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();,然后通过cfg.buildSessionFactory(sr)来得到SessionFatory实例。
3、获取Session 实例对象 Session session=sf.openSession();
4、在操作session过程中如果有事物产生,通过session.beginTransaction()得到Transaction 得到实例对象,对增、删、改进行事物操作
5、在操作完所有事物后,需要对session进行关闭。
通过session进行增删查改操作
1、查询单个对象 session.get(XX.class,id); session.load(XX.class,id) 懒加载
2、通过HQL 语句查询 ,主要涉及参数的传递
A、通过设置下标传递,如:“select from Order o where o.name=?” session.createQuery(hql).setParameter(0,name);
B、通过名称来传递,如:“select from Order o where o.name=:name” session.createQuery(hql).setParameter(“name”,name);
C、通过Map集合来传递多个参数
D、通过对象来传递多个参数
3、增加单个对象 session.save();
4、更新单个对象 session.update();
5、删除单个对象 session.delete();
二、Hibernate的映射文件
1、cfg配置文件
hinbernate.cfg.xml
标签主要涉及<session-factory> 及<property>
主要对property进行映射,主要设计内容为:
<property name="connection.driver_class">JDBC驱动</property>
<property name="connection.url">数据库连接的url</property>
<property name="connection.name">连接数据库的用户名</property>
<property name="connection.password">连接数据库的密码</property>
方言:即用的是什么数据库
<property name="dialect"></property>
其它参数配置,如是否显示sql语句 等等
<property name="show_sql">true</property>
<property name="format_sql">true</property>
导入映射文件
<mapping resource="要导入的映射文件" />
2、hbm映射文件
hbm映射文件主要是实体bean对象和数据库中列名一一对应的配置文件
主要标签涉及<class > <id> <property> <one-to-one> <set> <many-to-one> <one-to-many> <many-to-many>
class标签,属性主要涉及: name :对应哪个实体对象类 , table :数据库中对应的表 , optimistic-lock :乐观锁模式 ,值可以是dirty (脏数据) ,version(版本机制)
id标签,主要涉及属性有 name:实体对象的标号属性(一般是id),column:对应数据库中的主键列
generator标签,主要属性是class ,class 取值可以为identity(主键自增长),increment(数据库中主键没有设置主键自增长,hibernate根据当前数据库中主键的值,自动给数据库主键增长值),uuid(随机分配不重复的字符串),assigend(程序员自己手动分配的值),sequence(序列,在ORACLE数据库中,程序员只需创建序列)
property标签,主要属性是name:对应实体对象的属性,column:对应数据库中表的列名 ,type :数据类型,unique:是否唯一。
在项目实际关系中,对象与对象往往会存在很多种复杂关系,主要是一一对应,一对多,多对一,多对多关系,自关联关系,继承关系
一一对应关系(列如 丈夫与妻子):主键关联及唯一外键关联
主键关联:在数据库中体现为从表的主键取决于主表的主键,在实体对象中是(我有一个唯一的你,你有一个唯一的我)
在映射文件中体现:<one-to-one name="丈夫实体对象属性" class="妻子的类名" cascade=""></one-to-one>
在从表的映射文件中<generator>标签class属性设置为foreign <parm name="property">在妻子对象中对应的丈夫类属性名</parm>
cascade:级联关系:表示在对当前对象属性进行操作的时候,和该对象有关系的对象进行相关的级联操作。
唯一外键关联:
主表对应实体对象映射文件:<many-to-one name="wife" class="" column="fk_wife_id" cascade="all" unique="true"></many-to-one>
从表对应实体对象映射文件:<one-to-one name="husband" cascade="all" class="com.lovo.one2one.Husband" property-ref="wife"></one-to-one>
一对多对应关系(一个客户有多个订单)
客户类映射文件:
<set name="orders" table="t_order" cascade="all" inverse="true">
<key column="fk_custmoer_id"></key>
<one-to-many class="com.lovo.one2many.Order"/>
</set>
订单类映射文件:
<many-to-one name="custmoer" class="com.lovo.one2many.Customer" cascade="save-update" column="fk_custmoer_id" ></many-to-one>
多对多对应关系(玩家和武器),需要中间表进行关联
在映射文件中对应关系体现为
<set name="weapons" table="中间表名字" cascade="save-update" inverse="true">
<key column="fk_user_id"></key>
<many-to-many class="com.lovo.many2many.Weapon" column="fk_weapon_id"></many-to-many>
</set>
自关联关系(对象中的子对象也是该类的实体),在映射中体现为既有一对多关系也有多对一关系
三、性能操作
性能操作主要从延迟加载、缓存处理、事物锁来体现
延迟加载:用hibernate进行数据查询的时候,如果对象属性中有其他类的对象属性和集合的时候,不会直接查询出这个属性,而是当需要的时候,再去进行查询,以减少内存的开销。但是如果我们在关闭session以后,再想得到对象属性,将会报无法连接session异常。
改变延迟加载的方法有:
1、在映射文件中加上 Lazy 属性,Lazy="false" ,但是这样会大量消耗内存
2、在映射文件中加上fetch 属性,fetch="join"
3、通过Hibernate提供的Hibernate.initialize 方法进行主动加载
4、直接在HQL 文件中加上 left join fetch 语句进行查询。
个人习惯用第三种和第四中方法改变延迟加载。
缓存:缓存是介于内存和物理存储的介质。
Hibernate 主要分为一级缓存及二级缓存,一级缓存是基于Session,即一旦开启session,一级缓存默认开启。二级缓存是由SessionFactory实现,默认没有开启,需要导入其它组件。主要有Ehcached、OSCache、JBoss(服务器集群)、SwarmCache(服务器集群)
在应用二级缓存的时候,首先要在cfg.xml配置文件中开启二级缓存及配置二级缓存属性
<property name="hibernate.cache.EhCacheProvider" >true</property>
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
<property name="hibernate.cache.use_query_cache" >true</property>
然后需要配置缓存属性(单独的配置文件)
<ehcache>
<diskStore path="d:/cache"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="100"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120" />
</ehcache>
最后需要在映射文件中设置缓存策略(需要用到二级缓存的配置文件中)
<cache usage="read-write" />
read-only:只允许读,read-wite:读和写
或者在cfg.配置文件中指定,在最后写!
<class-cache usage="read-only" class=""/>
二级缓存适合长期保持一致的数据
事物锁机制:在进行事物操作的时候,不能对正在进行操作的数据进行事物操作
悲观锁:正在对表进行查询操作的时候,对数据进行锁住。
通过session.get(Order.class,1,LockOptions.UPGRADE) 单个查询进行上锁
通过 session.CreateQuery(hql).setLockOptions(LockOptions.UPGrADE).list() 对多个数据进行上锁
悲观锁在对数据进行查询的时候,就对数据进行上锁
乐观锁是在对数据进行事物操作的时候,才对数据惊喜上锁
乐观锁主要有三个方法进行实现:
A、乐观锁 version机制,在实体对象中增加version 属性,在表中增加f_version列
B、通过胀数据机制,在Mapping 映射中设置
optimistic-lock="dirty" dynamic-update="true"* 来设置锁机制
C、通过时间戳的机制,在实体对象中新增Timestamp(时间戳)属性,在表中增加t_ts列
总结:Hibernate虽然减轻了程序员的代码复杂性,而且计较智能。但是在性能操作方面,特别是大批量数据操作的时候,Hiberrnate并没有优势,需要重多方面去考虑Hibernate的性能,如果有大批量的数据操作,建议直接通过session.doWork()操作SQL 语句。