总结-Hibernate的核心要点

总结-Hibernate的核心要点


1.配置文件
(1)映射配置文件:类名.hbm.xml
<!DOCTYPE Hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.Hibernate.org/dtd/Hibernate-mapping-3.0.dtd">
<Hibernate-mapping>
    <!-- 类与表的映射 -->
    <class name="类的全限定名" table="表名">
        <!-- 主键 -->
        <id name="类的属性名" column="表的主键字段名">
            <!-- 主键策略,native(Number主键) 或 uuid(String主键) -->
            <generator class="native"/>  
        </id>
        
        <!-- 普通字段 -->
        <property name="" column=""></property>
    </class>
</Hibernate-mapping>
a.一对多关系配置

一方:客户

// 一方对象拥有一个集合属性,存放多方对象
private Set<Linkman> liknmanSet = new HashSet<>();
<!-- 一方的配置:set标签 -->
<set name="linkmanSet">
    <key column="多表外键字段名"/>
    <one-to-many class="多方对象类的全限定名">    
</set>

多方:联系人

// 多方对象拥有一个一方对象属性
private Customer customer; 
<!-- 配置多方 -->
<many-to-one name="customer" class="一方对象类的全限定名" column="外键字段名">
级联操作:cascade
一对多中,一方的set标签和多方的many-to-one标签中都有cascade属性,该属性决定了是否进行级联操作
cascade取值如下:
    none(不使用级联删除)
    save-update(级联保存或更新)
    delete(级联删除)
    delete-orphan(孤儿删除,只能应用在一对多的关系)
    all(包含save-update,delete)
    all-delete-orphan(包含all和delte-orphan)

级联操作具有方向性
其中孤儿删除指的是,从一方对象的set属性中移除一个多方对象,会在数据库中同步删除这个多方记录
放弃外键维护:inverse
一对多中,一方和多方配置都有外键信息,可以为一方的set标签设置属性inverse="true",则一方放弃外键维护
即操作一方时,数据库中的外键不变化;操作多方时,外键变化.
因此一方放弃外键维护后,应该使用多方对象进行curd操作
多对多关系中,必须有一方放弃外键的维护
b.多对多关系配置
Hibernate会为多对多的两张表自动建立和维护中间表,用户要做的是设置中间表名和配置多对多关系

两个多方对象都会用一个Set集合属性,存放另一个多方对象
例如:订单和商品是多对多的关系
Set<Good> goods = new HashSet<>();
Set<Order> orders = new HashSet<>();
<!-- Order.hbm.xml的多对多关系配置 -->
<set name="goods" table="orderItems" > // table是设置的中间表名
    <key column="Order在中间表的外键字段名"/>
    <many-to-many class="Good类的全限定名" column="Good在中间表的外键字段名">
</set>
多表也可以使用cascade级联操作,但是不能相互级联删除(全删除).
必须有一方放弃外键的维护:在set标签上添加属性inverse="true"
(2)核心配置文件:hibernate.cfg.xml
<!DOCTYPE Hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.Hibernate.org/dtd/Hibernate-configuration-3.0.dtd">
<Hibernate-configuration>
    <session-factory>
        <!--连接数据库的基本配置-->
        <property name="Hibernate.connection.driver_class">com.jdbc.mysql.Driver</property>
        <property name="Hibernate.connection.url">jdbc:mysql:///Hibernate</property>
        <property name="Hibernate.connection.user">root</property>
        <property name="Hibernate.connection.password">199465</property>
        
        <!--配置Hibernate的方言-->
        <property name="Hibernate.dialect">org.Hibernate.dialect.MySQLDialect</property>
        
        <!--可选的附加配置-->
        <!--自动建表-->
        <property name="Hibernate.hbm2ddl.auto">update</property>
        <!--在控制台打印sql语句-->
        <property name="Hibernate.show_sql">true</property>
        <!--格式化sql-->
        <property name="Hibernate.format_sql">true</property>
        
        <!-- 事务相关 -->
        <!-- 设置数据库隔离级别 -->
        <property name="hibernate.connection.isolation">4</property> 
        <!-- 通过SessionFactory.getCurrentSession获得当前线程绑定的Session -->
        <property name="hibernate.current_session_context_class">thread</property>
        
        <!--引入映射文件-->
        <mapping resource="com/Hibernate/domain/Customer.hbm.xml"/>
    </session-factory>
</Hibernate-configuration>
2.Hibernate的核心类
(1)Configuration

作用:加载核心配置文件,创建唯一的SessionFactory

// 读取src目录下的hibernate.cfg.xml,创建Configuration对象
Configuration config = new Configuration().configure(); 
// 创建sessionFactory对象
SessionFactory factory = config.buildSessionFactory();
(2)SessionFactory

线程安全且重量级的,一般一个数据库对应一个SessionFactory对象;二级缓存的作用

Session session = factory.openSession(); // 利用SessionFactory创建session对象
Session session = factory.getCurrentSession(); // 获取与线程绑定的session(需要配置)
(3)Session

类似于jdbc中的Connection;轻量级非线程安全的(多例);内部维护了一级缓存

Session的API-增删改
Seializable save(Object obj); // 返回的是序列化的ID(主键id)
void update(Object obj); // 更新操作时,没有设置的属性在数据库中会变成null值,建议先查询再更新
void saveOrUpdate(Object obj); // 如果obj没有设置id属性,执行save操作;有id属性且在数据库中找得到,执行update操作;有id在数据库中找不到报错
void delete(Object obj); // 删除操作时,where条件用的是obj不为null的属性,建议先查询再删除
Session的API-查询
T get(Class c,Serializable id); 
T load(Class c,Serializable id); // 延迟加载查询

