JavaEE学习笔记之SSH—Hibernate(2)

对象关系映射

ORM 解决的主要问题就是对象-关系的映射,域模型和关系模型都分别建立在概念模型的基础上,域模型是面向对象的,关系模型是面向关系的,一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录。 (可能存在类中多个属性对应一列的情况,映射组成关系)

ORM中间件采用元数据来描述对象-关系映射细节,元数据通常采用XML格式,并且存放在专门的对象-关系映射文件中,如果希望把ORM软件集成到自己的java应用中,用户首先要配置对象-关系映射文件(**.hbm.xml)。

session.save(customer)

执行过程:

1)运用反射机制,获得customer对象的类型Customer.class

2)参考对象-关系映射元数据,了解Customer类对应的表,以及属性对应的列,Customer类和其他类关系。

3)根据以上映射信息,生成SQL语句
  insert into h_customer values(id,name,password,telphone);
4)调用JDBC API,执行以上的SQL语句。

JDBC与Hibernate比较

1,JDBC: java中嵌入SQL,不便于维护

Hibernate: 无须编写SQL语句;由Hibernate通过读取映射文件在运行时自动生成SQL

save(student)-> insert into customer values(?,?,?);

2,JDBC:查询数据,需要手动封装成对象;保存对象,需要手动插入值

Hibernate: 可自动实现对象和表中记录的转换

3,JDBC:查询内存中已存在的对象,修改属性值,均需要和数据库进行交互

Hibernate:通过Dirty checking(脏检查)避免交互;

Hibernate的工作原理

1,Hibernate框架根据hibernate.cfg.xml的配置的信息来和数据库进行通信

2,Hibernate框架根据具体的映射文件**.hbm.xml 来保存,更新,删除,查询对象。

Hibernate API

Configuration接口:

Configuration对象用于配置并且根启动Hibernate,Hibernate应用通过Configuration实例还指定对象-关系映射文件的位置或者动态配置Hibernate的属性,然后创建SessionFactory实例

Configuration config = new Configuration();
Config.configure();
SessionFactory factory = config.buildSessionFactory();
SessionFactory 

用来构造Session的实例对象,它的特点:

1)线程安全: 该实例对象可以被多个线程共享

2)重量级:该实例对象的构造和销毁消耗系统资源,所以一般在应用程序启动的时候就构造实例对象,一般一个数据库对应一个SessionFactory的实例对象,如果要访问多个数据库,就需要创建多个该实例对象。

3)SessionFactory实例对象中维护了一个很大的缓存,存放了一些预定义的SQL语句和XML配置文件的信息,另外还维持了一个Hibernate的第二级缓存(缓存了所有Session对象所加载的POJO对象),用来保存在该生命周期中的一些业务对象,但是这个第二级缓存默认是关闭的,必须在xml中配置才可以开放

Session session = factory.openSession();

Session(别名:持久化管理器)

用来对对象的保存,更新,删除和查询

特点:

1)线程不安全,要避免同一个Session对象被多个线程共享,一般一个线程对应一个Session

2)轻量级:可以随意的构造和销毁该实例对象。

3)Session对象中维护了一个缓存,称为Hibernate的第一级缓存(缓存了当前Session对象所加载的POJO对象)每个Session对象都有自己的缓存。

Query

用来查询单个或者多个对象,利用HQL语句(Hibernate Query Language)面向对象的

Query query = session.createQuery("from Student where studentId=1");
Student s = (Student)query.uniqueResult();

Criteria

功能同上,以面向对象的形式和数据库进行复杂的CRUD操作,还适用于动态查询。

Transaction

用来处理事务的,事务的启动,提交,回滚

OID

在java语言中,按照内存地址来识别或区分同一个类的不同对象,关系型数据库按主键值来识别或区分同一个表的不同记录,Hibernate使用OID来统一两者之间的矛盾,OID是关系数据库中的主键(通常为代理主键)在java对象模型中的等价物。在运行时,Hibernate根据OID来维持java对象和数据库表中记录的对应关系。

