hibernate数据持久化组件
对象持久化,把数据保存在永久的存储介质中(数据库)
OR/M(object relationmapping)对象关系映射。
POJO类,就是标准的Java Bean。
Hibernate就是一个可以自动的根据xml完成对象关系映射,并持久化到数据库的开源组件。
Hibernate的底层也是有JDBC实现的。
hibernate是通过xml文件的配置,对数据库的底层的方言,以及数据库连接所需的信息,以及连接数据库的驱动。hibernate的系统配置文件的名字一般叫做hibernate.cfg.xml,
一般是映射类名加.hbm.xml。一般将映射类的xml文件和实体类放在一起。
hibernate.cfg.xml中会设置数据库的连接信息,以及引用的其他文件的文件名,和一些其他的摄制。这个文件一般放在项目的根目录下。
在hibernate.cfg.xml的写法
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/HibernateConfiguration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<propertyname="show_sql">true</property><!--显示sql语句-->
<propertyname="format_sql">true</property><!--使显示的sql语句格式化-->
<property name="dialect">....</property><!--使用的数据库方言信息-->
<propertyname="connection.driver_class">....</property>
<!--使用的数据库的驱动-->
<propertyname="connection.url">....</property><!--连接数据库使用的url-->
<propertyname="connection.username">...</property>
<!--连接数据库的用户名-->
<propertyname="connection.password">...</property>
<!--连接数据库的密码-->
<mappingresource="xxx/xxxx/Xxxxxx.hbm.xml"/>
<!--引入的映射对象的xml文件的全路径及文件名-->
</session-factory>
</hibernate-configuration>
hibernate的映射类的XXXX.hbm.xml的写法
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="XXX.XXX.XXX"><!--映射类所在的包-->
<classname="Xxxxxx" table="Xxxxx"><!--将类和数据库的表联系起来-->
<idname="studentId" column="studentId"><!--主键生成策略-->
<generatorclass="assigned"/>
<!--指定主键生成策略为用户指定-->
</id>
<propertyname="XXX" column="XXXX" type="string"/>
<!--类中的书性和字段之间建立联系-->
<property name="homeAddress"column="homeAddress"/>
<propertyname="schoolAddress" column="schoolAddress"/>
<propertyname="brithday" column="brithday"type="data"/>
<!--在hibernate中其他类型可以自动识别只有Data类型必须指名-->
</class>
</hibernate-mapping>
使用hibernate编程步骤
1,配置环境,加载hibernate的jar文件,以及连接数据库连接使用的jar文件,并配置CLASSPATH环境变量。
2,写hibernate所需的配置文件,hibernate.cfg.xml ,Xxxxx.hbm.xml
3,写POJO类
4,调用hibernate API。
1)使用Configuration对象的buildSessionFactory()方法创建SessionFactory对象
2)使用SessionFactory对象openSession()方法创建Session对象。
3)使用Session的相应方法来操作数据库,将对象信息持久化到数据库。
hibernate的配置文件hibernate.cfg.xml用于配置数据库的连接的信息,以及需要持久化的对象的xml映射文件的位置
在hibernate.cfg.xml中使用<mappingresource="xml/Student.hbm.xml">这种方式来指名要持久化对象的映射文件。
Configuration是用于解析hibernate.cfg.xml文件和XXXXX.hbm.xml文件,并产生SessionFactory对象。
SessionFactory是和一个数据库一一对应的,他只能对应一个hibernate.cfg.xml文件,一个hibernate.cfg.xml中只能配置一个数据库的连接信息。
POJO(普通的java类)
持久化对象和临时对象,持久化对象,即对象的信息在数据库中存在,在内存中也有。临时对象也就是新对象,没有同步到数据库。
Session,持久化管理器。
Hibernate的核心接口
1.Configuration,用于解析hibernate.cfg.xml文件和XXXXX.hbm.xml文件,并创建SessionFactory对象。
2.SessionFactory,用于创建Session对象。
3.Session,持久化管理器,对象级数据库操作
4.Query,对对象作持久化操作或查询操作
5.Transaction ,用于管理操作事务。
hibernate.cfg.xml中的标签
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/HibernateConfiguration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<propertyname="show_sql">true</property><!--显示sql语句-->
<propertyname="format_sql">true</property><!--使显示的sql语句格式化-->
<propertyname="dialect">....</property><!--使用的数据库方言信息-->
<propertyname="connection.driver_class">....</property>
<!--使用的数据库的驱动-->
<propertyname="connection.url">....</property><!--连接数据库使用的url-->
<propertyname="connection.username">...</property>
<!--连接数据库的用户名-->
<propertyname="connection.password">...</property>
<!--连接数据库的密码-->
<mappingresource="xxx/xxxx/Xxxxxx.hbm.xml"/>
<!--引入的映射对象的xml文件的全路径及文件名-->
</session-factory>
</hibernate-configuration>
对象映射文件
<hibernate-mapping package="XXX.XXX.XXX"auto-import="false"><!--映射类所在的包-->
<classname="Xxxxxx" table="Xxxxx"><!--将类和数据库的表联系起来-->
<idname="studentId" column="studentId"><!--主键生成策略-->
<generatorclass="assigned"/>
<!--指定主键生成策略为用户指定-->
</id>
<propertyname="XXX" column="XXXX" type="string"/>
<!--类中的书性和字段之间建立联系-->
<propertyname="homeAddress" column="homeAddress"/>
<propertyname="schoolAddress" column="schoolAddress"/>
<propertyname="brithday" column="brithday"type="data"/>
<!--在hibernate中其他类型可以自动识别只有Data类型必须指名-->
</class>
</hibernate-mapping>
id生成方式
1,序列sequence 只适用于Oracle
<id name="id" column="id">
<generatorclass="sequence">
<paramname="sequence">person_seq</param><!--指定sequence名-->
</generator>
</id>
2,自增列,适用于SQLServer
<id name="id" column="id">
<generatorclass="identity"/>
</id>
3,取最大值加一
<id name="id" column="id"type="integer">
<generatorclass="increment"/>
</id>
4,根据底层数据库指定生成方法
<id name="id"column="id">
<generatorclass="native"/>
</id>
针对Oracle数据库的生成方式还是sequence,只不过需要一个特定名字的sequence,"hibernate_sequence"。
5,高低位算法
<id name="id" column="id">
<generatorclass="hilo">
<paramname="table">high_value</param>
<!--设置高位值取值的表-->
<paramname="column">next_value</param>
<!--设置高位值取值的字段-->
<paramname="max_lo">50</param>
<!--指定低位最大值,当取道最大值是会再取一个高位值再运算-->
</generator>
</id>
类关联关系映射
一对一关系实现
建表策略
1,共享主键,也就是一方引用另一方的主键,作为自身的主键,也是外键。
2,外键引用,也就是一方引用另一方的主键,作为外键,并且对引用的外键加唯一约束。
一对多
建表策略,多方引用一方的主键当作外键
持久化对象,即就是在数据库中存有其相对应数据的对象,并且在内存中也有这个对象,这个对象在Session的管理范围内,也就是调用过save()方法同步到数据库的对象。
临时对象,即在内存中刚刚创建的对象,还没有同步到数据库,或者是数据库中信息被删除了的对象也是临时状态。
游离对象,也就是在数据库中有和该对象向对应的纪录,并且在内存中的也存在该对象,但是不在Session的管理范围之内,也就是在Session关闭之后,就成了游离对象,就不会在将其改变同步到数据库中,如果要使还想令其成为持久化对象就要在把它纳入Session管理中,也就是掉用Session中的update()方法就可以了。
及物的持久化,也就是说针对这个对象的属性进行持久化操作,也就是通过级联进行设置。
以下是一对多中一端set标签的设置
<set name="st" inverse="true"cascade="delete" batch-size="3">
<keycolumn="cid"/>
<one-to-manyclass="Student"/>
</set>
inverse="true"就是在设置如果在内存中的修改或添加了这个集合中的某一个或某几个对象他不会将全部集合的信息同步到数据库,而是只将集合中被修改的对象重新同步到数据库。
cascade属性是设置级联操作的也就是在操作一端的数据如果影响到多端数据时会进行级联操作,
cascade="none",cascade="save-update",cascade="delete",cascade="all"cascade="persist"
cascade="delete-orphan",cascade属性的值常用的设置为以上五项:
none就是不使用级联操作,默认级联是none。
save-update也就是只有对象保存操作(持久化操作)或者是持久化对象的更新操作,才会级联操作关联对象(子对象)。
persist就只是将级联对象也持久化到数据库。
delete对持久化对象的删除操作时会进行级联操作关联对象(子对象)。
all对持久化对象的所有操作都会级联操作关联对象(子对象)。
all-delete-orphan,在多端进行删除操作时,会再多端表中留下null空纪录,设置了级联操作为delete之会将表中表示关联的外键id置成null,不会将这条纪录也删除掉,而把级联设置成delete-orphan就不会留有空纪录,而是级联的把相关纪录删除掉。
batch-size这个属性只能够写在set标签中,这个属性带表批量加载,也就是在加载一端的集合属性时会一次加载指定的数量的对象,而不是默认的一个一个的加载,会提高效率,批量加载只能用于延迟加载和立即加载策略,也就是(lazy="true"或者lazy="false")。
lazy="true"延迟加载,所谓的延迟加载,就是对一端的集合属性的加载策略,就是在不使用到集合中的对象的数据就不会真正的加载集合中的对象数据,而是家在一个代理对象就相当于的一个空的容器。这也就是会出现LazyInitializationException异常,也就是没有初始化这个代理的集合对象,在事先查询到了集合中的对象就会初始化这个对象,如果Session没有关闭就会在查询加载集合中的对象信息,如果提前关闭了Session,当使用集合中的对象信息时就会有这个异常。
fetch="join",这就是使用了预先抓取策略,也就是针对关联的对象的加载策略,在使用到关联对象的信息时会再发送sql语句,如果不使用fetch="join",就会不使用表连接而是先查出一端的关联id再一条一条的发送sql语句查询到关联对象信息,使用了fetch="join"就会使用表连接将关联对象信息直接查寻出来的。fetch="lazy"这个是默认的设置。
注意:
在使用fetch="join"要区分开他和外连接的区别,他不会忽略配置文件中的加载策略,而使用了外连接就会忽略配置文件中使用了外连接的一端的所有加载策略,而替之为立即加载。
例:班级 tream,身份证 Certigicate 学生 student
身份证和学生是一对一关系,班级和学生是一对多的关系。学生对身份证的加载策略是预先抓取,学生对班级是预先抓取,但是班级对学生是延迟加载。
现在使用了外连接
Query q=session.createQuery("from Student as s left joins.team");
as 的语法是取别名的语法。
也就是使用了外连接的来查寻班级,这样就会忽略,学生对象对其所有属性除了使用外连接查寻的属性,而其余都会使用立即加载。
<property name="" column="" type=""not-null="true">,这样也就会使这个属性不能够为空值
查询对象,可以使用get()和load()方法,不过前提是必须知道该对象持久化时的唯一标识,也就是id,和这个对象的类对象。
hibernate的HQL中的select和update语法
select 别名 from 类全名 别名 where 别名.类属性=:变量名
如果要查寻全部可以简写为from 类全名
update 类全名 set 属性名=:变量名 where 属性名=:变量名
注意以上这些语句要在createQuery("...")中。
多对多的映射实现
一般多对多关联会拆分成两个一对多的关系来实现多对多关系,也可以通过hibernate提供的解决方案来实现。其实hibernate的实现方式是通过中间表间接的实现了多对多关系,实际上也是将多对多拆分成两个双向的一对多关系。
多对多关系XML文件的配置
<hibernate-mapping>
<class name="Course" table="course">
<set name="clazz"table="class_course" inverse="true"><!--设置中间表的表名-->
<keycolumn="courseid">
<many-to-manycolumn="classid" class="Clazz"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="Clazz" table="class">
<setname="course" table="class_course"cascade="save-update">
<keycolumn="classid"/>
<many-to-many column="courseid"class="Course"/>
</set>
</class>
</hibernate-mapping>
类继承关系映射
建表策略
1.所有类建一个表,只为具体类建表,每个类建一个表。
2.只为具体类建表,使用于不使用多态的情况下,具体类之间没有继承关系时适用
3.需要针对每个类写映射配置文件,就和普通的单表映射的xml文件相同。
4.也可以使用一个xml文件来进行映射,可以通过写union-subclass标签来表现其关系
5.这里不能使用id生成策略中的native,而是要指定特定的生成策略。
例:
<union-subclass name="notpad"table="tpcc_notpad">
<property name="wight" column="wight"type="integer"/>
</union-subclass>
<union-subclass name="desktop"table="tpcc_desktop">
<propertyname="LCD" column="isLCD" type="yes_no"/>
</union-subclass>
每个类建一个表,可以有效减少数据的冗余,减少字段,查询效率不很高。
正对每个类建一个表,只要写一个配置文件来进行类的映射即可
映射文件中的子类可以使用join-subclass标签来表示,并且引用父类的主键作为共享主键,就是不需要指定id生成策略
例:
<hibernate-mapping package="alan.hbn.rel.inherit"auto-import="false">
<classname="Computer" table="tph_computer">
<idname="comid" column="comid" type="long"unsaved-value="0">
<generatorclass="identity"/>
</id>
<propertyname="price" column="price" type="integer"/>
<joined-subclassname="notpad" table="tpc_notpad">
<key column="comid" />
<property name="wight"column="wight" type="integer"/>
</joined-subclass>
<joined-subclassname="Guest" table="tpc_guest">
<key column="comid"/>
<property name="LCD"column="isLCD" type="yes_no"/>
</joined-subclass>
</class>
</hibernate-mapping>
所有类只建一个表,查寻效率比较高,但是会产生很多空间浪费,当子类中的非空约束,就不大适用了,这是对于子类可以使用subclass标签表示。
<hibernate-mapping package="alan.hbn.rel.inherit"auto-import="false">
<classname="Computer" table="tph_computer">
<idname="id" column="id" type="long"unsaved-value="0">
<generatorclass="identity"/>
</id>
<discriminatorcolumn="computer_type" type="integer"/>
<propertyname="price" column="price" type="integer"/>
<subclassname="Administrator" discriminator-value="ad">
<propertyname="wight" column="wight" type="integer"/>
</subclass>
<subclass name="Guest"discriminator-value="gu">
<property name="LCD"column="isLCD" type="yes_no"/>
</subclass>
</class>
</hibernate-mapping>
不考虑多态时,最好是用只针对具体类建表,而考虑多态时尽量使用所有类建一个表,只有当子类中的属性过多是才考虑每个类建一个表的策略。
Hibernate控制的事务
事务保证原子操作的不可分,也就是操作的同时成功或同时失败。
Transactiontran=session.beginTranaction();
tran.commit();
tran.rollback();
以上是事务对象的方法,来实现对事务的支持。
hibernate的事务隔离级别
hibernate的事务隔离级别和JDBC中大致相同。
设置时要在hibernate.cfg.xml配置
<propertyname="hibernate.connection.isolation">4</property>
1,读未提交的数据(Read uncommitted isolation)
2,读已提交的数据(Read committed isolation)
4,可重复读级别(Repeatable read isolation)
8,可串行化级别(Serializable isolation)
hibernate的锁(悲观锁,乐观锁)
悲观锁是由数据库本身所实现的,会对数据库中的数据进行锁定,也就是锁行。
LockMode.UPGRADE,修改锁,在get()方法中加上这个设置作为第三个参数。
LockMode.NONE 无锁机制
LockMode.READ 读取锁
LockMode.WRITE 写入锁,不能在程序中直接使用
还可以使用Session.lock()Query.setLockMode() Criteria.setLockMode()方法来设置锁
乐观锁,也就是通过对记录加上某些信息来解决并发访问的问题。
版本检查
要在其表中多加上一列表示版本信息,会在读取时读到这个版本号,并在修改之后更新这个版本号,并且只有版本号相同才会予以更新,如果版本号低,就会抛出例外。
<versionname="version" column="version" type="integer"/>
时间戳
使用时间戳,是通过最后修改时间来判断是否来做更新操作,也就是只有在最后更新时间之后才会做更新。
<timestampname="updateTime" column="updatetime"/>
hibernate组件映射
组件不会生成唯一标识,但是也需要对应实体类。
hibernate中可以把一个类的对象当作一个属性组件来使用,并且在使用时会自动创建,所以同一组件对象是不会被两次引用的。
例:
<hibernate-mappingpackage="alan.hbn.rel.inherit" auto-import="false">
<class name="Guest"table="guest">
<id name="id"column="id" type="long" unsaved-value="0">
<generatorclass="native"/>
</id>
<propertyname="userName" column="userName"type="string"/>
<propertyname="password" column="pwd" type="string"/>
<propertyname="birthday" column="birthday"type="date"/>
<componentname="homeAddress" class="Address">
<propertyname="street" column="street"type="string"/> <propertyname="zipcode" column="zipcode" type="string"/> </component>
</class
</hibernate-mapping>
hibernate的HQL(hibernate Query Language)
HQL是hibernate的查询语言,他可以支持面向对象的查询。使用HQL语句,只能通过session.createQuery("...")。
使用hibernate分页显示,使用Query对象的setFirstResult(int firstResult)(firstResult从零开始)方法和setMaxResults(int maxResults) 方法。他会根据不同的底层数据库来显示指定数量的记录。