Query query = session.create("from Customer"); // 利用HQL查询语言获取query对象查询
List<Customer> list = query.list(); // 查询所有
Session的一级缓存
缓存是一种优化的方式,将某些数据存入内存中,调用的时候更快
一级缓存又称为Session级别的缓存,生命周期与Session一致;自带且不可卸载,随Hibernate自启
二级缓存(SessionFactory)需要配置,现在被Redis取代

执行session的相关方法时,得到的对象会被存入一级缓存的快照区做备份,当session执行commit时,会对比目前对象和快照区中的对象是否一致,若不一致则发送sql语句将当前对象持久化到数据库中.看起来就像是持久态的持久化类自己完成了与数据库保持同步的功能.
(4)Transaction
// 事务管理的类,由session开启事务,由Transaction提交/回滚事务
Transaction transaction = session.beginTransaction();
// ...事务
transaction.commit(); // 提交
3.持久化类

指的是能与数据库某张表映射的类

(1)持久化类的编写规则
1.提供一个无参的构造方法:因为Hibernate底层需要反射实现实例化,反射用的是无参构造
2.属性private,提供public的get和set方法
3.必须提供一个唯一标识oid与数据库主键对应
4.类的属性使用包装类(int=>Integer...):因为基本类型默认值为0(有歧义),而包装类没赋值时为null
5.持久化类不要用final修饰:final修饰的类不能被继承,懒加载(load)使用的javassist技术产生的代理对象底层使用的是继承.final修饰的持久化类,load方法失效,优化失效.
(2)持久化类的三种状态
瞬时态:没有oid,也没有被session管理
托管态:有oid,没有被session管理
持久态:有oid,也被session管理
4.Hibernate事务管理
(1)事务的四个特性
A 原子性 事务不可分割
C 一致性 
I 隔离性
D 持久性
(2)事务的并发问题
通过设置隔离级别避免
脏读:一个事务可以读取另一个事务未提交的数据
不可重复读:一个事务可以读取另一个事务提交的update数据
虚读:一个事务可以读取到另一个事务提交的insert数据
设置事务的隔离级别
<property name="hibernate.connection.isolation">4</property> // 隔离级别:1 2 4 8
通过设置乐观锁避免
两个用户同时读取数据并修改,后发送sql语句的会覆盖前面的修改
解决:设置乐观锁,即每次提交数据时验证版本号是否和之前读取数据的版本号一致,若不一致则不能提交
(3)线程绑定session的获取
<!-- SessionFactory.getCurrentSession()获得与线程绑定的session -->
<property name="hibernate.current_session_context_class">thread</property>
5.Hibernate的查询语言:HQL&QBC
(1)Query查询接口

可以认为是半面向对象的sql语言

Query query = session.createQuery("from User"); // 用HQL语言产生Query对象
(2)HQL语言
Query query = session.createQuery("from User where username like :name"); // 支持别名
query.setString("name","%tom%"); // 支持条件查询和模糊查询
List<User> list = query.list(); 
// 别名+排序+方法链
List<User> list = session.createQuery("from Customer c order by c.cid asc").list();
// 分页
query.setFirstResult(0); // 设置从第1条记录开始查
query,setMaxResults(3); // 设置每页显示3条记录
query.list(); //得到第一页结果
// 指定字段查询,不会自动封装
List<Object[]> list = session.createQuery("select name,sex from Customer").list();
// 要实现自动封装,需要在javabean中提供这些指定属性的构造方法(空参构造方法不能漏!)
List<Customer> list = session.createQuery("select new Customer(name,sex) from Customer").list();
// 聚合函数(count可以写*)
List<Number> list = session.createQuery("select count(*) from Customer").list(); 
list.get(0).intValue(); // Number方法;查询数量结果
List<Number> list = session.createQuery("select sum(id) from Customer").list();
list.get(0).intValue(); // 查询id和
HQL的多表查询

多表查询适用于有外键关系的表之间查询.从对象的角度看,就是一个对象有另一个对象的属性

内连接:仅查询有联系人的客户,即linkmans属性不能为null

// inner join + 别名.属性(用来指代另一张表)
Query query = session.createQuery("from Customer c inner join c.linkmans"); 
List<Object[]>list = query.list(); // 默认返回的还是数组

// inner join fetch: 封装但是有重复
List<Customer> list = session.createQuery("from Customer c inner join fetch c.linkmans").list; 
// 去除list中的重复对象
Set<Customer> set = new HashSet<>(list):

左外连接:查询所有客户,没有联系人他的linkmans属性为null

// 和内连接步骤基本一样,区别只有query创建时,inner join改为left join
List<Customer> list = session.createQuery("from Customer c left join fetch c.linkmans").list; 
(3)Criteria查询接口

完全的面向对象的查询语言,适用于条件查询

Criteria criteria = session.createCriteria(User.class); // "在线"Criteria
List<User> list = criteria.list(); // 查询所有
DetachedCriteria criteria = DetachedCriteria.forClass(User.class); // 离线Criteria

// 离线存在的意义:可以在web层就将需要查询的criteria设置好,直接传参到service层使用
// 使用离线criteria查询(需要session)
Criteria criteria = detachedcriteria.getExecutableCriteria(session); // 离线变在线
(4)QBC语言
// 添加条件;参数Criterion为条件接口,通过工具类Restrictions产生
criteria.add(Criterion criterion); 
criteria.add(Restrictions.gt("age",18)); // 条件:where age > 18
criteria.add(Restrictions.like("name","%老王%")); // 条件:where name like %老王% 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值