为了保证持久化对象的OID的唯一性和不可变性,通常由Hibernate或底层数据库来为OID赋值,可以将OID的setId()方法设置为private类型,以禁止java应用程序随便修改OID。

<generator>子元素用来设定标识符生成器

Hibernate提供了标识符生成器接口:

net.sf.hibernate.id.IdentifierGenerator,并且提供了很多内置实现。

net.sf.hibernate.id.IdentityGenerator     --缩写名-- identity

net.sf.hibernate.id.IncrementGenerator   --缩写名-- increment

主键生成方式

1,increment

其生成方式与底层数据库无关,大部分数据库都支持,该方式的实现机制是在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为转。其不足之处是当多个线程并发对数据库表进行写操作时,可能出现相同的主键值,发生主键重复的冲突,所以在多线程并发操作的时候不应该使用该方法。

<generator class="increment" />

2,identity:

与底层数据库有关,要求数据库支持Identity,如MySQL中auto_increment,SQL Server中的identity。支持的数据库有MySQL,SQL Server,DB2,Sybase,但是不支持oracle.支持并发。

<generator class="identity" />

3,assigned

主键由外部程序负责生成,无需Hibernate参与。—-如果要由程序代码来指定主键,就采有这种。

<generator class="assigned" />

4,sequence

使用序列生成主键,需要底层数据库支持

在数据库中建一个序列

create sequence seq_name increment by 1 start with 1;

在映射文件中指定使用序列的名字

<generator class="sequence">
       <param name="sequence">seq_name</param>
</generator>

5,hilo

通过hi/lo算法生成主键,需要一个表来保存主键的信息,

在数据库中建一张表:

create table hi_value(next_hi number not null);
insert into hi_value(next_hi) values(1);
commit;

映射文件中需要指明这些表信息

<generator class="hilo">
       <param name="table">hi_value</param>
       <param name="column">next_hi</param>
       <param name="max_lo">100</param>
</generator>

6,seqhilo

与hilo 类似,通过hi/lo 算法实现的主键生成机制,

只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库,

在数据库中建一个序列

create sequence seq_name increment by 1 start with 1;
<generator class="seqhilo">
    <param name="sequence">seq_name</param>
    <param name="max_lo">100</param>
</generator>

7, native:

由Hibernate根据不同的数据库方言,

自行判断采用identity、hilo、sequence其中一种作为Hibernate主键生成方式,native的 优点是与底层性无关,便于不同数据库之间的移植,由Hibernate根据不同数据库选择主键的生成方式。在oracle中需要创建叫 Hibernate_sequence名字的sequence,如果设置了Hibernate.hbm2ddl.auto属性,不需要手动建立序列,前提 是数据库帐号必须有Create Sequence这种高级权限。mysql等数据库则不用建立sequence。

 <generator class="native" />

8,foreign

外键生成方式,依赖其他表的主键,在主键一对一映射中需要使用到

<generator class="foreign>
  <param name="property">husband</param>
</generator>

9,uuid.hex:

采用基于128位的算法生成唯一值,并编制成32位长度的唯一字符串作为主键值,uuid.hex的优点是支持大部分数据库,缺点就是要占用较大的存储空间。对于并发Insert要求较高的系统,推荐采用uuid.hex 作为主键生成机制。

<generator class="uuid.hex" />

10,uuid.string:

使用UUID算法,UUID被编码为一个16个字符长的任意ASCII字符组成的字符串。不能在PostgreSQL数据库中使用。uuid.string同uuid.hex类似,需要占很大的存储空间。

11,select

使用触发器生成主键(主要用于早期的数据库主键生成机制,少用)

hibernate内置映射类型

Hibernate的类型映射类型从总体上可以分为两种:内置类型映射和客户类型映射。

内置类型映射负责把一些常见的java类型映射到sql类型

客户类型映射可以将用户定义的java类映射到数据库表的相应字段。

内置类型映射:

(1) Java基本类型的Hibernate映射:

(2) Java时间和日期类型的Hibernate的类型映射:

