1>、Hibernate是数据访问层框架,是一个ORM(Object Relation Mapping)框架,作者为:Gavin King
2>、搭建Hibernate的开发环境
a>、添加jar包:
aa>、hibernatte开发包中/lib/required/所有jar
bb>、数据库的驱动程序
b>、定制hibernate的工作参数:在classpath根目录下创建一个hibernate.cfg.xml的配置文件
模版从hibernate开发包中/documentation/manual/en-US/html_single/index.html教程第一章
<?xml version='1.0' encoding='utf-8'?>
<!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="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:SXT</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<!-- 数据库连接池大小 -->
<property name="connection.pool_size">1</property>
<!-- SQL方言 -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- 禁用二级缓存 -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!--向控制台输出所有执行的SQL语句 -->
<property name="show_sql">true</property>
<!-- 自动建表 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注册映射文件 -->
<mapping resource="com/sxt/hibernate/po/Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
c>、设计持久化类(Employee),持化化类设计的规范为
a>、public 非final
b>、有一个OID属性,该属性唯一标识一个对象,基本类型建议使用包装类型
c>、有无参的构造方法
d>、属性有get/set方法
e>、集合属性声明为接口类型,如Set,List
d>、完成持久化类的对象关系映射,在持久化类所在位置,建一个名字为:持久化类名.hbm.xml的映射文件
<?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>
<class name="com.sxt.hibernate.po.Employee" table="t_emps">
<!-- 主键映射 -->
<id name="id" column="emp_id">
<!-- 主键的生成策略 -->
<generator class="native"/>
</id>
<!-- 其它属性映射 -->
<property name="empno" length="20" />
<property name="name" column="ename" length="30" not-null="true"/>
<property name="sex" length="2"/>
<property name="job" length="20"/>
<property name="hiredate" />
<property name="salary" column="sal" />
</class>
</hibernate-mapping>
e>、使用Hibernate API完成数据库访问操作
//读取hibernate.cfg.xml中的配置信息
Configuration cfg = new Configuration();
cfg.configure();
//创建SessionFactory
SessionFactory sf = cfg.buildSessionFactory();
//创建Session
Session session = sf.openSession();
//开始事务
Transaction tx = session.beginTransaction();
//执行数据库操作
session.save(emp1);
//提交事务
tx.commit();
//释放资源
session.close();
2>、使用Hibernate完成CRUD操作
session.save();
session.get();
session.update();
session.delete();
session.createQuery(hql);
3>、主键的生成策略
a>、由数据库生成: identity,sequence,native
b>、由程序生成:assigned : 在调用save()方法,必须为对象的OID属性指定值
c>、由Hibernate生成: increment,uuid(主键为字符串类型),guid
4>、基于注解的映射方式
@Entity
@Table(name="t_emp3")
public class Employee3 {
@Id
@GeneratedValue
@Column(name="emp_id")
private Integer id; // OID:对象标识符,对应了数据库表的主键列
@Column(name="eno",length=20,nullable=false)
private String empno;
@Column(name="ename",length=20)
private String name;
@Column(length=2)
private String sex;
@Column(length=10)
private String job;
@Temporal(TemporalType.DATE)
private Date hiredate;
@Column(name="sal")
private double salary;
}
5>、持久化对象的三种状态
临时态(Transient) 持久态(Persistent) 脱管态(Detached)
OID属性是否有值 没有 有 有
是否位于session的缓存 否 是 否
数据库中是否有对应的记录 没有 有 有
a>、save(),update(),saveOrUpdate(),get(),query.list()得到的对象都是持久态
b> 、持久态的对象如果其属性发生变化,在事务提交时hibernate会自动执行更新,将其状态同步至数据库,如果没有变化,即使调用update()方法也不会执行更新
c>、当执行get(),load()查询时,会首先从session的缓存中取,只有在session的缓存中没有时,才查询数据库
d>、如果将对象的引用设为null,emp=null;临时态,脱管态可以被垃圾回收,持久态不能
e>、与状态有关的方法
session.saveOrUpdate()
session.eveict();
session.clear();
session.flush();
6>、关联关系的映射
a>、两个对象究竟是什么关系(一对多/多对一,一对一,多对多,继承)
b>、该关系所对应的表结构
c>、对象模型怎么建
A -> B
B -> A
A <-> B
一般在关联关系的维护方(如果在保存A时,需要B的信息,则A为关联关系的维护)建单向关联
如果要在关联关系的非维护方建关,就建双向关联,在非关联关系的维护方建关联关系,只影响查询操作
d>、关联关系映射怎么做
e>、在对对象执行crud操作时需注意什么
aa>、执行保存操作时,关联关系的维护方需设定关联关系,关联对象必须为持久态或脱管态
emp.setDept(new Dept(1)); //关联对象只需主键有值
bb>、如果在对象上建了关联关系,并进行了映射,hibernate保证查询到的对象可以访问关联的对象 : e.getDept().getName();
cc>、如果一个对象被另一个对象引用,则该对象不能删除(除非设定cascade)
7>、多对一/一对多关联
a>、表结构:在Many方建外键
b>、双向关联中<set inverse="true"></set> insert="true" : 指定set不维持关联关系
c>、延迟加载(lazy) :只有当访问关联对象时,才执行SQL语句从数据库中查询对象
只有session打开的情况下才能实现延迟加载,如果session关闭前,延迟属性没有初始化,关闭之后访问该属性会出异常
<many-to-one lazy="false/proxy"/>
<set lazy="true/false/extra"/> : 集合属性一定要使用延迟加载
lazy="extra" : 在执行dept.getEmps().size()时,执行的sql为:select count(dept_id) from t_emps where dept_id=1
d>、抓取策略 : 如何查询关联对象
<many-to-one fetch="select/join"/> : join 外连接抓取,在查询员工的同时使用外连接将员工的部门一块查出来,会覆盖lazy的设定
<set fetch="select/join/subselect"/> : subselect : 当执行List<Dept> depts = session.createQuery("from Dept").list();
depts.get(0).emps(); 会将所有部门的员工一块查出来
e>、级联操作:当对主控对象执行save,update,delete操作时,是否在关联对象上执行同样的操作
g>、<set order-by="salary desc"/> : order-by : 指定加载集合元素时,按哪个属性排序
8>、session.get()与load()方法的差别:(都是根据主键查询对象)
get(): 立即加载,执行get()方法会立即发出SQL语句,执行数据库查询,查询到的就是目标类(Employee)的对象,如果数据不存在返回null
load():延迟加载, 执行load()方法不会发出SQL语句,只有在访问load()方法返回的对象的属性时,才执行查询,查询返回的是目标类的代理类对象,数据不存在抛异常
9>、一对一映射
a>、共用主键
b>、唯一外键
10>、多对多映射
a>、关联关系上没有附加属性
public class Product {
private Integer id;
private String name;
private double salary;
}
public class Order {
private Integer id;
private String username; // 客户姓名
private String addr; // 送货地址
private String tel; // 联系电话
private Set<Product> products = new HashSet<Product>();
}
<class name="Order" table="t_orders">
<id name="id" column="order_id">
<generator class="native"/>
</id>
<property name="username" length="10" />
<property name="addr" length="20" />
<property name="tel" length="20" />
<!-- 多对多关联 -->
<set name="products" table="t_items" >
<key column="o_id"/> <!-- t_items表与t_orders表的连接列 -->
<many-to-many class="Product" column="p_id"/> <!-- p_id是t_items表与t_products表的连接列 -->
</set>
</class>
b>、关联关系上附加有其它属性(如订单上购买的商品的数量) : 可以将多对多关系拆成两个一对多
public class Product {
private Integer id;
private String name;
private double salary;
}
public class LineItem {
private Integer id;
private Order order; // 所属订单
private Product product; // 对应的商品
private int quantity = 1; // 数量
}
<class name="LineItem" table="t_items">
<id name="id" column="item_id">
<generator class="native"/>
</id>
<property name="quantity" />
<many-to-one name="order" column="o_id"/>
<many-to-one name="product" column="p_id"/>
</class>
<class name="Order" table="t_orders">
<id name="id" column="order_id">
<generator class="native"/>
</id>
<property name="username" length="10" />
<property name="addr" length="20" />
<property name="tel" length="20" />
<!-- 一对多关联 -->
<set name="items" cascade="all">
<key column="o_id"/>
<one-to-many class="LineItem"/>
</set>
</class>
11>、list映射
a>、当需要保证元素的添加次序与获取次序一致时使用list,否则应用set,使用list时,元素在list中的次序会在数据库中存储下来
b>、list必须是关联关系的维护方
c>、
<list name="products" table="t_items" >
<key column="o_id"/> <!-- t_items表与t_orders表的连接列 -->
<list-index column="prod_seq"/> <!-- 指定记录产品在订单中次序的列名 -->
<many-to-many class="Product" column="p_id"/> <!-- p_id是t_items表与t_products表的连接列 -->
</list>
12>、继承映射
Person : id,name,sex,age
Student extends Person : sno,score;
Teacher extends Person : title,salary;
a>、每个类分层结构一张表(table per class hierarchy) [单表]
id name sex age sno score title salary type[鉴别列]
1 张三 男 20 null null null null p
2 李四 女 15 sxt01 90 null null s
3 王五 男 30 null null 教授 5000 t
aa>、优点:所有数据都在一张表中,crud速度比较快
bb>、所有子类属性不能有not null约束,当子类属性比较多时,可能会产生很多null值
b>、每个子类一张表(table per subclass)
t_persons
id name sex age
1 张三 男 20
2 李四 女 15
3 王五 男 30
t_students
id sno score
2 sxt01 90
t_teachers
id title salary
3 教授 5000
bb>、缺点:子类的crud操作都访问至入两张表
c>、每个具体类一张表(table per concrete class)
t_persons
id name sex age
1 张三 男 20
t_students
id name sex age sno score
2 李四 女 15 sxt01 90
t_teachers
id name sex age title salary
3 王五 男 30 教授 5000
aa>、所有表中主键值不能相同
13>、Hibernate的查询操作
a>、QBC : Query By Criteria
b>、Native SQL :
c>、HQL查询
14>、批量处理
a>、批量插入
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
b>、批量更新与删除
session = HibernateUtils.getSession();
session.beginTransaction();
//String hql = "update Employee e set e.salary=e.salary + 200 where e.salary<2000";
String hql = "delete from Employee e where e.salary < 2000";
Query query = session.createQuery(hql);
int rows = query.executeUpdate();
System.out.println("删除了" + rows + "条记录");
session.getTransaction().commit();
c>、恢复scott的数据
aa>在sqlplus 下执行: @ D:\oracle\product\10.2.0\db_1\RDBMS\ADMIN\scott.sql
15、缓存 (将对象放入内存,提升查询的性能)
a>、一级缓存
session的缓存,对缓存对象的管理由hibernate实现,缓存的是所有持久态的对象,Hibernate不控制缓存中对象的数量,可能会出现内存溢出,所缓存对象的生命周期较短
b>、二级缓存
SessionFactory的缓存,由第三方实现,hibernate只提供了存取缓存对象的API,在使用前需要打开与配置,所缓存对象的生命周期较长,经常被查询且很少会改变的对象适合放入二级缓存
aa>、选择缓存供应商,在hibernate.cfg.xml中添加相关配置
<property name="cache.use_query_cache">true</property>
<property name="cache.use_second_level_cache">true</property>
<property name="cache.use_structured_entries">true</property>
<property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>
bb>、添加缓存供应商的jar包
cc>、准备缓存提供者的配置文件
dd>、指定需要放入二级缓存中的类
aaa>、在类的映射文件中指定: <class name="Employee"><cache usage="read-only"/></class>
bbb>、在hibernate.cfg.xml中指定
<class-cache usage="read-only" class="com.sxt.hibernate.po.Employee"/>
c>、查询缓存
缓存的是HQL属性查询的结果集,对实体查询只缓存主键值
select e.name,e.job,e.salary from Employee e where e.salary > 2000 and e.job='MANAGER'
query.setCacheable(true)
16、JPA : Java Persistence API
a>、JPA与Hibernate的关系
JPA是一套持久化规范,不是一个持久化框架
Hibernate是JPA的实现者之一
b>、搭建JPA开发环境(Hibernate实现)
aa>、添加Jar : 1)、原hibernate的所有jar包,2)、hibernate的lib\jpa\hibernate-entitymanager-4.3.2.Final.jar
bb>、配置文件(classpath:META-INF/persistence.xml)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="sxt">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- property的name与value属性的值由JPA的实现来定 -->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="java"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
c>、使用JPA完成CRUD操作
persist();
find();
merge()
remove();
d>、关联关系映射
17、
<property name="gender" not-null="true" length="5">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.itqiang.model.Gender</param>
<!--
12为java.sql.Types.VARCHAR常量值,即保存枚举的字面值到数据库。如果不指定type参数,保存枚举的索引值(从0开始)到数据库
-->
<param name="type">12</param>
</type>
</property>