hibernate是一种orm框架
orm:Object Relational Mapping,即对象关系映射
通过映射文件配置对象与表的关系,代替了jdbc和dbutils
简单的hibernate框架搭建:
1.导包
hibernate包:即官网下载好hibernate后lib目录下的required目录全部jar包
hibernate-release-5.0.7.Final\lib\required

驱动包:

log4j包:第一个是核心jar包

2.创建数据库,准备表,实体
CREATE TABLE cst_customer (
cust_id BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT ‘客户编号(主键)’,
cust_name VARCHAR(32) NOT NULL COMMENT ‘客户名称(公司名称)’,
cust_source VARCHAR(32) DEFAULT NULL COMMENT ‘客户信息来源’,
cust_industry VARCHAR(32) DEFAULT NULL COMMENT ‘客户所属行业’,
cust_level VARCHAR(32) DEFAULT NULL COMMENT ‘客户级别’,
cust_linkman VARCHAR(64) DEFAULT NULL COMMENT ‘联系人’,
cust_phone VARCHAR(64) DEFAULT NULL COMMENT ‘固定电话’,
cust_mobile VARCHAR(16) DEFAULT NULL COMMENT ‘移动电话’,
PRIMARY KEY (cust_id)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_linkman() {
return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
}
}
3.书写orm元数据(对象与表的映射配置文件)
该配置文件名任意取,满足约束
<?xml version="1.0" encoding="UTF-8"?>
<!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.xdh.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<generator class=""></generator>
</id>
<property name="cust_name" column="cust_name"></property>
<property name="cust_source" column="cust_source"></property>
<property name="cust_industry" column="cust_industry"></property>
<property name="cust_level" column="cust_level"></property>
<property name="cust_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
</class>
</hibernate-mapping>
约束:hibernate-core-5.0.7.Final.jar目录下的org.hibernate目录下的

4.书写主配置文件:src目录下
约束:这里是hibernate-configuration-3.0.dtd约束

主约束文件名必须为hibernate.cfg.xml:
配置参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件
<?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>
<!--
## MySQL
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!--
#hibernate.show_sql true
#hibernate.format_sql true
-->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!--
## auto schema export
#hibernate.hbm2ddl.auto create-drop
#hibernate.hbm2ddl.auto create
#hibernate.hbm2ddl.auto update
#hibernate.hbm2ddl.auto validate
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="com/xdh/domain/customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
5.测试类
package com.xdh.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import com.xdh.domain.Customer;
public class TestCon {
@Test
//保存客户
public void fun1(){
Configuration conf = new Configuration().configure();
SessionFactory sessionFactory = conf.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------
Customer c = new Customer();
c.setCust_name("google公司");
session.save(c);//执行保存
//----------------------------------------------
tx.commit();
session.close();
sessionFactory.close();
}
}
执行结果:

配置详解:
1.orm元数据:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 根元素,package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简单类名了 -->
<hibernate-mapping package="com.xdh.domain">
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<!-- <class name="com.xdh.domain.Customer" table="cst_customer"> -->
<class name="Customer" table="cst_customer">
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="cust_id" column="cust_id">
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<!-- type
1.java类型:<property name="cust_name" column="cust_name" type="java.lang.String"></property>
2.hibernate类型:<property name="cust_name" column="cust_name" type="string"></property>
3.数据库类型<property name="cust_name" column="cust_name">
<column name="cust_name" sql-type="varchar" ></column>
</property>
-->
<property name="cust_name" column="cust_name"></property>
<property name="cust_source" column="cust_source"></property>
<property name="cust_industry" column="cust_industry"></property>
<property name="cust_level" column="cust_level"></property>
<property name="cust_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
</class>
</hibernate-mapping>
2.主配置文件:
必选属性配置(5个):
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate01</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">root</property>
<!-- 数据库方言
不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
sql99标准: DDL 定义语言 库表的增删改查
DCL 控制语言 事务 权限
DML 操纵语言 增删改查
注意: MYSQL在选择方言时,请选择最短的方言.通用语法,针对不同引擎
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
可选属性配置:
<!-- 将hibernate生成的sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
<property name="hibernate.format_sql">true</property>
<!--
## auto schema export 自动导出表结构. 自动建表
#hibernate.hbm2ddl.auto create 自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
#hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
#hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
#hibernate.hbm2ddl.auto validate 校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败,抛出异常
-->
<property name="hibernate.hbm2ddl.auto">update</property>
元数据引入配置:
<!-- 引入orm元数据
路径书写: 填写src下的路径
-->
<mapping resource="com/xdh/domain/customer.hbm.xml"/>
API详解:
四个对象
1.Configuration
Configuration功能: 配置加载类,用于加载主配置,orm元数据加载
package com.xdh.api;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
//Configuration功能: 配置加载类,用于加载主配置,orm元数据加载
public class ConfigurationDemo {
@Test
public void fun1(){
//1 创建,调用空参构造
Configuration conf = new Configuration();
//2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
conf.configure();
//3 读取指定orm元数据(扩展),如果主配置中已经引入映射配置.不需要手动加载
//conf.addResource(resourceName);
//conf.addClass(persistentClass);
//4 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
}
}
2.SessionFactory
SessionFactory功能: 用于创建操作数据库核心对象session对象的工厂.
简单说功能就一个—创建session对象
注意:1.sessionfactory 负责保存和使用所有配置信息.消耗内存资源非常大.
2.sessionFactory属于线程安全的对象设计.
结论: 保证在web项目中,只创建一个sessionFactory.
package com.xdh.api;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class SessionFactoryDemo {
@Test
public void fun1(){
//1 创建,调用空参构造
Configuration conf = new Configuration();
//2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
conf.configure();
//3 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//--------------------------------------------------
//4 获得session
//打开一个新的session对象
sf.openSession();
//获得一个与线程绑定的session对象
sf.getCurrentSession();
}
}
3.Session
session对象功能: 表达hibernate框架与数据库之间的连接(会话).session类似于JDBC年代的connection对象,还可以完成对数据库中数据的增删改查操作.
session是hibernate操作数据库的核心对象
package com.xdh.api;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import com.xdh.domain.Customer;
public class SessionDemo {
@Test
//事务操作
public void fun1(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//获得操作事务的tx对象
//Transaction tx = session.getTransaction();
//开启事务
//tx.begin();
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
//----------------------------------------------
tx2.commit();//提交事务
tx2.rollback();//回滚事务
session.close();//释放资源
sf.close();//释放资源
}
@Test
//session的新增
public void fun2(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
Customer c = new Customer();
c.setCust_name("sogou");
session.save(c);
//----------------------------------------------
tx2.commit();//提交事务
session.close();//释放资源
sf.close();//释放资源
}
@Test
//session的查询
//查询id为1的customer对象
public void fun3(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
Customer customer = session.get(Customer.class, 1l);
System.out.println(customer);
//----------------------------------------------
tx2.commit();//提交事务
session.close();//释放资源
sf.close();//释放资源
}
@Test
//session的修改
//修改id为1的customer对象的name属性为黑马程序员
public void fun4(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
//1 获得要修改的对象
Customer c = session.get(Customer.class, 1l);
//2 修改
c.setCust_name("firefox");
//3 执行update
session.update(c);
//----------------------------------------------
tx2.commit();//提交事务
session.close();//释放资源
sf.close();//释放资源
}
@Test
//session的删除
//删除id为1的customer对象
public void fun5(){
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
Session session = sf.openSession();
//4 session获得操作事务的Transaction对象
//开启事务并获得操作事务的tx对象(建议使用)
Transaction tx2 = session.beginTransaction();
//----------------------------------------------
//1 获得要修改的对象
Customer c = session.get(Customer.class, 1l);
//2 调用delete删除对象
session.delete(c);
//----------------------------------------------
tx2.commit();//提交事务
session.close();//释放资源
sf.close();//释放资源
}
}
4.Transaction
事务开启,事务提交,事务回滚
整合成一个返回session对象的Hibernate工具类:
package com.xdh.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory sf;
static{
//1 创建,调用空参构造
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
sf = conf.buildSessionFactory();
}
//获得session => 获得全新session
public static Session openSession(){
//3 获得session
Session session = sf.openSession();
return session;
}
//获得session => 获得与线程绑定的session
public static Session getCurrentSession(){
//3 获得session
Session session = sf.getCurrentSession();
return session;
}
public static void main(String[] args) {
System.out.println(HibernateUtils.openSession());
}
}
hibernate中的实体规则
1.实体类创建的注意事项:
1)持久化类提供无参构造(newInstance方法需要调用无参构造)
2)成员变量私有,提供get/set方法,即提供属性
3)持久化类中的属性,尽量使用包装类型
包装类型的初始值为null,防止数据库中有空值给基本类型赋不上值
4)持久化类需要提供oid,与数据库中主键对应
没有主键的表无法映射到hibernate中
5)不要用final修饰class
hibernate使用cglib代理生成代理对象,代理对象继承被代理对象,如果被final修饰将无法生成代理对象
2.主键类型:
1)自然主键
表的业务中有某业务列符合主键规则,可作为主键使用
2)代理主键
创建一个没有业务意义的列作为主键
3.主键生成策略
元数据orm中关于主键的配置:
<id name="cust_id" column="cust_id">
<!-- generator:主键生成策略 ,即每条记录录入时,主键生成规则。
1.identity:主键自增,由数据库来维护逐主键值,录入时不需要指定主键
2.sequence: Oracle中的主键生成策略.
3.increment(了解): 主键自增.由hibernate来维护.每次插入前会先查询表中id最大值.+1作为新主键值.
并发访问时,会存在线程问题
4.hilo(了解): 高低位算法.主键自增.由hibernate来维护.开发时不使用.
5.native:hilo+sequence+identity 自动根据方言三选一策略.
6.uuid: 产生随机字符串作为主键. 主键类型必须为string 类型.
7.assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.
-->
<generator class="native"></generator>
</id>
hibernate中的对象状态
三种状态:
1.瞬时状态
没有id,没有在session缓存中
2.持久化状态
有id,在session缓存中
特点:持久化状态对象的任何变化都会自动同步到数据库中
3.游离/托管状态
有id,没有在session缓存中
Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
c.setCust_name("baidu公司");//瞬时状态
session.save(c);//持久化状态
tx.commit();
session.close();//关闭后,有id,没有关联,游离/托管状态
save方法本质是一个对象状态转化,为了生成id
三种状态转换:

