您的位置:首页 > 其它

Hibernate学习总结--入门2

2015-07-29 22:58 295 查看
关于Hibernate API的几个主要接口

1.Configuration:hibernate的配置对象,主要用于读取配置,解析配置,然后创建SessionFactory实例.

2.SessionFactory:该接口对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存,查询缓存。负责创建Session对象.

3.Session:提供了和持久化类相关的操作,因此被称为持久化管理器.

4.Transaction:数据库事务接口,对底层的事务接口做了封装.

5.Query:查询接口,用于向数据库查询对象,以及控制执行查询的过程.

主键生成策略:(主键分为代理主键与自然主键)--总结自(Hibernate逍遥游记)

代理主键:

increment标识符生成器:

由Hibernate以递增的方式为代理主键赋值.

Hibernate仅运行在单个应用服务器上,该生成器才能有效工作.

适用范围:

1.increment标识符的机制不依赖与底层数据库系统,所以适合于所有的数据库系统.

2.适用于只有单个Hibernate应用进程访问同一个数据库的场合.

3.OID必须为long,int或short类型,如果为byte,在运行时会抛出异常IdentiferGenerationException

identity标识符生成器:

由底层数据库来负责生成标识符,要求底层数据库把主键定义为自动增长字段类型

适用范围:

1.由于其依赖底层数据库系统,所以要求底层必须支持自动增长字段类型,不适合于所有的数据库系统.

2.OID必须为long,int或short类型,如果为byte,在运行时会抛出异常IdentiferGenerationException

sequence标识符生成器:

利用底层数据库提供的序列来生成标识符.

适用范围:

1.由于依赖于底层数据库系统的序列,所以要求底层必须支持序列,不适合于所有的数据库系统.

2.OID必须为long,int或short类型,如果为byte,在运行时会抛出异常IdentiferGenerationException

hilo标识符生成器

由Hibernate按照一种high/low算法自动生成标识符,从数据库的特定表的字段中获取high值.

适用范围:

1.由于不依赖底层数据库系统,所以适用于所有的数据库系统.

2.OID必须为long,int或short类型,如果为byte,在运行时会抛出异常IdentiferGenerationException.

3.high/low算法生成的标识符只能在一个数据库中保证唯一.

4.当用户为Hibernate自行提供数据库连接,或Hibernate通过JTA,从应用服务器的数据源获得数据库连接的时候无法使用hilo,所以不能保证hilo单独在新的数据库连接的事务中访问hi_value表(特定表)

native标识符生成器:

依据底层数据库对自动生成标识符的支持能力来选择使用identity,sequence或者hilo.

其能自动判断底层数据库提供的生成标识符的机制.

适用范围:

1.由于其能根据底层数据库系统的类型自动选择合适的标识符生成方式,所以适合于跨数据库平台开发.

2.OID必须为long,int或short类型,如果为byte,在运行时会抛出异常IdentiferGenerationException

自然主键:具有业务含义的主键

assigned标识符生成策略:表示由应用程序为自然主键字段赋值.

*映射关系之单向多对一

1.在上次项目中对t_student表增加一个字段sclass_id,并在数据库中建立t_grade表,字段为(cid,cname,cloctioon,cstreet)由于当时建的是t_class,想起class是关键字,故而改了表名,但是加了数据于是字段就没改.增加外键关系(sid对应cid).

这样就形成了多对一的关系,多个学生对应一个班级,所谓单向多对一就是在Hibernate中只在多方配置多对一关系.

2.根据表建立持久化类Student,Grade如下:

public class Student {
private Long id;
private String name;
private Integer age;
private String gender;

//外键关联
private Grade grade;

//省略getter,setter....
}
public class Grade {
private Long id;
private String name;
private String location;
private String street;

//省略getter,setter.....
}
3.创建映射配置文件,配置如下

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件 -->
<hibernate-mapping package="org.zy._01_hibernate.domain">
<!-- 配置Student 多方-->
<class name="Student" table="t_student">
<!-- 配置主键 -->
<id name="id" column="sid">
<generator class="native" />
</id>

<!-- 其他属性 -->
<property name="name" column="sname"/>
<property name="age" column="sage"/>
<property name="gender" column="sgender"></property>

<!-- 单向多对一 -->
<!-- 多个学生对应一个班级 -->
<!-- name对应属性名 -->
<many-to-one name="grade" column="sclass_id" class="Grade" />
</class>

<!-- 配置班级  一方-->
<class name="Grade" table="t_grade">
<id name="id" column="cid">
<generator class="native"/>
</id>