运行实例:

<property name=”name” column=”Name” type=”string”/>
 <property name=”birthday” column=”Brithday” type=”date”/>
 <property name=”registereddate” column=”Registereddate” type=”timestamp”/>

下图为以上配置对应的数据库表:

(3) JDK自带的个别Java类的Hibernate映射类型:

注:

一个java类型对应多个Hibernate映射类型的场合。例如,如果持久化类的属性为java.util.Date类型,对应的Hibernate映射类型可以是date,time或timestamp。此时必须根据对应的数据库表的字段的SQL类型,来确定Hibernate映射类型。如果字段为Date类型,则hibernate映射为date,如果为TIME则为time,如果为TIMESTAMP则为timestamp。

客户类型映射:

以下例子可以把User类的Integer类型的phone属性映射到user表的varchar类型的phone字段

User.java

public class User implements Serializable{
    private static final long serialVersionUID = -5925415258301826484L;
    private Long id;
    private String name;
    private Integer phone;
    private Date birthday;
    private Timestamp registerTime;
    public User() {
        super();
    }
    public User(Long id, String name, Integer phone, Date birthday,
            Timestamp registerTime) {
        super();
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.birthday = birthday;
        this.registerTime = registerTime;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getPhone() {
        return phone;
    }
    public void setPhone(Integer phone) {
        this.phone = phone;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Timestamp getRegisterTime() {
        return registerTime;
    }
    public void setRegisterTime(Timestamp registerTime) {
        this.registerTime = registerTime;
    }

}

注意:这个类要实现序列化接口

JAVA类的数据 ,如果要进行相关的存储工作(如写文件,网络传输,写数据库等),那么这个数据的类 就必须实现序列化接口 (java.io.Serializable). 

序列化 :  把对象转换 为二进制数据(如网络传输,存储数据库等),必须实现序列化接口 (java.io.Serializable).

持久化 :  把对象保存 在介质上(如写文件,读文件不是), 没有接口实现,一般指方法调用. 

数据的持久化是序列化的又一个典型的应用,对象只有在序列化之后才能进行持久化存储,从持久化存储介质加载的数据通过反序列化转变成运行时对象。

user.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.briup.test">
    <class name="User" table="user" dynamic-insert="true" dynamic-update="true">
        <id name="id" column="id" type="long">
            <generator class="native" />
        </id>
        <property name="name" column="name" type="string" not-null="true" />
                <!-- 自定义类型映射 -->
                <property name="phone" column="phone" type="com.briup.test.PhoneUserType" not-null="true" />
        <property name="birthday" column="birthday" type="date" />
        <property name="registerTime" column="registerTime" type="timestamp" insert="false" update="false"/>
    </class>
</hibernate-mapping>  

将映射文件添加到配置文件中hibernate.cfg.xml

<mapping resource="com/briup/test/user.hbm.xml" /> 

主方法Test.java

/**
 * 测试自定义类型映射
 * @author Administrator
 *
 */
public class Test {

    public static void main(String[] args) {
        Configuration config = new Configuration().configure();
        Session session = config.buildSessionFactory().openSession();

    }

}

结果:

说明:

PhoneUserType实现了org.hibernate.UserType接口的所有方法(11个)

sqlTypes() 设置数据库中对应表的字段的类型,这里是varchar

returnedClass() 设置数据库字段类型对应的Java类型,这里时Integer

equals(Object x, Object y) hibernate会调用此方法比较当前对象是否和它的快照相同,参数x代表当前值,y代表有deepCopy()方法生成的属性快照值

hashCode(Object x) 获得当前属性的hash码

deepCopy(Object value) hibernate调用此方法生成快照的值,由于本例中Interger为不可变类,故直接返回value参数

isMutable() 判断自定义属性类是否为可变类 ,此处Integer为不可变类,故返回false

disassemble(Object value) 当hibernate把对象保存到第二缓存中时,调用此方法获得自定义属性的序列化数据

assemble(Serializable cached, Object owner)    当hibernate从第二缓存中加载对象到session 时,调用此方法获得自定义属性(此例为:phone)的反序列化数据

nullSafeGet(ResultSet resultSet, String[] names, Object owner) 当hibernate从数据库中加载对象时,调用此方法取得自定义属性的值

nullSafeSet(PreparedStatement statement, Object value, int index) 当hibernate把对象持久化到数据库时,调用此方法把自定义属性的值添加到SQL 语句中

replace(Object original, Object target, Object owner) 当session调用merge()方法把对象A融合到对象B时,调用此方法获得替代B对象的自定义属性的值
时间: 2024-10-11 20:51:28

JavaEE学习笔记之SSH—Hibernate(2)的相关文章

JavaEE学习笔记之SSH—Hibernate(4)

今天来讲讲 Hibernate 的灵魂所在--> Session 缓存 session缓存是由一系列的Java集合构成的.当一个对象被加入到Session缓存中,这个对象的引用就加入到了java的集合中,以后即使应用程序中的引用变量不再引用该对象,只要Session缓存不被清空,这个对象一直处于生命周期中. Session缓存的作用: 1)减少访问数据库的频率. 2)保证缓存中的对象与数据库中的相关记录保持同步. Session清理缓存的时机: 1)当调用Transaction的commit()

JavaEE学习笔记之SSH—Struts2(1)

现在来学习SSH中的第二个框架--Struts2 Struts2是一个基于MVC设计模式的Web应用框架. 首先将Struts2的框架搭建起来: 1)获取发布包 可以从 Struts2官网.Apache.GitHub等,当然直接百度肯定也是可以的. 2)导入相关 jar 包 将 struts-2.3.24.1-all\struts-2.3.24.1\apps\struts2-blank.war 压缩文件解压,然后将 E:\utils\struts2\struts-2.3.24.1-all\str

JavaEE学习笔记之SSH—Spring(1)

一.Spring相关概念 1:轻量级的容器: 容器:spring容器帮我们管理业务逻辑层,里边有很多业务逻辑对象,有对象就有对象的生命周期的管理(创建,销毁). 轻量级:容器给予的业务逻辑对象多少种服务?spring给用户提供的服务完全由用户自己决定,spring想用什么服务自己开启使用.但是重量级的都是只要你用就把所有的服务都给你,不能自己定制. spring容器从来不能独立运行,一定借助于其他容器启动,或者借助web容器启动,或者ejb容器启动. 特点: 应用模块之间耦合度小,组件都是可重用

JavaEE学习笔记之SSH—Struts2(3)

一.action中如何接受页面传过来的参数 第一种情况:(同名参数) 例如: 通过页面要把id=1 name=tom age=20这三个参数传给action 1.action里面定义三个成员变量id name age,这三个变量的名字一定要和所传变量的名字一致. 2.提供get.set方法 3.将来页面把这三个参数传过来的时候,struts2框架会自动的帮我们把这个三个参数值放action中的三个属性里面.(同时还做了类型的转换) 注意:这个工作其实是由defaultStack这个拦截器栈里面的

JavaEE学习笔记之SSH—Spring(3)

一.代理模式 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 注意: 委托类对象就是我们后面说到的 目标对象(需要[被]代理的对象) 代理类对象就是我们后面说到的 代理对象(目标对象就是需要这个对象做为代理) 按照代理类的

JavaEE学习笔记之SSH—Struts2(4)

这篇文章讲讲 Struts2 的核心所在--拦截器 一.strut2框架中的拦截器(interceptor) 1.什么是拦截器(interceptor) 拦截器是strut2框架中提供的一种java类. 作用: 1.可以拦截访问action的请求 2.给这个action加入新的丰富功能(上传.参数自动接收.类型自动转换等等)需要配置之后,指明哪一个拦截器去拦截哪一个action或者哪一些action,这样这个拦截器才会去拦截我们的这个action,每一个拦截器就可以给我们的action加入一个新

[原创]java WEB学习笔记95:Hibernate 目录

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------