Hibernate组成:
1.pojo类:
特点:
1.属性设为私有
2.所有属性设置set(),get() 方法
3.序列化类.实现Serializable接口
4.创建一个默认的无参构造器
2.hibernate配置文件:
hiberna.cfg.xml
3.映射文件
pojo类名.hbm.xml
-----------------------------------------------------------------------------
hibernate配置文件的设置
<session-factory>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:XE</property>
<property name="hibernate.connection.username">songwie</property>
<property name="hibernate.connection.password">465305858</property>
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="hibernate.show_sql">true</property> 是否显示运行的sql语句
<property name="hibernate.hbm2ddl.auto">update</property>
update 表示:每次运行对表进行更新,原先的数据存在
create 表示:每次运行对表进行重新创建,原先的数据不存在
<property name="hibernate.jdbc.batch_size">20</property><!-- 批处理大小
<mapping resource="com/briup/one2many/Person.hbm.xml" />
<mapping resource="com/briup/one2many/Address.hbm.xml" />
映射文件的路径
</session-factory>
--------------------------------------------------------------------------
映射文件设置:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.briup.one2many" >
package:映射文件所在路径
---------------------------------
<1> class配置:
<class name="Person" table="t_person" dinamic-update="true">
1.name所对应的值为映射类的名
2.table多对应的值为映射表的名
3.dinamic-insert(true,false):表示没有设置值的列是否自动设置空值,
默认为false:不设置
true 为设置
4 dinamic-update(true,false)
默认会更新所有的列
true:表示更新某条记录时,仅更新该条记录所对应的列,动态的生成update语句,而不是使用
session所持有的缓存语句全部更新;
5.lazy(true,false) 是否延时装载:
默认延时true
延迟装载:(默认是延迟装载)
延时装载的使用地方:
1. 属性延时装载
2.整个实体类延时装载
3.关联映射(相关联的对象延迟装载)
注:load才会使用延迟装载
延迟加载的三种级别:
1)字段级别
2)类级别
3)关联级别
注意:在Hibernate3.0中这三种级别默认都采用延迟加载.
在使用延时装载的地方使用Hibernate.initialize(student);
--------------------------------
<2>. 主键的内置生成器的主键生成方式:
<id name="id" column="ID">
<generator class="increment"/>
主键内置生成器
1. 高低值(可移植性高)
id=hi_value*(max_lo+1)+lo_value
其中hi_value会自动加1,下次使用继续叠加 ;
lo_value每次会从0开始加,下次还是从0开始
<generator class="hilo">
<param name="table">t_high</param> 存放高值的表名
<param name="column">high_value</param>表中存放高值的列名
<param name="max_lo">1</param>
</generator>-->
2.通过序列(可移植性不高)
<!--<generator class="sequence">
<param name="sequence">seq_student_id</param>
</generator> -->
3.高值与序列的结合(可移植性不高):
id=hi_value*(max_lo+1)+lo_value(hi_value由序列产生)
<!--<generator class="seqhilo">
<param name="sequence">hi_value</param>
<param name="max_lo">1</param>
</generator>-->
4.自增长方式(根据表中的值加1)
注:缺点,当并发访问时会出现问题
<!--<generator class="increment"/>-->
5.靠底层数据库自己生成:
例如:
mysql: id number primary key aotu_increment;
<!--<generator class="identity"/>-->
6.uuid:
根据ip,JVM启动时间,当前时间,内部增量产生一个16进制的数值,
在根据其产生一个32位的字符串
<!--<generator class="uuid"/>-->
7.assigned默认配置
自己手动设置主键
8.native:hibernate会根据底层数据库,选择一种相应的方式
9.foreign :唯一外键方式一种(主键根据外键生成)
<generator class="foreign"> <!-- 主键生成方式根据外键生成 -->
<param name="property">address</param>
</generator>
</id>
<property name="name" type="string" column="NAME" length="10" />
type可以选择:
1. java中的类型(必须加上包名:java.lang.Integer)
2. hibernate的类型小写integer(java中所有类型hibernate都有有一种类型对应)
<property name="age" type="integer">
<column name="AGE" precision="3" scale="0"></column>
对应的表中的列可以用子标签表示也可以写在同一个标签
注:
写在子标签的类型可以设置刻度精度等,而其他的不可以
</property>
<3>property的配置:
<property name="gender" type="string" column="GENDER" length="10" />
1.unique(true,false): 对应表中的唯一约束
2.not-null(true,false)对应表中的非空约束
3.precision (P,S)对应表中值的精度和刻度
<4>映射的方式
注:当有多张表时的对应映射关系:
-------------------------------------------------------------
<<1>> one-2-one:(两种)
注:
1 .级联保存保存必须加上cascade()
//级联操作(保存任何一个就可以)但是必须加上
// cascade取值(none,save-update,delete,all,delete-orphan,all-delete-orphan)
2. cascade 与查询没有关系(select默认为级联查询,不需设置)
delete-orphan:当解除关系时同时把person中的对应的记录删掉(对象java角度)
<1>. 唯一外键映射(第一种)
注: unique="true": 由于是一对一关系所以此处unique设置为true表示一对一
person:(含有外键列的表)
a.主键生成方式:
<generator class="increment"/>
b.映射关系:
<many-to-one name="address" class="Address" unique="true" cascade="all">
<column name="address_id"/>
</many-to-one>
address:(没有外键的表)
映射关系:
<one-to-one name="person" class="Person" cascade="all"/>
<2>.主键映射 (主外键合一)(第二种)
person:(含有外键列的表)
a.主键生成方式:(注:此时主键生成方式foreig仅仅在此情况下使用)
<generator class="foreign"><!-- 主键生成方式根据外键生成 -->
<param name="property">address</param>
</generator>
b.映射关系:
<one-to-one name="address" class="Address" constrained="true"/>
注:constrained(true,false) true表示加上外键关系
address:(没有外键的表)
映射关系:
<one-to-one name="person" class="Person" cascade="all"/>
-------------------------------------------------
<<2>> one-2-many:
person:(含有外键列的表)
<many-to-one name="address" class="Address" cascade="all">
<column name="address_id"/>
</many-to-one>
address:(没有外键的表)
<set name="persons" cascade="all" inverse="true">
<key column="address_id"/>
<one-to-many class="Person"/>
</set>
Address address = (Address) session.get(Address.class, 1);
Person person = (Person) session.get(Person.class, 1);
address.getPersons().remove(person);
<!-- inverse控制翻转,取值false,true默认为false
当为false是address和person都会维护外键;
当true时只有person来维护 -->>
只在一的那边写:
//当inverse设为true 时,外键仅由person管理,person中的地址外键 无法 删除
//当inverse设为false 时,外键由person,address共同管理,person中的地址外键 可以 删除
-------------------------------------------
<<3>> many-to-many
1.Student.hbm.xml:
<set name="course" table="t_stu_cou" >
<key column="stu_id"/>
<many-to-many column="cou_id" class="Course"/>
</set>
2.Course.hbm.xml:
<set name="students" table="t_stu_cou" cascade="all" inverse="true" >
<key column="cou_id"/>
<many-to-many column="stu_id" class="Student"/>
</set>
注意:
inverse 必须有一个设为true 否则,桥表两边都会维护,都会插入数据会导致同时插入
两个相同的数据,违反唯一约束
<<4>>继承映射:
1.办法一: 父类有表,每个子类也有表
<class name="Payment" table="t_payment" >
<id name="id" column="ID">
<generator class="increment"/>
</id>
<property name="amount" type="double" column="amount" length="50" />
<joined-subclass name="ChequePayment" table="t_cheque_payment">
<key column="pay_id"/>
<property name="chequeNo" column="cheque_no" type="string"/>
</joined-subclass>
</class>
2.办法二:父类没有表,每个子类有表
<class name="Payment" table="t_payment" >
<id name="id" column="ID">
<generator class="increment"/>
</id>
<property name="amount" type="double" column="amount" length="50" />
<union-subclass name="CreditPayment" table="t_credit_payment">
<property name="cardType" column="card_type" type="string"/>
</union-subclass>
</class>
3.办法三:父类子类合为一张表
<class name="Payment" table="t_payment" >
<id name="id" column="ID">
<generator class="increment"/>
</id><!--
必须写在id后面
-->
<discriminator column="pay_type" type="string" /> //制定列名
<property name="amount" type="double" column="amount" length="50" />
<subclass name="ChequePayment" discriminator-value="cheque"> //制定列值
<property name="chequeNo" column="cheque_no" type="string" />
</subclass>
</class>
优缺点:
是否支持多态, 维护是否方便, 出具报表是否方便
----------------- --------------- -------------------
每个类一张表 是 是 不方便
每个子类一张表 否 不方便 方便
整个类一张表 是 方便 方便
注:以上几种映射方式,全部为双向映射.
attribute: String chequeNo;
property: setChequeNo(String chequeNo);
-----------------------------------------------------------------------
1.Hibernate的简介
1.基于ORM的实现持久化层的一个开源的持久化框架;
2.Hibernate3.0 author:Gravin King;
3.ORM中间件,位于业务逻辑层和数据库中间,提供对象-关系的映射,将一个持久化对象保
存到数据库中称为一条记录.
表现层(web层)
业务逻辑层
持久化层(jdbc Hibernate)
数据库
2.Hibernate的工作原理
1.Hibernate框架根据hibernate.cfg.xml的配置的信息(URL,Driver,User,Password)来和
数据库进行通信;
2.Hibernate框架根据具体的映射文件(如:student.hbm.xml,该文件配置类和表,类的属性
和表中字段的映射关系)来对对象
进行保存,更新,删除和查询;
3. hibernate 核心接口:
1.Configration
2.SessionFactoty
3.Session
4.Transaction
5.Query
6.Criteria
4.Hibernate的优点
1.对JDBC做了轻量级的封装,底层的和数据库操作是基于jdbc的.
Hibernate框架对外提供了一些操作数据库的接口方法(如:save()).
2.减少了这个软件系统的开发周期.
3.另外对JDBC的事务和JTA的分布式事务和JNDI也做了封装.
4.所谓轻量级就是指应用程序可以直接使用Hibernate提供的API操作数据库,
也可以绕过Hibernate使用jdbc提供的API操作数据库.
---------------------------------------------------------------
1.编写配置文件
2.写一个java类(pojo类)
3.编写映射文件
4.编写应用程序调用API
a.根启动configure,
加载所有配置文件config.config("路径");
b.实例化SessionFactory
c.实例化Session
d 启动事务
e 执行curd
f 关闭资源
Configuration config = new Configuration();
config.configure("com/briup/one2many/hibernate.cfg.xml");
SessionFactory factory = config.buildSessionFactory();
Session session = factory.openSession();
Transaction tran = session.beginTransaction();
--------------------------------------------------------
SessionFactory的四种特征:(重量级的)
1.线程安全的
2.建议一个数据库对应一个SessionFactory
3.维护着一个缓存(2级缓存)默认情况下是不启用的
4.对每一个实体类缓存了四条sql语句insert...
delete...
select...
update...
Session四种特征:(轻量级)
1.线程不安全的
2.建议一个事务对应一个Session
3.维护着一个缓存(1级缓存)默认情况下是启用的
4.对每一个实体类缓存了四条sql语句insert...
delete...
select...
update...
-------------------------------------------------------------------
hibernate的类型:
1 . 值类型(inerger等不可以被持久管理器保存)
2 . 实体类型(创建的对象,可以被持久管理器保存)
---------------------------------------------------------------------------
hibernate操作持久化对象:
1. hibernate管理对象的状态:
a: 自由态(transient): 自己new出一个对象
b: 持久态(persistent): 用session从数据库查找到的,同时受session管理
c: 游离态(detached): 用session从数据库查找到的,不受session管理
状态 数据库中是否有对应记录 是否受Session管理
自由态 否 否
持久态 是 是
游离态 是 否
-------------------------------------------------------------
2. hibernate的脏检查机制:(仅对持有态有用)
对于一个持久化的对象,当提交事务时,hibernate会自动的将对象的的信息同步到数据库当中,而不需要
调用session的update方法;
3.session中get与load的却别?
数据库中没有对应的记录 是否使用代理
get null 否
load Exception 是
------------------------------------------------------------------------------
常用的方法:
save, savaOrUpdate, update,delete,load , get
lock:能够操作游离态的对象,将游离态的对象变为持久态
注: (与update的区别就是它仅仅改变状态不会保存信息到数据库中)
merge:能够操作游离态的对象,将信息保存到数据库当中,但是不改变对象的状态
evict:将指定对象从session中清除,变为游离态
注:与clear的区别是merge仅仅清除制定对象,而
clear:全部清空
flush: 整理缓存,将需要执行的sql执行
对象保存:
sava()
1. 自由态: 当做新对象直接保存到数据库(增加一条新数据)
2. 持久态: 不做任何操作
3. 游离态 : 当做新对象直接保存到数据库(增加一条新数据)
saveOrUpdate()
1. 自由态: 当做新对象直接保存到数据库(增加一条新数据)
2. 持久太: 更新对象到数据库
3. 游离态 : 更新对象到数据库
update()
1. 自由态: 异常
2. 持久太: 更新
3. 游离态 : 更新对象到数据库
delete()
1. 自由态: 不做任何操作
2. 持久太: 直接删除
3. 游离态 : 先变为持久态,后删除
--------------------------------------------------------------------
1. hibernate处理事务:
1.oracle 中事务的边界:
开始:a.连接到数据库
b.一个事务结束,另一个事务开始
结束:a. 提交 commit (DDL,DCL自动提交)
b 回滚 rollback
2.jdbc中:
开始:connection.setAutoCommit(false); 设置事务提交为手动(jdbc中默认为系统自动提交)
结束: connection.commit();
connection.roolBack();
3.hibernate当中:
开始: Transaction tran = session.beginTransaction();
结束:tran.commit(); (必须手动提交事务 ) 默认在提交事务之前会session.flush();
2.jdbc与JTA(java 事务框架)
jdbc处理的是单个数据库的事务,JTA处理的多个数据库的事务
a. 单个数据库的事务:
session.begintransaction()----->开始一个新的事务
b. 多个数据的事务
session.begintransaction()
1. 当时操作已经有事务,加入当前事务
2.当前没有事务,开始一个新的事物
3. flush Session
1. 某些queue语句执行之前,整理缓存
2. 提交事务的的时候
3. 手动调用session.flush
session.setFlushMode(FlushMode.XXX); 设置flush整理的模式(什么时候整理缓存)
FlushMode.XXX:
某些queue语句执行之前 提交事务 调用flush
-----------------------------------------------------------------
1.auto (默认) : 会 会 会
2.commit: 不会 会 会
3.never : 不会 不会 会
4.事务的隔离级别:
-------------------------------------------------------
1.第一类丢失更新:一个事务的回滚导致其它事务的提交被覆盖
时间 事务一(取款) 事务二(转账)
T1 开始事务
T2 开始事务
T3 查询余额为1000
T4 查询余额为1000
T5 存款100,余额变为1100
T6 提交事务
T7 取款100,余额变为900
T8 撤销事务,余额变为1000
-------------------------------
2.脏读:一个事务读取到了另外一个事务还没有提交的数据
时间 事务一(取款) 事务二(转账)
T 开始事务
T2 开始事务
T3 查询余额为1000
T4 取款100,余额变为900
T5 查询余额为900(脏读)
T6 撤销事务,余额变为1000
T7 转入100,余额变为1000
T8 提交事务
---------------------------------------------
3.重复读:一个事务读取到了另外一个事务已经提交的更新的数据,
一个事务对同一条数据读取两次,结果不相同
时间 事务一(取款) 事务二(转账)
T1 开始事务
T2 开始事务
T3 查询余额为1000
T4 查询余额为1000
T5 取款100,余额变为900
T6 提交事务
T7 查询余额为900
T8 到底是1000 还是900?
-------------------------------------------------------
4. 第二类丢失更新:一个事务的提交导致其它事务的提交被覆盖
时间 事务一(取款) 事务二(转账)
T1 开始事务
T2 开始事务
T3 查询余额为1000
T4 查询余额为1000
T5 取款100,余额变为900
T6 提交事务
T7 存款100,余额变为1100
T8 提交事务
-----------------------------------------------------
5.虚读:一个事务读取到了另外一个事务已经提交的新插入的数据,
一个事务执行两次查询,查询结果包含的记录数不相同
时间 事务一(注册用户) 事务二(统计人数)
T1 开始事务
T2 开始事务
T3 查询总人数为1000
T4 注册一个新用户
T5 提交事务
T6 查询总人数为1001(虚读)
T7 到底是1000 还是1001?
隔离级别: 设置级别 oracle支持 1 2 3 4 5
---------------------------------------------------------- -------- -------------------------
1. 读未提交的数据 (read uncommited) 1 不 n y y y y
2. 读已提交的数据 read commited 2 支持 (默认) n n y n n
3. 不可重复读 repeatable 4 不 n n n y y
4. 事务的最高级别 serializable 8 支持 n n n n n
在配置文件中设置隔离级别:
<property name="HIbernate.connection.isolation">级别</property>
-----------------------------
6 局部线程的并发访问
1. 悲观锁(hibernate认为一个事务在操作这条数据时另一个事务也会操作这条数据,所以在事务一开始就加锁
hibernate本身并没有实现这种锁,完全依靠底层数据库来实现)(for update)
LockMode.UPDGRADE(for update) 拿不到锁则等待
LockMode.UPDGRADE_NOWAIT (for update nowait ) 拿不到锁则不等待,马上结束(导致异常)
2. 乐观锁
hibernate假想在一个事务操作一条资源的时候,不会有另一条记录来访问,hibernate通过版本号控制数据的一致性
--------------------------------------------------------------------------------------
7. 高级查询
<1>. 如何检索对象信息?
a. 通过唯一的OID
session.get/load(xxx.class,OID);
b. 导航对象图方式
Address address = (Address)session.get(Address.class,1);
Person person = address.getPerson();导航对象图(级联)
c. HQL:
基本步骤:
1.创建一个hql语句 String hql = "from Address where id < ?";
查询所有的列,不用谢select 语句
查询部分列,要设置select语句
2.创建Query对象
Query query= session.createQuery(hql);
3.设置参数(不是必须的)
String hql = "from Address where id < ?"
queue.setInteger(0,100); 从零开始,jdbc中preparedStatement注册参数从1开始
设置参数方式:
a. 按照参数顺序
query.setInteger(n,100); n=(0....n)
b. 按照名字:
String hql = "from Address where id < :id"
query.setInteger("id",100); : 后面的id就是设置中的id
c. 直接拼hql
public List method(int id){
String hql = "from Address where id="+id;
String hql = "from Address where name='"+name+"' ";
}
注:提取公共:
<query name="getPerson" ><![CDATA[from Person where id < ?]]> </query>
Query query = session.getNamedQuery("getPerson");
query.setInteger(0, 10);
4.设置其他信息(比如分页查询)
query.setFirstResult(0); (page-1)*maxCount
query.setMaxResults(20);
5.获取结果集:
a. List list = query.list();
b. Address address = (Address)query.uniqueResult(); 仅仅有一条结果时
c. Iterator iter = query.iterator();
d. 通过命名的hql语句查询
<2> hibernate连接
特征 结果
------------------------------------------------------------------------
1. 普通连接 只用 join 对象类型的数组
2. 迫切连接 有join, fetch 特定类型的的对象
3. 交叉连接 笛卡尔积 对象类型的数组
4. 隐式连接 属性链 特定类型的的对象
1. from Person p join p.address
2. from Person p join fetch p.address
3. from Person p, Address a
4. from Person p where p.address.country=?
--------------------------------------------------------
<3>投影查询(有select 查询部分列)
<4>动态查询
<5>Criteria 使用 (当连接条件不确定时候使用)
BufferString hql = "from Person where 1=1 ";
if(age!=null){
hql.append("and age="+age);
}
Criteria c = session.createCriteria(Person.class);
if(age!=null){
c.add(Restrictions.eq("age",age));
}
Criteria c = session.createCriteria(Person.class);
c.add(Restrictions.eq("name","sw"));
<======>
String hql = "from Person where name=?";
Query query = session.createQuery(hql);
qruey.setString(0,"sw");
<6> Example(模板)(不推荐)
Criteria c = session.createCriteria(Person.class);
Person p = new Person();
p.setName("sw");
c.add(Example.create(p));
List list = c.list();
<7> 本地sql(不推荐)
String sql = "select * from t_person where name = ?";
//String sql = "select s* from t_person where name = ?";
Query query = session.createSQLQuery(sql);
query.setString(0,"sw");
//query.addEntity(Person.class);
List list = query.list(); (object 类型数组);
<8> hql操作DML语句
String hql = "delete from Person where id < 100" ;
Query query = session.createQuery(hql);
query.executeUpdate();
Hibernate
发表回复