<property name="name" column="cname"/>
<property name="location" column="clocation"/>
<property name="street" column="cstreet"/>
</class>
</hibernate-mapping>
4.创建数据库配置文件:

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 根节点:代表Hibernate的配置,对应于Hibernate的类Configuration -->
<!-- 在当前配置文件里面可以不写hibernate. -->
<hibernate-configuration>
<!-- session-factory代表会话工厂,对应于Hibernate的类SessionFactory,创建Session对象 -->
<!-- hibernate4.x:需要删除name="foo"如果不删除,运行会报错 -->
<session-factory>

<!-- 连接数据库必须配置内容:4个 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernatedb</property>
<property name="connection.username">root</property>
<property name="connection.password">QNmd12980</property>

<!-- 配置其他信息 -->
<!-- 必须配置的1个方言:实现数据库移植:分页语句,主键生成 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 可选配置 -->
<!-- property属性配置 -->
<!-- 是否自动创建表,不写默认为none -->
<property name="hbm2ddl.auto">validate</property>
<!-- 是否显示sql语句 -->
<property name="show_sql">true</property>

<!-- 是否显示格式化sql语句 -->
<!-- <property name="format_sql">true</property> -->

<!-- mapping加载映射文件 -->
<!-- 加载属性resource->xml,路径必须是文件路径 -->
<mapping resource="org/zy/_01_hibernate/domain/domain.hbm.xml" />
</session-factory>
</hibernate-configuration>


5.编写测试类

package org.zy._01_hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import org.zy._01_hibernate.domain.Grade;
import org.zy._01_hibernate.domain.Student;
import org.zy._01_hibernate.util.HibernateUtils;
@SuppressWarnings("all")
public class Many2oneTest {

@Test
public void testSave1() {
Session session = HibernateUtils.INSTANCE.getSession();
Transaction tx = null;
try {
//保存时应该先保存一方,然后保存多方
tx = session.beginTransaction();
Grade grade = new Grade("元魔门","云川岛","岛内某地");//临时状态

Student stu = new Student("寒梨",20,"男");
stu.setGrade(grade);//处理外键,保证grade的id不为null

session.save(grade);//id!=null
session.save(stu);

tx.commit();
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
}finally{
if (session != null) {
session.close();
}
}
}

@Test
public void testSave2() {
Session session = HibernateUtils.INSTANCE.getSession();
Transaction tx = null;
try {
//演示TransientObjetException异常
//解决方案使用级联,在保存多方时一起保存一方
tx = session.beginTransaction();
Grade grade = new Grade("元魔门","云川岛","岛内某地");//临时状态

Student stu = new Student("寒梨",20,"男",grade);

session.save(stu);

tx.commit();
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
}finally{
if (session != null) {
session.close();
}
}
}

@Test
public void testSave3() {
Session session = HibernateUtils.INSTANCE.getSession();
Transaction tx = null;
try {
//演示脏数据更新
tx = session.beginTransaction();
Grade grade = new Grade("元魔门","云川岛","岛内某地");//临时状态

Student stu = new Student("寒梨",20,"男");
stu.setGrade(grade);//处理外键,保证grade的id不为null
//先保存多方后保存一方
//会比testSave1()方法多出一条update于语句(update t_student set sname=?, sage=?, sgender=?, sclass_id=? where sid=?)
session.save(stu);
session.save(grade);

tx.commit();
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
}finally{
if (session != null) {
session.close();
}
}
}
}
testSave2()抛出的TransientObjectException异常是因为执行session.save(stu)时,stu由临时状态变成了持久状态,成为持久化对象,而Hibernate不会自动持久化与stu相关联的grade对象,所以grade还处于临时状体,这就是说session.save(stu)只是向数据库中插入了一条数据,并且这个数据的sclass_id为null.

stu作为持久化对象后会位于Session的缓存中,当调用事务的commit()方法时会先清空缓存中的持久化对象,于是抛出了该异常.

解决方案:使用级联保存和更新(cascade属性):

当Hibernate持久化stu对象时会自动持久化其所关联的grade对象

脏数据并不是废弃和无用的数据,而是状态前后发生变化的数据。

补充:
临时状态/瞬时状态(transient):刚用new语句创建,没有被持久化,不处于session中。

持久化状态/托管状态(persistent):已经被持久化,加入到session的缓存中。session没有关闭,该状态的对象为持久化对象。

游离状态/脱管状态(detached):已经被持久化,但不处于session中。


删除状态(removed):对象有关联的ID,并且在Session管理下,但是已经被计划(事务提交的时候,commit())删除。如果没有事务就不能删除
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: