Java实战之02Hibernate-02映射、一级缓存、实体对象状态
五、映射基础
1、实体类采用javabean的编写规范
JavaBean编写规范:
a、类一般是public的
b、有默认的构造方法
c、字段都是私有的
d、提供公有的getter和setter方法
e、一般都实现java.io.Serializable接口
注意:hibernate采用的暴力反射
2、基本类型OR包装类型
int ---> Integer
.......
3、访问实体类数据的策略(了解)
通过上面我们可知,hibernate是采用的暴力反射,所以我们既可以通过属性页可以用过字段访问。但是一般都使用属性(即get和set方法)
直接执行会报错,我们需要通过在配置文件中配置,来告知hibernate采用访问属性的方式进行取值和赋值。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 创建映射文件:
1、在实体类所在的包下,创建一个以实体类名称.hbm.xml的文件。
2、导入dtd约束
在hibernate的核心jar包中 hibernate-mapping-3.0.dtd
明确:
映射中指定类中的属性都是针对的set方法后面的部分。
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<!-- 类和表的对应关系 -->
<class name="Student" table="student">
<!-- 类中的字段和表中的列的对应关系 -->
<!-- 主键的映射 -->
<id name="id" column="id">
<!-- 主键的生成方式
native:
它指的是使用本地数据自己的自动增长能力
(如果数据库之中字段自增长,那就是用字段自增长。
如果数据库支持的是序列自增长,那就是用序列自增长。)
-->
<generator class="native"></generator>
</id>
<!-- 其他字段映射
指定访问的方式是通过字段访问:access="field"
-->
<property name="name" column="name"></property>
<property name="gender" column="gender"></property>
<property name="birthday" column="birthday"></property>
</class>
</hibernate-mapping>
4、派生属性
概念:
实体类中的某些属性在数据库表中没有对应的字段,该属性的值是由数据库表中其他字段计算出来的。这样的属性叫做派生属性。
模拟测试数据:
创建一个订单表:
<hibernate-mapping package="cn.itcast.domain">
<class name="Customer" table="customer">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 映射totalPrice,它是一个派生属性。不是表中本身的字段信息
formula:用于映射派生属性
必须以括号开头
括号内中 需要使用别名的地方,要自己指定
-->
<property name="totalPrice" formula="(select sum(o.price) from orders o where o.customer_id = id)"></property>
</class>
</hibernate-mapping>
5、控制insert和update
映射文件:xml
5.1、property元素(了解)
insert:默认值是true,如果改为false。表示该属性永远不会被插入。(动态生成的SQL语句)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 创建映射文件:
1、在实体类所在的包下,创建一个以实体类名称.hbm.xml的文件。
2、导入dtd约束
在hibernate的核心jar包中 hibernate-mapping-3.0.dtd
明确:
映射中指定类中的属性都是针对的set方法后面的部分。
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<!-- 类和表的对应关系
属性:
dynamic-insert:动态生成SQL语句,生成的规则是,永远不涉及为null的字段。
取值true/false。默认值false。当改为true时,按照上述规则生成。
dynamic-update:动态生成SQL语句,生成规则是,永远不涉及不变的字段。(修改前和修改后数据一样的,不会被涉及)
取值true/false。默认值false。当改为true时,按照上述规则生成。
-->
<class name="Student" table="student" dynamic-insert="true" dynamic-update="true">
<!-- 类中的字段和表中的列的对应关系 -->
<!-- 主键的映射 -->
<id name="id" column="id">
<!-- 主键的生成方式
native:
它指的是使用本地数据自己的自动增长能力
(如果数据库之中字段自增长,那就是用字段自增长。
如果数据库支持的是序列自增长,那就是用序列自增长。)
increment:
有hibernate自己维护主键的自增长。需要先查询一次最大的id。
identity:
使用的是本地数据库的字段自增长能力
sequence:
使用的是本地数据库的序列自增长能力
assigned:
使用手动指定的方式。(主键有一定的生成规则时,使用此值)
hilo:
高地位算法
-->
<generator class="identity"></generator>
</id>
<!-- 其他字段映射
指定访问的方式是通过字段访问:access="field"
insert属性:用于动态生成SQL语句,该属性取值是true和false。默认值是true。
true:会插入该字段数据。
false:永远不会插入该字段数据。
update属性:用于动态生成SQL语句,该属性取值true和false。默认值是true。
true:会更新字段信息。
false:永远不会更新该字段信息
-->
<property name="name" column="name" ></property>
<property name="gender" column="gender"></property>
<property name="birthday" column="birthday"></property>
</class>
</hibernate-mapping>
5.2、class元素
mutable:默认值是true,如果为false,表示当前类所有属性都不会被修改。
dynamic-insert:默认是false,如果为true。会动态生成insert语句,只涉及不为null的字段。
dynamic-update:默认值是false。如果为true,会动态生成update语句,只更新数据有变化了的字段。
如果类的属性很多,建立动态生成insert或update。(动态生成SQL消耗的资源可以忽略不计)。
6、避免与数据库关键字冲突的问题
例如:
我们在创建订单表时,有可能会使用Order来作为表名,但是由于order是关键字,可以在order上加入反引号。
六、映射对象标识符
1、概述
总结:应该让Hibernate来管理OID。
2、Hibernate主键生成策略
2.1、如何配置
<id name="id" column="id">
<generator class="native"></generator>
3 </id>
2.2、常用生成策略
a、increment
OID必须是long,int,short类型的。
弊端:
适用于单应用访问同一个数据库的场合,在集群环境下不推荐使用。
b、identity
数据库系统必须支持自动增长字段类型
OID必须是long、int、short类型
注意:increment和identity的区别,一个是由Hibernate来负责维护,一个是由数据库来负责维护。
c、hilo:hibernate利用高地位算法生成OID
不依赖底层数据库,适用于所有的数据库。
OID必须是long、int、short类型
该算法生成的标识符只能在一个数据库中保证唯一
<?xml version="1.0" encoding="UTF-8"?>
<!-- 创建映射文件:
1、在实体类所在的包下,创建一个以实体类名称.hbm.xml的文件。
2、导入dtd约束
在hibernate的核心jar包中 hibernate-mapping-3.0.dtd
明确:
映射中指定类中的属性都是针对的set方法后面的部分。
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain">
<!-- 类和表的对应关系
属性:
dynamic-insert:动态生成SQL语句,生成的规则是,永远不涉及为null的字段。
取值true/false。默认值false。当改为true时,按照上述规则生成。
dynamic-update:动态生成SQL语句,生成规则是,永远不涉及不变的字段。(修改前和修改后数据一样的,不会被涉及)
取值true/false。默认值false。当改为true时,按照上述规则生成。
-->
<class name="Student" table="student" dynamic-insert="true" dynamic-update="true">
<!-- 类中的字段和表中的列的对应关系 -->
<!-- 主键的映射 -->
<id name="id" column="id">
<!-- 主键的生成方式
native:
它指的是使用本地数据自己的自动增长能力
(如果数据库之中字段自增长,那就是用字段自增长。
如果数据库支持的是序列自增长,那就是用序列自增长。)
increment:
有hibernate自己维护主键的自增长。需要先查询一次最大的id。
identity:
使用的是本地数据库的字段自增长能力
sequence:
使用的是本地数据库的序列自增长能力
assigned:
使用手动指定的方式。(主键有一定的生成规则时,使用此值)
hilo:
高地位算法
-->
<generator class="identity"></generator>
</id>
<!-- 其他字段映射
指定访问的方式是通过字段访问:access="field"
insert属性:用于动态生成SQL语句,该属性取值是true和false。默认值是true。
true:会插入该字段数据。
false:永远不会插入该字段数据。
update属性:用于动态生成SQL语句,该属性取值true和false。默认值是true。
true:会更新字段信息。
false:永远不会更新该字段信息
-->
<property name="name" column="name" ></property>
<property name="gender" column="gender"></property>
<property name="birthday" column="birthday"></property>
</class>
</hibernate-mapping>
算法:
高值*(max_lo+1)+不大于max_lo的值
高值从0开始
0*(5+1)+0=0 忽略
0*(5+1)+1=1
0*(5+1)+2=2
0*(5+1)+3=3
0*(5+1)+4=4
0*(5+1)+5=5 下一个高值为1
1*(5+1)+0=6
1*(5+1)+1=7
1*(5+1)+2=8
1*(5+1)+3=9
1*(5+1)+4=10
1*(5+1)+5=11 下一个高值为2
d、native
依据底层数据库对自动生成标识符的支持能力来选择使用identity、sequence来生成标识符
适合跨数据库平台开发
OID必须是long、int、short类型
七、Session对象的一级缓存
1、Session的一级缓存
//证明一级缓存的存在
@Test
public void test1(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s1 = s.get(Student.class, 2);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
System.out.println(s1);
Student s2 = s.get(Student.class, 2);//不会去查询,因为一级缓存之中有数据。
System.out.println(s2);
tx.commit();
s.close();
}
2、为什么使用缓存
a、减少访问数据库的频率。应用从缓存中读取数据的速度比从数据库获取数据要快,提高了数据的访问性能
b、当缓存中的对象之间存在循环关联关系时,Session保证不会出现访问对象的关联死循环,以及由死循环造成的JVM堆栈溢出问题
c、保证数据库中的相关记录与缓存中的对象保持同步
注意:当与数据库中的数据一致时,不会进行更新。
3、如何做到数据发生变化时进行同步
3.1、快照(SnapShot)机制
//修改数据
//快照机制
@Test
public void test2(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s1 = s.get(Student.class, 2);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
System.out.println(s1);//gender:male
s1.setGender("male");//改gender,其实改的是内存对象
System.out.println(s1);//gender:female
tx.commit();
s.close();//一级缓存在此行执行之后就消失了。 //在此种再接着写代码
System.out.println(s1);//gender:female
}
4、控制Session的一级缓存
目的:学习Session中与一级缓存有关的方法。
4.1、Session.clear();:清空缓存。
/*
* clear方法
* 作用:清空一级缓存
*
* 和close有区别:
* close执行之后,一级缓存也没有了。
* clear执行完成之后,session是还可以用的。
*/
@Test
public void test1(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s1 = s.get(Student.class, 2);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
System.out.println(s1); s.clear(); Student s2 = s.get(Student.class, 2);
System.out.println(s2);
tx.commit();
s.close();
}
4.2、Session.evict(Object entity);:清除一级缓存中指定的实体对象。
/*
* evict方法
* 作用清除的是指定实体的缓存
*/
@Test
public void test2(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s2 = s.get(Student.class, 2);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
Student s3 = s.get(Student.class, 3);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。 s.evict(s2); Student s4 = s.get(Student.class, 2);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
Student s5 = s.get(Student.class, 3);//不会去查询,因为一级缓存之中有数据
tx.commit();
s.close();
}
4.3、Session.refresh(Obect entity);:重新刷新缓存(用数据库中的数据同步缓存中指定的实体)
/*
* refresh方法
* 作用:那数据库的数据,来同步一级缓存。
*/
@Test
public void test3(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s1 = s.get(Student.class, 6);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
System.out.println(s1);//gender :male
s1.setGender("female");//修改gender:female
System.out.println(s1);
s.refresh(s1);
System.out.println(s1);
tx.commit();
s.close();
}
4.4、Session.flush();:清理缓存(同步缓存中数据到数据库中),但是不会清空。
a、清理时机:
1、Transaction.commit()时会先清理缓存后提交事务。安排在此处是为了减少数据访问的频率和缩短当前事务对数据库中资源的锁定时间。
2、当应用中执行一些查询操作(Query)时,如果缓存中的对象发生了变化,会先进行清理。从而保证查询出的数据是正确的
3、显式调用Session的flush()方法
/*
* flush方法
* 作用:手动刷新缓存。把数据从session中刷新出去。
*/
@Test
public void test5(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Student s1 = s.get(Student.class, 6);//会去数据库查询,同时会把查询出来的数据存入一级缓存之中。
System.out.println(s1);//gender :male
s1.setGender("male");//修改gender:female
System.out.println(s1); s.flush();//当有此行存在时,此时就会看到update语句 tx.commit();//默认此行刷出缓存中的数据。去拿缓存修改数据库的数据
s.close();
}
b、设置清理时机
八、实体对象的状态
1、各种状态图
2、状态说明:(判断对象处于什么状态不以数据库中有无记录作为依据,因为事务的问题,事务是否已经提交)
2.1、临时状态(transient):
用new语句创建,还没有被持久化,并且不在Session的缓存中。
标识:OID为null,没有和Session建立关系。
2.2、持久化状态(persistent):
已经计划被持久化,并且加入到Session的缓存中。(为什么说计划:因为事务问题,是否已经提交事务)
标识:OID不为null,建立了和Session的关系。
2.3、删除状态(removed):
不在Session的缓存中,且Session已经计划将其从数据库中删除。
标识:OID不为null,计划要从Session中删除的。
2.4、游离状态(detached脱管):
已经被持久化,不在Session的缓存中
标识:OID不为null,没有和Session建立关系。
Java实战之02Hibernate-02映射、一级缓存、实体对象状态的更多相关文章
- hibernate一级缓存及对象的状态
hibernate中实体类对象的状态 在hibernate中实体类对象有三种状态 (1)瞬时态(临时态) 瞬时态:即我们自己创建一个对象,还没有保存到数据库就叫临时态,其实也可以说是对像没有id值,跟 ...
- 【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】
一.Session概述 1.Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法. 2.理解Sessi ...
- mybatis一级缓存二级缓存
一级缓存 Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言.所以在参数和SQL完全一样的情况下,我们使用同一个SqlSess ...
- mybatis一级缓存和二级缓存(二)
注意事项与示例配置 一级缓存 Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言.所以在参数和SQL完全一样的情况下,我们使用 ...
- Hibernate 的一级缓存和二级缓存总结
缓存:缓存是什么,解决什么问题? 位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为缓存Cache.缓存目的:让数据更接近于应用程序,协调速度不匹配,使访问速度更快 ...
- Hibernate学习笔记(二)—— 实体规则&对象的状态&一级缓存
一.持久化类 1.1 什么是持久化类? Hibernate是持久层的ORM映射框架,专注于数据的持久化工作.所谓的持久化,就是将内存中的数据永久存储到关系型数据库中.那么知道了什么是持久化,什么又是持 ...
- Hibernate缓存简介和对比、一级缓存、二级缓存详解
一.hibernate缓存简介 缓存的范围分为3类: 1.事务范围(单Session即一级缓存) 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象 ...
- 三大框架 之 Hibernate生成策略与缓存策略(主键生成策略、持久化、持久化类划分、一级缓存、事物管理)
目录 Hibernate生成策略与缓存策略 主键生成策略 主键分类 主键的生成策略 持久化 什么是持久化 什么是持久化类 持久化类编写规则 持久化类的划分 三种状态区分 持久态对象特征 一级缓存 什么 ...
- (转)mybatis一级缓存二级缓存
一级缓存 Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言.所以在参数和SQL完全一样的情况下,我们使用同一个SqlSess ...
随机推荐
- 使用Genymotion调试出现错误INSTALL_FAILED_CPU_ABI_INCOMPATI
转载:http://my.oschina.net/u/242764/blog/375909 当我们安装好Genymotion后,把Android运用部署到上面调试时,console控制台会报错:Ins ...
- cocos2d-x 手势之简单实现
转自:http://blog.sina.com.cn/s/blog_61ece099010187tl.html 手势之前也发过一篇,但是我感觉那个还不够轻巧. 而且大多数游戏里面不会有那么复杂的手势, ...
- 使用 Windows 窗体 TextBox 控件创建密码文本框
密码框是一种 Windows 窗体文本框,它在用户键入字符串时显示占位符. 创建密码文本框 将 TextBox 控件的 PasswordChar 属性设置为某个特定字符. PasswordChar 属 ...
- memcpy内存拷贝及优化策略图解
一般内存拷贝与优化 代码实现 #include<iostream> usingnamespace std; //不安全的内存拷贝(当源内存地址与目标内存地址重叠时会产生错误) void h ...
- FloatingActionButton
https://github.com/Clans/FloatingActionButton
- java复习1 java简单介绍
在学校的时候.学JAVA学的模棱两可,半知半解.工作以后给我带来了非常大的困扰,所以我须要在学一遍.如今就開始吧... . java[1]是一种能够撰写跨平台应用软件的面向对象的程序设计语言,是由Su ...
- C _数据结构 _线性表的顺序存储
#ifndef __MY_SEQLIST_H__ #define __MY_SEQLIST_H__ typedef void SeqList; typedef void SeqListNode; // ...
- html页面docutype前面出现字符会导致IE678 margin:0 auto;失效
html页面<!DOCTYPE html>前面出现字符会导致IE678 margin:0 auto;失效
- Mechanism of Loading Resources
Mechanism of Loading Resources 1. Distributed strategy 1.1. Developer guilde 1.2. Notes 2. Centraliz ...
- Asp.Net 之 缓存机制
asp.net缓存有三种:页面缓存,数据源缓存,数据缓存. 一.页面缓存 原理:页面缓存是最常用的缓存方式,原理是用户第一次访问的时候asp.net服务器把动态生成的页面存到内存里,之后一段时间再有用 ...