hibernate:一级缓存
缓存:提高效率
提高效率手段:
1.查询时,第一次查询时,对象会放入缓存,再次查询则返回缓存中数据,提高查询效率
//执行以下三条语句,只执行一次select
Customer c1 = session.get(Customer.class, 1l);
Customer c2 = session.get(Customer.class, 1l);
Customer c3 = session.get(Customer.class, 1l);
System.out.println(c1==c3);//返回true

2.修改时,使用快照对比修改前后对象属性区别,只执行一次修改,减少不必要的修改语句发送
//假设当cust_id为1l时,cust_name为哈哈,以下代码只执行了select(快照)
Customer customer = session.get(Customer.class, 1l);
customer.setCust_name("呵呵");
customer.setCust_name("哈哈");

hibernate的事务
在主配置文件中配置事务的隔离级别:
<!-- 指定hibernate操作数据库时的隔离级别
#hibernate.connection.isolation 1|2|4|8
0001 1 读未提交
0010 2 读已提交
0100 4 可重复读
1000 8 串行化
-->
<property name="hibernate.connection.isolation">4</property>
在项目中管理事务:
业务开始之前打开事务,业务执行之后提交事务,执行过程中出现异常,回滚事务
在Dao层操作数据库需要使用到session对象,在service层控制事务也使用到session对象,这时需确保dao层和service层使用的是同一个session
在hibernate中,使用sessionFactory.getCurrentSession()即获得了与当前线程绑定的session对象
注意:
1.调用getCurrentSession()方法需在主配置文件中配置:
<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
2.通过getCurrentSession()方法获得的session对象,当事务提交时,session会自动关闭,不能手动关闭
hibernate中的批量查询
1.HQL查询
hibernate独家查询语言,属于面向对象的查询语言,select * from 完整类名 where 属性名 = XXX,不出现数据库表名和列名
- 基本查询:
1)返回多条:
//1> 书写HQL语句
//String hql = " from com.xdh.domain.Customer ";
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list(); // 返回list结果
2)返回单条:
String hql = " from Customer where cust_id = 1l";
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
Customer c =(Customer) query.uniqueResult();//接收唯一的查询结果
- 条件查询:
1)?占位符的使用
//1> 书写HQL语句
String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
//query.setLong(0, 1l);
query.setParameter(0, 1l);//通用
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
这里注意索引从0开始,JDBC的setString()从1开始
2)命名占位符的使用
//1> 书写HQL语句
String hql = " from Customer where cust_id = :cust_id "; //冒号后为自定义占位符名称
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id", 1l);//键对应自己定义的占位符名称
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
- 分页查询:
//1> 书写HQL语句
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置分页信息 limit ?,?
query.setFirstResult(1);//第几条
query.setMaxResults(1);//展示几条
//3> 根据查询对象获得查询结果
List<Customer> list = query.list();
2.Criteria查询
hibernate自创的无语句面向对象查询
- 基本查询
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();//多条
Customer c = (Customer) criteria.uniqueResult();//单条
- 条件查询
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//添加查询参数 => 查询cust_id为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
//执行查询获得结果
Customer c = (Customer) criteria.uniqueResult();
注意:
// > gt
// >= ge
// < lt
// <= le
// == eq
// != ne
// in in
// between and between
// like like
// is not null isNotNull
// is null isNull
// or or
// and and
- 分页查询
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置分页信息 limit ?,?
criteria.setFirstResult(1);
criteria.setMaxResults(2);
//执行查询
List<Customer> list = criteria.list();
- 查询总记录数
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询的聚合函数 => 总行数
criteria.setProjection(Projections.rowCount());
//执行查询
Long count = (Long) criteria.uniqueResult();
原生SQL查询
- 基本查询
1)返回数组List
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//3 调用方法查询结果
List<Object[]> list = query.list();//多条
//query.uniqueResult();//单条
2)返回对象List
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
- 条件查询
//1 书写sql语句
String sql = "select * from cst_customer where cust_id = ? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 1l);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
Customer c = (Customer)query.uniqueResult();
注意:索引从0开始
- 分页查询
//1 书写sql语句
String sql = "select * from cst_customer limit ?,? ";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, 0);
query.setParameter(1, 1);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
多表关系在hibernate中的表达
1.一对多/多对一
1)数据库中表达
从表外键指向主表主键
2)在对象中的表达
- 主对象中:
private Set<从对象> xx;
//使用set集合,表达一对多关系
private Set<LinkMan> linkMens = new HashSet<LinkMan>();
- 从对象中:
private 主对象 xx;
//表达多对一关系
private Customer customer ;
3)元数据orm中的表达:
- 主对象的映射文件:
<!-- 集合,一对多关系,在配置文件中配置 -->
<!--
name属性:集合属性名
column属性: 外键列名
class属性: 关联的对象完整类名
-->
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
- 从对象的映射文件:
<!-- 多对一 -->
<!--
name属性:引用属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" >
</many-to-one>
测试:
Customer c = new Customer();
c.setCust_name("baidu");
LinkMan lm1 = new LinkMan();
lm1.setLkm_name("mrli");
LinkMan lm2 = new LinkMan();
lm2.setLkm_name("missma");
//表达一对多,客户下有多个联系人
//如果customer元数据配置了放弃维护关系,以下两行代码无需执行
c.getLinkMens().add(lm1);
c.getLinkMens().add(lm2);
//表达多对一,联系人属于哪个客户
lm1.setCustomer(c);
lm2.setCustomer(c);
session.save(c);
//如果customer元数据配置了cascade="save-update",以下两行代码无需执行
session.save(lm1);
session.save(lm2);
补充级联和关系(外键)维护属性配置:
主对象元数据中:
<!--
级联操作: cascade
save-update: 级联保存更新,即主对象更新数据,从对象同步更新
delete:级联删除
all:save-update+delete
级联操作: 简化操作.目的就是为了少两行代码.
-->
<!-- inverse属性: 配置关系是否维护.
true: customer不维护关系
false(默认值): customer维护关系
inverse属性: 性能优化.提高关系维护的性能.
原则: 无论怎么放弃,总有一方必须要维护关系.
一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
-->
<set name="linkMens" inverse="true" cascade="save-update" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
从对象元数据中:
<!--
级联操作: cascade
save-update: 级联保存更新
delete:级联删除
all:save-update+delete
级联操作: 简化操作.目的就是为了少些两行代码.
-->
<!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方. -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="save-update">
</many-to-one>
注意:
1).主从对象元数据中只需一方配置cascade=""
2).在保存时,双方都会维护外键关系,关系维护两次,冗余了
3).外键在的一方不能放弃维护关系,
2.多对多
1)数据库中表达
使用中间表,至少两类,都是外键列,分别引用两张表的主键
2)实体中表达
实体A:
private Set b;
private Set<Role> roles = new HashSet<Role>();
实体B:
private Set a;
private Set<User> users = new HashSet<User>();
3)元数据orm中表达
User对象元数据:
<!-- 多对多关系表达 -->
<!--
name: 集合属性名
table: 配置中间表名
key
|-column:外键,别人引用"我"的外键列名
class: 我与哪个类是多对多关系
column:外键.我引用别人的外键列名
-->
<!-- cascade级联操作:
save-update: 级联保存更新
delete:级联删除
all:级联保存更新+级联删除
结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
如果使用delete操作太过危险.尤其在多对多中.不建议使用.
-->
<set name="roles" table="sys_user_role" cascade="save-update" >
<key column="user_id" ></key>
<many-to-many class="Role" column="role_id" ></many-to-many>
</set>
Role对象元数据:
<!-- 使用inverse属性
true: 放弃维护外键关系
false(默认值):维护关系
结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
-->
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id" ></key>
<many-to-many class="User" column="user_id" ></many-to-many>
</set>
测试:
package com.xdh.onemany;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.xdh.domain.Role;
import com.xdh.domain.User;
import com.xdh.utils.HibernateUtils;
public class TestMany2Many {
@Test
//保存员工以及角色
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
//1> 创建两个 User
User u1 = new User();
u1.setUser_name("张三");
User u2 = new User();
u2.setUser_name("李四");
//2> 创建两个 Role
Role r1 = new Role();
r1.setRole_name("程序员");
Role r2 = new Role();
r2.setRole_name("会计");
//3> 用户表达关系
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
u2.getRoles().add(r2);
//4> 角色表达关系
//双方默认都维护关系,都会向中间表中插入数据,违反主键唯一原则
//所以必须只能指定一方维护关系,不指定以下代码报错
r1.getUsers().add(u1);
r1.getUsers().add(u2);
r2.getUsers().add(u1);
r2.getUsers().add(u2);
//5> 调用Save方法一次保存
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
@Test
//为张三新增一个角色
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
//1> 获得张三用户
User user = session.get(User.class, 1l);
//2> 创建公关角色
Role r = new Role();
r.setRole_name("项目经理");
//3> 将角色添加到用户中
user.getRoles().add(r);
//4> 将角色转换为持久化
//配了级联后以下代码不用写
//session.save(r);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
@Test
//为张三解除一个角色
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
//1> 获得张三用户
User user = session.get(User.class, 1l);
//2> 获得要操作的角色对象(会计,项目经理)
Role r1 = session.get(Role.class, 2l);
Role r2 = session.get(Role.class, 3l);
//3> 将角色从用户的角色集合中移除
user.getRoles().remove(r1);
user.getRoles().remove(r2);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
}
hibernate查询总结:
1.get()
2.对象属性导航查询
3.HQL
4.Criteria
5.原生SQL
HQL查询:
1)基础语法
String hql = " from com.xdh.domain.Customer ";//完整写法
String hql2 = " from Customer "; //简单写法
String hql3 = " from java.lang.Object ";
Query query = session.createQuery(hql3);
List list = query.list();
2)排序
String hql1 = " from com.xdh.domain.Customer order by cust_id asc ";//完整写法
String hql2 = " from com.xdh.domain.Customer order by cust_id desc ";//完整写法
Query query = session.createQuery(hql2);
List list = query.list();
3)条件查询
String hql1 = " from com.xdh.domain.Customer where cust_id =? ";//完整写法
String hql2 = " from com.xdh.domain.Customer where cust_id = :id ";//完整写法
Query query = session.createQuery(hql2);
// query.setParameter(0, 2l);
query.setParameter("id", 2l);
List list = query.list();
4)分页查询
String hql1 = " from com.xdh.domain.Customer ";//完整写法
Query query = session.createQuery(hql1);
//limit ?,?
query.setFirstResult(2);// (当前页数-1)*每页条数
query.setMaxResults(2);
List list = query.list();
5)聚合函数查询
String hql1 = " select count(*) from com.xdh.domain.Customer ";//完整写法
String hql2 = " select sum(cust_id) from com.xdh.domain.Customer ";//完整写法
String hql3 = " select avg(cust_id) from com.xdh.domain.Customer ";//完整写法
String hql4 = " select max(cust_id) from com.xdh.domain.Customer ";//完整写法
String hql5 = " select min(cust_id) from com.xdh.domain.Customer ";//完整写法
Query query = session.createQuery(hql5);
Number number = (Number) query.uniqueResult();
6)投影查询(即查询部分属性)
String hql1 = " select cust_name from com.xdh.domain.Customer ";
String hql2 = " select cust_name,cust_id from com.xdh.domain.Customer ";
String hql3 = " select new Customer(cust_id,cust_name) from com.xdh.domain.Customer ";
Query query = session.createQuery(hql3);
List list = query.list();
7)内连接
- 内连接
String hql = " from Customer c inner join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
- 迫切内连接
String hql = " from Customer c inner join fetch c.linkMens ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
内连接是把查询结果封装在Object数组里,数组里有Customer和Linkman两个对象,而迫切内连接则是把查询结果封装在一个对象里
8)左连接
String hql = " from Customer c left join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
9)右连接
String hql = " from Customer c right join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
Criteria查询:
1)基本语法
Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();
2)条件查询
Criteria c = session.createCriteria(Customer.class);
// c.add(Restrictions.idEq(2l));
c.add(Restrictions.eq("cust_id",2l));
List<Customer> list = c.list();
3)分页查询
Criteria c = session.createCriteria(Customer.class);
//limit ?,?
c.setFirstResult(0);
c.setMaxResults(2);
List<Customer> list = c.list();
4)排序
Criteria c = session.createCriteria(Customer.class);
c.addOrder(Order.asc("cust_id"));
//c.addOrder(Order.desc("cust_id"));
List<Customer> list = c.list();
5)聚合函数
Criteria c = session.createCriteria(Customer.class);
//设置查询目标
c.setProjection(Projections.rowCount());
List list = c.list();
6)离线Criteria
当使用Criteria查询时,查询条件只能在dao层指定,为了在web层接收参数,所以使用离线Criteria
非离线:

离线:

//Service/web层
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致)
//----------------------------------------------------
//Dao层
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = dc.getExecutableCriteria(session);
List list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
查询优化:
1.类级别查询
1)get方法: 立即加载,执行方法时立即发送sql语句查询结果
2)load方法:
在类上配置:
<class name="Customer" table="cst_customer" lazy="true">
lazy:true 加载时,不查询,使用时才查询b(默认)
lazy:false 加载时立即查询.
Transaction tx = session.beginTransaction();
Customer c = session.load(Customer.class, 2l);
System.out.println(c);//输出c代表使用对象了,执行该条语句才会查询
2.关联级别查询
1)集合策略
即把联系人集合加载到客户类中
<!--
lazy属性: 决定是否延迟加载
true(默认值): 延迟加载,懒加载
false: 立即加载
extra: 极其懒惰
fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据
select(默认值): 单表查询加载
join: 使用多表查询加载集合
subselect:使用子查询加载集合
-->
<!-- batch-size: 抓取集合的数量为3.
抓取客户的集合时,一次抓取几个客户的联系人集合.
-->
<set name="linkMens" fetch="select" lazy="true" batch-size="3">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
- fetch:select 单表查询
lazy:true 使用时才加载集合数据. - fetch:select 单表查询
lazy:false 立即记载集合数据 - fetch:select 单表查询
lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句) - fetch:join 多表查询
lazy:true|false|extra 失效.立即加载. - fetch: subselect 子查询
lazy: true 懒加载 - fetch: subselect 子查询
lazy: false 立即加载 - fetch: subselect 子查询
lazy: extra 极其懒惰
2)关联属性策略
即把客户类加载到联系人类中
<!--
fetch 决定加载的sql语句
select: 使用单表查询
join : 多表查询
lazy 决定加载时机
false: 立即加载
proxy: 由customer的类级别加载策略决定.
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy" >
- fetch:select 单表查询
lazy:proxy
customer-true 懒加载 - fetch:join 多表
lazy: 失效 - fetch:select 单表查询
lazy:proxy
customer-false 立即加载
总结:
1.为了提高效率,fetch的应该用select,lazy应该用true,即都用默认值
2.当用了懒加载后,可能会存在session关闭了,需要的数据还没有返回前端
解决没有session的情况:加一个过滤器

324

被折叠的 条评论
为什么被折叠?



