hibernate入门
hibernate框架
hibernate的持久化解决方案将开发者从复杂的JDBC访问中释放出来,用户无需关注底层的JDBC操作,一面想对象的形式进行持久层操作。
将应用层从底层的JDBC/JTA API中抽象出来。通过配置文件管理底层JDBC链接,让Hibernate解决持久化访问的实现。
hibernate主要对象和功能
https://blog.csdn.net/weixin_34306446/article/details/91927193
hibernate的api(就是操作的时候使用的对象)
Configuration接口:配置和启动Hibernate,创建SessionFactory对象,Hibernate应用通过Configuration实例获得对象-关系映射文件的源数据,以及动态配置Hibernate的属性,然后创建sessionFactory实例;
SessionFactory接口:初始化Hibernate,充当数据存储源的代理,创建session对象;
session接口:也成为了持久化管理器,提供持久化相关的操作,如保存、更新、删除、加载和查询对象;
Transaction:接口:管理实务;
Query和Criteria接口:执行数据库查询,Query接口用于执行HQL数据库查询,而Criteia接口用于QBC检索方式。
持久化对象
1、创建pojo
2、创建student.hbm.xml(注意pojo和hbm.xml映射文件要在同一个目录下面)
student.java
package com.qst.chapter05.pojos;
public class Student {
// 属性
private String id;
private String name;
private int score;
// 省略getter和setter方法
}
student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qst.chapter05.pojos.Student" table="STUDENTS">
<id name="id" column="ID">
<generator class="uuid.hex" />
</id>
<property name="name" column="NAME" type="string" not-null="true" />
<property name="score" column="SCORE" type="java.lang.Integer" not-null="true" />
</class>
</hibernate-mapping>
hibernate配置文件
hibernate配置文件用于配置访问数据库的一些参数,比如链接数据库的URL链接字符串、用户名、密码以及是否创建或更新表等信息。
常用的形式是新建hibernate.cfg.xml文件
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>
<!-- 配置访问Oracle数据库参数信息 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="connection.username">scott</property>
<property name="connection.password">scott123</property>
<!-- 在控制台显示SQL语句 -->
<property name="show_sql">true</property>
<!--根据需要自动生成、更新数据表 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注册所有ORM映射文件 -->
<mapping resource="com/qst/chapter05/pojos/Student.hbm.xml" />
<mapping resource="com/qst/chapter05/pojos/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
hibernae-configuration,hibernate配置文件根元素
session-factory,根元素的子元素
property,session-factory子元素,用于配置方位数据库参数信息,可以有多个property
mapping:session-factory子元素,用于注册所有orm樱色号文件,每个mapping子元素注册一个hibernate映射文件,可以有多个mapping子元素。
hibernate配置文件常用属性
属性 | 功能描述 |
---|---|
hibernate.dialect | 针对不同数据库提供不同方言,允许hibernate针对特定数据库生成优化sql语句 |
hibernate.connection.driver_class | 数据库驱动类 |
hibernate.connection.datasource | 数据库原的jndi名字 |
hibernate.connection.url | JNDI数据库提供的URL |
hibernate.connection.username | 连接数据库用户名 |
hibernate.connection.password | 链接数据库的password |
hibernate.connection.pool_size | 数据库连接池的最大容量 |
hibernate.show_sql | 是否输出hibernate操作数据库使用的sql语句 |
hibernate.format_sql | 是否格式化输出的sql语句 |
hibernate.hbm2ddl.auto | 是否根据映射文件自动创建数据库表,有create、create-drop\updateqizhong,create会根据pojo创建表,每次运行重新生成表;值为create-drop,关闭sessionFactory是自动删除创建的表;update最常用属性,不会删除以前的行记录 |
hibernate映射文件
hibernate映射文件根元素是hibernate-mapping,该元素有多个class子元素,每个class元素对应一个pojo持久化类的映射,将类和表之间关系进行映射。
user.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qst.chapter05.pojos.User" table="tbUsers">
<id name="id" column="ID">
<generator class="native"></generator>
</id>
<property name="userName" column="USERNAME" type="string" not-null="true"></property>
<property name="userPwd" column="USERPWD" type="string" not-null="true"></property>
<property name="role" column="ROLE" type="java.lang.Interger" not-null="true"></property>
</class>
</hibernate-mapping>
class元素常用属性
属性 | 功能描述 |
---|---|
name | 持久化类名(java pojo类) |
table | 持久化类映射的表名(数据表名) |
discriminator-value | 区分不同子类的值 |
mutable | 指定持久化类实例是否可变,默认为true |
proxy | 延迟装载是的代理,可以是该类自己的名称 |
id常用属性
属性 | 功能描述 |
---|---|
name | 标识属性名 |
type | 标识属性的数据类型,改数据类型既可以是hibernate内奸诶性,也可以是java类型 |
column | 标识属性锁映射的数据库中标的列名 |
unsaved-value | 指定刚创建、未保存的某个实例的表示属性值 |
access | 指定访问表示属性的访问策略,默认property |
主键生成器列表
类型名 | 功能描述 |
---|---|
increment | 获取数据库表所有主键最大值,最大值基础上加1 |
identity | 自动增长。MS SQL Server、MySQL和DB2数据库可以设置表单额某个字段的数值增长 |
sequence | 序列。Oracle、DB2等数据库可以创建一个序列,然后从序列中获取当前序列号作为主键值 |
hilo | 高低位高效算法产生主键 |
seqhilo | 使用指定sequence获取高位置 |
uuid | 采用128位uuid算法生成字符串类型的主键 |
guid | 采用guid字符串产生主键值 |
native | 有hibernate根据使用的数据库支持能力从identity、sequence或者hilo中选择,例如oracle使用sequence,MySQL用identity |
assigned | 指派值 |
foreign | 通过关联持久化对象为主键赋值 |
在使用生成策略。
应用系统不需要分布式,数据库支持情况下使用sequence、identity、hilo、seqhilo和uuid
应用需要使用多个数据库或者进行分布式部署,使用uuid最佳
创建hibernate完整过程
1、配置hibernate应用环境,在应用中添加hibernate所需要的的jar包,创建hibernate配置文件;
2、编写po
3、创建configuration对象
4、创建sessionfactory对象;
5、获取session对象
6、transaction管理实务
7、使用Query进行HQL查询后利用Criteria实现条件查询
session中的方法
方法 | 功能描述 |
---|---|
save() | 保持持久化对象,在数据库中新增一条记录 |
get() | 获取数据库中一条记录,当未找到符合条件的持久化对象是返回null |
load() | 获取数据库中一条记录,当没找到符合条件的持久化对象是抛出异常 |
update() | 更新数据库中敌营的数据 |
delete() | 删除数据库中的一条记录 |
session获取多条数据查询
使用Query进行hql查询或使用Criteria进行查询
Query query = session.createQuery("from User");
List<User> list = query.list();
Criteria criteria = session.createCriteria(Student.class);
List<Student> list = criteria.list();
导入相应的hibernate包
新建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>
<!-- 配置访问Oracle数据库参数信息 -->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="connection.username">scott</property>
<property name="connection.password">scott123</property>
<!-- 在控制台显示SQL语句 -->
<property name="show_sql">true</property>
<!--根据需要自动生成、更新数据表 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注册所有ORM映射文件 -->
<mapping resource="com/qst/chapter05/pojos/Student.hbm.xml" />
<mapping resource="com/qst/chapter05/pojos/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
创建pojo、pojo.hbm.xml、修改hibernate.cfg.xml添加mapping映射文件
User.java
package com.qst.chapter05.pojos;
import java.io.Serializable;
public class User implements Serializable {
/* 用户ID */
private Integer id;
/* 用户名 */
private String userName;
/* 密码 */
private String userPwd;
/* 权限 */
private Integer role;
/* 默认构造方法 */
public User() {
}
/* 根据属性创建 构造方法 */
public User(String userName, String userPwd,Integer role) {
this.userName = userName;
this.userPwd=userPwd;
this.role=role;
}
//省略getter和setter方法
user.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qst.chapter05.pojos.User" table="tbUsers">
<id name="id" column="ID">
<generator class="native"></generator>
</id>
<property name="userName" column="USERNAME" type="string" not-null="true"></property>
<property name="userPwd" column="USERPWD" type="string" not-null="true"></property>
<property name="role" column="ROLE" type="java.lang.Interger" not-null="true"></property>
</class>
</hibernate-mapping>
hibernate.cfg.xml在session-factory子元素最后添加
<mapping resource="com/qst/chapter05/pojos/User.hbm.xml" />
测试
UserDemo
package com.qst.chapter05.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import com.qst.chapter05.pojos.User;
public class UserDemo {
public static void main(String[] args) {
// 创建User对象
User user = new User("zhangsan", "123", 1);
// 实例化Configuration
Configuration configuration = new Configuration();
// 加载hibernate.cfg.xml文件
configuration.configure("/hibernate.cfg.xml");
// 创建SessionFactory
// Hibernate4.3创建SessionFactory的方式
StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder();
standardServiceRegistryBuilder.applySettings(configuration
.getProperties());
SessionFactory sessionFactory = configuration
.buildSessionFactory(standardServiceRegistryBuilder.build());
// 打开Session
Session session = sessionFactory.openSession();
// 开始一个事务
Transaction trans = session.beginTransaction();
// 持久化操作
session.save(user);
// 提交事务
trans.commit();
// 关闭Session
session.close();
}
}
pojo状态
瞬时状态:刚刚new对象,没有持久化,没有与hibernate session关联,不处于session的缓存之中。处于顺势状态的对象被称为瞬态对象,瞬态对象不会被持久化到数据库。也不会被赋予持久化表示。
持久化状态:已经被持久化加入session缓存中,数据库表中记录对应,并且拥有一个持久化表示。持久化状态对象可以保存,也可以被夹在。hi贝尔纳特检测到持久化状态的对象可以任何改动,并且在session关闭或者transaction提交的时候更新数据库中的对应数据,不需要手动更新。
脱管状态:已经被持久化,不再session缓存中,如果对象曾经处于持久化状态,但是与之关联的session关闭后,该对象变成托管状态,如果该对象与某个session重新关联又变成持久化状态
hibernate工具类
HibernateUtils.java
package com.qst.chapter05.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal
= new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder();
private static SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
/* 静态代码块创建SessionFactory */
static {
try {
configuration.configure(configFile);
//Hibernate4.3创建SessionFactory的方式
standardServiceRegistryBuilder.applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(standardServiceRegistryBuilder.build());
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateUtils() {
}
/**
* 返回ThreadLocal中的session实例
*/
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
/**
* 返回Hibernate的SessionFactory
*/
public static void rebuildSessionFactory() {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory(standardServiceRegistryBuilder.build());
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
/**
* 关闭Session实例并且把ThreadLocal中副本清除
*/
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
/**
* 返回SessionFactory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void setConfigFile(String configFile) {
HibernateUtils.configFile = configFile;
sessionFactory = null;
}
public static Configuration getConfiguration() {
return configuration;
}
}
HibernateSessionDemo.java
package com.qst.chapter05.demo;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.qst.chapter05.pojos.User;
import com.qst.chapter05.util.HibernateUtils;
public class HibernateSessionDemo {
public static void main(String[] args) {
// 调用getUser()方法获取用户对象
User user = getUser(new Integer(1));
System.out.println("--------原始数据-----------");
System.out.println(user.getId() + "\t" + user.getUserName()
+ "\t" + user.getUserPwd() + "\t" +user.getRole());
user.setUserPwd("987654");
// 调用changeUser()方法修改用户对象信息
changeUser(user);
System.out.println("--------修改后的数据-----------");
System.out.println(user.getId() + "\t" + user.getUserName()
+ "\t" + user.getUserPwd() + "\t" +user.getRole());
}
/* 获取用户 */
public static User getUser(Integer key) {
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
// 根据主键获取用户对象
User user = (User) session.get(User.class, key);
trans.commit();
HibernateUtils.closeSession();
return user;
}
/* 修改用户信息 */
public static void changeUser(User user) {
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
// 更新
session.update(user);
trans.commit();
HibernateUtils.closeSession();
}
}
hibernate进阶
hibernate关联关系
单向N-1关系(many-to-one) 比如订单和客户
实际开发当中不建议使用单向1-N关联,建议使用双向1-N关联,在1端配置<set>,在N端配置<many-to-one>元素即可形成双向关联
1、在N类中添加1类的对象,比如
Order.java中添加
private Customer customer;
2、order.hbm.xml中添加
<many-to-one name="customer" column="CUSTOMER_ID" class="Customer"/>
3、检查hibernate.cfg.xml是否添加链接
N-1关联成功建立
many-to-one属性介绍
属性名 | 描述 |
---|---|
name | 指定属性名称,例如order类中的customer属性名 |
column | 指定进行关联的外键列的列名,例如,order表的外键CUSTOMER_ID |
class | 指定关联实体的类名,默认通过反射得到该属性所属类的类名 |
cascade | 指定哪些持久化操作会从主表记录级联到子表记录 |
fetch | 指定hibernate抓取策略可以join和select |
property-ref | 指定关联类中的属性,该属性和贝类外检对象,默认直接使用地方关联类的主键 |
access | 指定hibernate访问此关联属性的访问策略,默认是property |
unique | 指定hibernatte通过DDL为外检列添加唯一约束,可以用作property-ref的目标属性 |
lazy | 指定引用关联实体的延迟加载特性,该属性只能接受false、proxy、no-proxy三个值:hibernate默认会启动但实力代理,当指定no-proxy是实例变量第一次被访问采用延迟抓取,指定为false关联实体总是被预先抓取。 |
not-null | 指定DDL为外键字段添加非空约束,如果为true表示不为空。默认为false,该属性会影响hi贝尔纳特运行行为,比如hibernate保存order对象,检查customer属性是否为null |
not-found | 该属性指定当外检参照的主表记录不存在是如何处理,是ignore和exeption(默认) |
formula | 指定一个sql表达式,改外键值根据sql表达式计算 |
实例请看第六章order和customer N-1的实例 193页
单向1-N关系映射(set) 比如客户和订单
1、添加customer中的属性,表示1-N
private Set orders = new HashSet(0);
2、customer.hbm.xml的class紫属性中添加set标签
<set name="orders">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order"/>
</set>
双向关联(1-N)实际开发推荐使用
双向关联就是单向1-N和N-1同时配置,注意实际开发建议同时配置。
步骤
1、在N类中添加1类的对象,比如
Order.java中添加
private Customer customer;
2、order.hbm.xml中添加
<many-to-one name="customer" column="CUSTOMER_ID" class="Customer"/>
3、添加customer中的属性,表示1
private Set<Order> orders = new HashSet<Order>(0);
4、customer.hbm.xml的class紫属性中添加set标签
<set name="orders">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order"/>
</set>
1-1关联(one-to-one)
one-to-one在两个对象中加上相应对象的属性
被关联对象修改,同时对关联对象进行级联操作
基于外键单向,可以理解为特殊的单向N-1关系,N端为1 N端用many-to-one 设置unique属性
基于主键单向,基于主键的关联持久化类不能拥有自己的主键生成策略,主键有关联实体负责生成
基于外键双向,外键可以房子啊任意一边,存储外键的一端增加<many-to-one>元素,另一端需要使用<one-to-one>元素
基于主键的双向1-1关联,连个关联表使用相同的主键值,其中一个表的主键值共享另外一个表的主键值
基于主键双向,关联和被关联对象都用one-to-one,但是被关联对象设置cascade属性,关联对象设置constrained属性
基于外键的双向1-1
1、IdCard添加
private Customer customer;
2、Customer添加
private IdCard idCard;
2、IdCard.hbm.xml添加
<one-to-one name="customer" class="Customer" constrained="true"/>
3、Customer.hbm.xml添加
<many-to-one name="idCard" class="IdCard" cascade="all" column = "IDCARD_ID" unique="true"/>
基于主键的双向1-1
1、添加IdCard.hbm.xml
<one-to-one name="customer" class="Customer" class="Customer" constrained="true">
2、添加Customer.hbm.xml
<one-to-one name="idCard" class="IdCard" cascade="all">
N-N拆分两个1-N关联实现(Order和Product)
实际开发当中,数据库表之间N-N关联使用不太多,通常是拆分成连个1-N关联实现,同样在hibernate中也是使用两个1-N替换N-N关联。
1、创建中间表OrderItem(id,order,product,)
2、orderitem.hbm.xml添加<many-to-one>对应order和product
3、在order.hbm.xml和product.hbm.xml中添加<set>标签 <one-to-many>
创建OrderItem.java
package com.qst.chapter06.pojos;
public class OrderItem {
private Integer id;
private Order order;
private Product product;
private Integer quantity;
private Double purchasePrice;
//省略getter和setter方法
}
order.hbm.xml
添加<set> 1-N标签
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.qst.chapter06.poojos">
<class name="OrderItem" table="ORDERITEM">
<id name="id" column="ID">
<generator class="native"></generator>
</id>
<many-to-one name="order" class="Order" column="ORDER_ID"></many-to-one>
<many-to-one name="product" class="Product" column="PRODUCT_ID"></many-to-one>
<property name="quantity" column="QUANTITY" type="integer"></property>
<property name="purchasePrice" column="PURCHASEPRICE" type="double"></property>
</class>
</hibernate-mapping>
Product.hbm.xml
添加<1-n标签>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.qst.chapter06.poojos">
<class name="Product" table="PRODUCT">
<id name="id" column="ID">
<generator class="native"/>
</id>
<property name="name" column="NAME" type="string" not-null="true"></property>
<property name="price" column="PRICE" type="double" not-null="true"></property>
<property name="description" column="DESCRIPTION" type="string"></property>
<set name="orders" table="ORDERITEM">
<key column="PRODUCT_ID"></key>
<many-to-many class="Order" column="ORDER_ID"></many-to-many>
</set>
<set name="orderitems" table="ORDERITEM" inverse="true">
<key column="PRODUCT_ID"></key>
<one-to-many class="OrderItem"></one-to-many>
</set>
</class>
</hibernate-mapping>
级联关系(比如修改customer同时修改order关联对象)
持久化对象通过关联关系相互引用是很常见的,通常对其中一个对象进行修改、删除或更新等操作的时候,被关联的对象需要进行相应的操作。进行这样的操作的时候通过使用hibernate的级联功能即可解决。
cascade属性级介绍
属性值 | 描述 |
---|---|
none | 默认值表示关联对象之间无级联操作 |
save-update | 表示主动方在调用save()、update()和saveOrUpdate()方法是对被关联对象执行保存或更新操作 |
delete | 表示主动方独享调用delete()是对被关联对象执行删除操作 |
delete-orphan | 用在1-N关联中,表示主动方对象调用delete()方法是删除不被任何一个关联对象锁引用的关联对象,多用于父子关联对象中 |
all | 等价于save-update和delete的联合使用 |
1、修改Customer.hbm.xml(关联对象) <set>标签添加inverse="true"关联关系交给order和cascade="save-update"交给对方保存和修改
<set name="orders" inverse="true" cascade="save-update">
<key column="CUSTOMER_ID"></key>
<one-to-many class="Order"/>
</set>
HQL与QBC查询和批量处理
hql查询带有sql语句,qbc查询完全是java语句查询
hql查询依赖于query对象,通常hql的检索方式步骤如下
1、获取hibernate的session对象;
2、编写hql查询语句;
3、以hql作为参数,调用session对象的createquery()方法,创建query对象;
4、如果hql语句中包含参数,调用query对象的setXXX()方法为参数赋值;
5、调用query对象的list()等方法得出查询结果。
HQL查询依赖于query接口,query是hibernate提供的查询接口,每个query实例都对应一个查询对象,用于向数据库查询对象以及控制执行查询的过程。
hql查询关键字
关键字 | 功能 | 示例 |
---|---|---|
from | 指定查询类 | from Customer(返回Customer类的所有实例,默认情况下省略select子句,返回实例所有属性) |
where | 指定条件,用来筛选数据源 | from Customer where address=‘青岛市’(返回地址是"青岛市"的所有Customer实例,其中address是Customer类的属性) |
select | 执行查询后,返回元素所包含的内容 | select realName,address from Customer |
group by | 对查询结果进行分组 | select count(o) from |
order by | 对查询结果进行排序 | from Customer order by age(默认按照属性age进行升序排序,可以使用asc或desc关键字之名了按照升序或降序进行) |
join | join单独使用是表示内连接,left join表示做外链接,right join表示右外连接 | select c from Customer c inner join fecth c.orders(返回Customer的所有实例,并把该实例的orders属性进行预先加载,而不是延迟加载) |
fetch | 一次性去除当前对象和锁被关联的对象,也叫预先抓取对象 | select c from Customer c inner join c.orders(返回Customer的所有实例,并把该实例的orders属性进行预先加载,不是延迟加载) |
Query接口的方法及描述
方法名 | 描述 |
---|---|
int executeUpdate() | 执行更新或删除等操作,返回值是首次操作影响的记录数 |
Iterator iterate() | 返回一个Iterator对象,用于迭代查询的结果集。使用该方法是,首先检索ID字段,然后根据ID字段到Hibernate的一级缓存和耳机缓存中查找匹配的对象,如果存在就放到结果集中,否则执行额外的select语句,根据ID查询数据库。如果对象位于缓存中,该方法性能比list()方法要高 |
List list() | 返回List类型的结果集,如果是投影查询即查询部分属性,则返回Object[]形式 |
Query setFirstResult(int first) | 设定开始检索的起始位置,参数first表示帝乡在查询结果中的索引位置,索引位置的其实质为0.默认情况下,query接口从索引位置为0的对象开始检索 |
Query setMaxResult(int max) | 设定一次最多检索出的对象数据,默认情况下,query接口检索出查询结果中的所有对象,该方法通常和setFirstReuslt()方法匹配实现分页查询 |
Object uniqueResult() | 返回单个对象,如果没有查询到结果则返回null,该方法通常和setMaxResul()方法配合使用,用于返回单个对象 |
Query setString(String name,Stringval) | 绑定映射类型为String的参数,query接口提供了绑定各种hibernate映射类型的参数的方法 |
Query setEntity(String name,Object val) | 把参数与一个持久化对象绑定,该方法有多个重载方法 |
Query setParameter(String name,Object val) | 用于绑定任意类型的参数,该方法有多个重载方法 |
Query setProperties(String name,Object val) | 用命名参数与一个对象的属性值绑定,该方法有多个重载方法 |
使用hql查询
//1、获取session对象
Session session = HibernateUtils.getSession();
//2、编写hql语句
String hql = "from Customer c where c.address=:address";
//3、以HQL作为参数,调用session的createQuery()方法创建Query对象
Query query = session.createQuery(hql);
//4、调用Query对象的setXXX()方法为参数赋值
query.setString("address",address);
//5、调用Query对象的list()等方法得到查询结果
List<Customer> list = query.list();
//遍历输出结果
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
QBC检索
主要通过连个接口和一个工具类实现
Criteria接口,代表依次查询;
Criterion接口,代表一个查询条件;
Restrictions类,产生查询条件的工具类;
QBC检索方式的步骤:
1、获取Hibernate的Session对象;
2、调用Session对象的createCriteria()方法,创建Criteria对象;
3、调用Criteria对象的add()方法,增加Criterion查询条件;
4、执行Criteria的list()或uniqueResult()方法返回查询结果集。
//1、获取Session对象
Session session = HibernateUtils.getSession();
//2、以Customer的Class对象作为参数,创建Criteria对象
Criteria critera = session.createCriteria(Customer.class);
//3、调用Criteria对象的add()方法,增加Criterion查询条件
critera.add(Restrictions.eq("address",address));
//4、执行Criteria的list()方法,增加Criterion查询条件
List<Customer> list = critera.list();
//遍历输出结果
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
查询结果排序
1、HQL查询结果排序
使用order by升序和降序
注意hql语句中order by
Session session = HibernateUtils.getSession();
String hql = "from Customer c order by c.uesrName desc";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
2、Criteria查询结果排序
使用org.hibernate.criterion.Order类对查询结果进行排序,其中Order类是代表排序的类,该类提供了asc()和desc()两个静态方法,用于升序和降序。
Session session = HibernateUtils.getSession();
Criteria critera = session.createCriteria(Customer.class);
critera.addOrder(org.hibernate.criterion.Order.desc("userName"));
List<Customer> list = critera.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
分页查询
1、HQL分页查询
通过Query接口中的setFirstResult和setMaxResult实现
//pageNo表示第几页,perPageNum表示一页多少条记录
Session session = HibernateUtils.getSession();
String hql = "from Customer c order by c.userName desc";
Query query = session.createQuery(hql);
query.setFirstResult(pageNo-1)*perPageNum);
queyr.setMaxResults(perPageNum);
List<Customer> list = query.list();
Criteria分页查询
通过Criteria接口中的setFirstResult()和setMaxResults()方法结合使用
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFristResult((pageNo-1)*perPageNum);
criteria.setMaxResults(perPageNum);
List<Customer> list = criteria.list();
查询单条记录
1、先调用Query或Criteria接口中的setMaxResults(1)方法,将最大检索数设置为1;
2、然后调用uniqueResult()方法返回一个Object类型的对象。
HQL绑定参数
查询条件,绑定参数返回
创建查询语句
使用:name命名
Session session = HibernateUtils.getSession();
String hql = "from Customer as c where c.userName = :name";
Query query = session.createQuery(hql);
query.setString("name",name);
使用?
设定查询条件
userName查询
Session session = HibernateUtils.getSession();
String hql = "from Customer as c where c.userName = ?";
Query query = session.createQuery(hql);
query.setString(0,name);
比较运算
HQL检索地址不是"青岛"的Customer
session.createQuery(“from Customer c where c.address <> ‘青岛’”)
范围运算
HQL检索在指定范围
session.createQuery(“from Customer c where c.userName in(‘zhangsan’,‘list’,‘wangwu’)”);
指定订单日期为2015年3月
String hql = "from Order o where o.date between ? and ?";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try{
List<Order> list = session.createQuery(hql).setParameter(0,dateFormat.parse("2015-03-01 00:00:00")).setParameter(1,dateFormat.parse("2015-03-31 23:59:59")).list();
}catch(ParseException e){
e.printStckTrace();
}
字符串匹配
hql检索用户名以z开头的Customer
session.createQuery(“from Customer c where c.userName like ‘z%’”);
逻辑运算
HQL检索用户已z开头
session.createQuery(“from Customer c where c.userName like ‘z%’ and c.address=‘青岛’”)
连接查询
Hql连接查询
内连接(inner join)
String hql = "from Customer c inner join c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name","z%");
预先抓取内连接(inner join fetch)
String hql = "from Customer c inner join fetch c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name","z%");
List<Customer> list = query.list();
Set<Customer> set = new HashSet<Customer>(list);
分组与统计查询
HQL常用统计函数
函数名称 | 功能 |
---|---|
count() | 统计记录条数 |
min() | 求最小值 |
max() | 求最大值 |
sum() | 求和 |
avg() | 求平均值 |
例如:
String hql = "select count(p.id) from Product p";
Long count = (Long)session.createQuery(hql).uniqueResult();
动态查询
HQL动态查询
Session session = HibernateUtils.getSession();
StringBuffer buffer = new StringBuffer();
buffer.append("from Product p where 1=1");
if(name!=null&&!name.equals("")){
buffer.append("and lower(p.name) like :name");
}
if(price != null && price != 0){
buffer.append("and p.price = :price");
}
Query query = session.createQuery(buffer.toString());
if(name!=null){
query.setString("name",""%"+name.toLowerCase()+"%"");
}
if(price!=null&&price!=0){
query.setDouble("price",price);
}
QBC动态查询
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Product.class);
if(name != null){
criteria.add(Restrictions.ilke("name",name,MatchMode.ANYWHERE));
}
if(price!=null&&price!=0){
criteria.add(Restrictioins.eq("price",price));
}
单行子查询
Session session = HibernateUtils.getSession;
String hql = "from Product p where p.price = (select p1.price from Product p1 where p1.name = :name) and p.name!=:name";
Query query = session.createQuery(hql);
queyr.setStirng("name","打印机");
多行子查询
多行运算符
all运算符,返回所有订单的价格小于100的客户
from Customer c where 100>all(select o.total from c.orders o)
any运算符,返回一条订单价格小于100的客户
from Customer c where 100>and(select o.total from c.orders o)
in运算符。返回一条订单的价格等于100的客户
from Customer c where 100 in(select o.total from c.orders o)
返回至少一个订单客户
from Customer c where exists(from c.orders)
批量添加
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
for(int i = 0;i<1000000;i++){
Customer customer = new Customer();
session.save(customer);
//没保存10个Customer对象清空一次缓存
if(i%10==0){
session.flush();
session.clear();
trans.commit();
trans=session.beginTransaction();
}
}
批量更新
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
ScrollableResults customers = session.createQuery("from Customer").scroll();
int count = 0;
while(customers.next()){
Customer customer = (Customer)customers.get(0);
customer.setUserName("username"+count);
if(i%10==0){
session.flush();
session.clear();
trans.commit();
trans=session.beginTransaction();
}
count++;
}
trans.commit();
HibernateUtils.closeSession();
}
批量删除
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
String hql = "delete Customer";
int count = session.createQuery(hql).executeUpdate();
trans.commit();
HibernateUtils.closeSession();
HQL与QBC查询和批量处理(demo.java)
HqlCriteriaBusinessDemo.java
package com.qst.chapter06.demo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import com.qst.chapter06.pojos.Customer;
import com.qst.chapter06.pojos.Order;
import com.qst.chapter06.pojos.Product;
import com.qst.chapter06.util.HibernateUtils;
public class HqlCriteriaBusinessDemo {
public static void main(String[] args) {
findCustomersByAddress_HQL("青岛市");
}
/*hql获取数据*/
public static void findCustomersByAddress_HQL(String address){
Session session = HibernateUtils.getSession();
String hql="from Customer c where c.address = :address";
Query query = session.createQuery(hql);
query.setString("address", address);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
}
/*qbc获取数据*/
public static void findCustomerByAddress_QBC(String address){
Session session = HibernateUtils.getSession();
Criteria critera = session.createCriteria(Customer.class);
critera.add(Restrictions.eq("address", address));
List<Customer> list = critera.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
}
/*order by排序*/
public static void orderByUserNameByDesc_HQL(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c order by c.userName desc";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
}
/*QBC排序*/
public static void orderByUserNameByDesc_QBC(){
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(org.hibernate.criterion.Order.desc("userName"));
List<Customer> list = criteria.list();
for(Customer c:list){
System.out.println(c.getId()+"\t"+c.getUserName());
}
}
/*HQL分页查询*/
public static List<Customer> listPageCustomer_HQL(int pageNo,int perPageNum){
Session session = HibernateUtils.getSession();
String hql = "from Customer c order by c.userName desc";;
Query query = session.createQuery(hql);
query.setFirstResult((pageNo-1)*perPageNum);
query.setMaxResults(perPageNum);
List<Customer> list = query.list();
return list;
}
/*QBC分页查询*/
public static List<Customer> listPageCustomer_QBC(int pageNo,int perPageNum){
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult((pageNo-1)*perPageNum);
criteria.setMaxResults(perPageNum);
List<Customer> list = criteria.list();
return list;
}
/*HQL查询单条记录*/
public static Customer findOneCustomer_HQL(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c order by c.userName desc";
Customer customer = (Customer) session.createQuery(hql).setMaxResults(1).uniqueResult();
return customer;
}
/*QBC查询单条记录*/
public static Customer findOneCustomer_QBC(){
Session session = HibernateUtils.getSession();
Customer customer = (Customer)session.createCriteria(Customer.class).addOrder(org.hibernate.criterion.Order.desc("userName")).setMaxResults(1).uniqueResult();
return customer;
}
/*不建议使用造成sql注入*/
public static List<Customer> findCustomersByName(String name){
Session session = HibernateUtils.getSession();
String hql = "from Customer as c where c.realName = '"+name+"'";
Query query = session.createQuery(hql);
return query.list();
}
/*推荐使用,防止sql注入。在语句中插入值*/
public static List<Customer> findCustomersByName1(String name){
Session session = HibernateUtils.getSession();
String hql = "from Customer as c where c.userName = :name";
Query query = session.createQuery(hql);
query.setString("name", name);
return query.list();
}
public static List<Customer> findCustomersByName2(String name){
Session session = HibernateUtils.getSession();
String hql = "from Customer as c where c.userName = ?";
Query query = session.createQuery(hql);
query.setString(0, name);
return query.list();
}
/*hql输出日期*/
public static void printOrders_HQL(){
Session session = HibernateUtils.getSession();
String hql = "from Order o where o.date between ? and ?";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try{
List<Order> list = session.createQuery(hql).setParameter(0, dateFormat.parse("2015-03-01 00:00:00"))
.setParameter(1, dateFormat.parse("2015-03-31 23:59:59")).list();
for(Order o : list){
System.out.println(o.getId()+"\t"+o.getDate());
}
}catch (ParseException e) {
// TODO: handle exception
}
}
/*QBC检索3月份的订单对象*/
public static void printOrders_QBC(){
Session session = HibernateUtils.getSession();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try{
List<Order> list = session.createCriteria(Order.class).add(Restrictions.between("date", dateFormat.parse("2015-03-01 00:00:00"), dateFormat.parse("2015-03-31 23:59:59"))).list();
for(Order o : list){
System.out.println(o.getId() + "\t" + o.getDate());
}
}catch (ParseException e) {
// TODO: handle exception
}
}
/*内连接获取*/
public static void findCustomerByJoin(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c inner join c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name", "z%");
List<Object[]> list =query.list();
for(Object[] objs:list){
Customer customer = (Customer)objs[0];
System.out.println();
}
}
/*使用预先抓取fetch获取内连接*/
public static void findCustomerByFetchJoin(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c inner join fetch c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name","z%");
List<Customer> list =query.list();
Set<Customer> set = new HashSet<Customer>(list);
for(Customer customer : list){
System.out.println(customer.getId()+""+customer.getUserName()+" ");
for(Order order:customer.getOrders()){
System.out.println(order.getOrderNo()+" ");
}
System.out.println();
}
}
/*左连接获取*/
public static void findCustomerByLeftJoin(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c left join c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name", "z%");
List<Object[]> list =query.list();
for(Object[] objs:list){
Customer customer = (Customer)objs[0];
System.out.println();
}
}
/*使用预先抓取fetch获取左连接*/
public static void findCustomerByFetchLeftJoin(){
Session session = HibernateUtils.getSession();
String hql = "from Customer c left join fetch c.orders o where c.userName like :name";
Query query = session.createQuery(hql);
query.setString("name","z%");
List<Customer> list =query.list();
Set<Customer> set = new HashSet<Customer>(list);
for(Customer customer : list){
System.out.println(customer.getId()+""+customer.getUserName()+" ");
for(Order order:customer.getOrders()){
System.out.println(order.getOrderNo()+" ");
}
System.out.println();
}
}
/*根据id统计用户总数*/
public static void groupByCustomer(){
Session session = HibernateUtils.getSession();
String hql = "select c.userName,count(o) from Customer c left join c.orders o group by c.id";
Query query = session.createQuery(hql);
List<Object[]> list =query.list();
for(Object[] objs:list){
String username = (String)objs[0];
Long count=(Long)objs[1];
System.out.println("用户名:"+username+"订单数:"+count);
}
}
/*HQL动态查询产品信息*/
public static List<Product> findProductsByHQL(String name,Double price){
Session session = HibernateUtils.getSession();
StringBuffer buffer = new StringBuffer();
buffer.append("from Product p where 1=1");
if(name!=null){
buffer.append("and lower(p.name) like :name");
}
if(price!=null&&price!=0){
buffer.append("and p.price = :price");
}
Query query = session.createQuery(buffer.toString());
if(name!=null){
query.setString("name", "%"+name.toLowerCase()+"%");
}
if(price!=null&&price!=0){
query.setDouble("price", price);
}
return query.list();
}
/* Criteria动态查询产品信息*/
public static List<Product> findProductsByCriterial(String name,Double price){
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Product.class);
if(name!=null){
criteria.add(Restrictions.ilike("name", name,MatchMode.ANYWHERE));
}
if(price!=null&&price!=0){
criteria.add(Restrictions.eq("price",price));
}
return criteria.list();
}
/* 单行子查询*/
public static void findProductBySubQuerys(){
Session session = HibernateUtils.getSession();
String hql = "from Product p where p.price=(select pl.price from Product p1 where p1.name = :name) and p.name!=:name";
Query query = session.createQuery(hql);
query.setString("name", "打印机");
List<Product> list = query.list();
for(Product p : list){
System.out.println(p.getId()+"\t"+p.getName()+"\t"+p.getPrice()+"\t"+p.getDescription());
}
}
/* 批量插入数据*/
public static void bulkInsert(){
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
for(int i = 0;i<1000000;i++){
Customer customer = new Customer();
session.save(customer);
//没保存10个Customer对象,清空缓存
if(i%10==0){
session.flush();
session.clear();
trans.commit();
trans = session.beginTransaction();
}
}
HibernateUtils.closeSession();
}
/* 批量修改**/
public static void bulkUpdate(){
Session session = HibernateUtils.getSession();
Transaction trans = session.beginTransaction();
//查询customer表中所有对象
ScrollableResults customers = session.createQuery("from Customer").scroll();
int count = 0;
while(customers.next()){
Customer customer = (Customer)customers.get(0);
customer.setUserName("username"+count);
if(count%10==0){
session.flush();
session.clear();
trans.commit();
trans = session.beginTransaction();
}
count++;
}
}
}
hibernate高级
检索策略
类级别检索策略:使用Sesssion的load()或者get()方法进行检索,对高档亲对象进行检索的策略,例如对Customer对象进行检索的时候,直接检索该对象本身。类级别建松包括立即加载和延迟加载。
关联级别检索策略:使用Session的load、get()方法或使用HQL进行检索是,对当前对象的关联对象进行建搜的策略,例如对于Customer进行关联的Order对象(及Customer对象的orders集合)进行检索的时候采用的策略,包括:立即加载、延迟加载和预先抓取
类级别检索策略
检索策略 | 功能说明 |
---|---|
立即检索 | 如果把<class>标签的lazy属性设置为false时,立即加载;当调用session的load()方法是,会立即加载检索方法指定的对象,立即进行sql查询,并且进队load()方法影响 |
延迟检索 | 延迟检索是默认检索策略,<class>标签lazy属性,默认为true,当加载对象时,并没有直接进行SQL查询,只有当调用对象当中的属性是,才会真正查询数据库 |
分为立即加载和延迟加载,在class标签上设置
立即加载
当通过session的load()方法加载Customer对象的时候,Hibernate会立即执行查询t_customer的select语句
select * from t_customer where id = 1
struts.xml
<class name="com.qst.chapter07.pojos.Customer" table="t_customer" lazy="false">
类级别延迟加载
设置之后,session.load()方法不会立即查询,而是等调用,具体实体类的getter或setter方法执行。
当Customer.hbm.xml的<class>标签中lazy属性为true的时候
<class name="com.qst.chapter07.pojos.Customer" table="t_customer" lazy="true">
执行session.load()方法,hibernate不会立即执行select语句并进行数据库的SQL查询,而是返回Customer类的代理类实例。
1、有hibernate运行时动态生成,扩展了Customer类,并继承了Customer类的属性和方法。
2、当hibernate创建customer代理类实例的时候,进初始化该对象的OID,其他属性为null
3、当应用程序第一次访问Customer代理类实例(如调用getter()和setter()方法等),Hibernate会初始化代理类的实例,初始化过程中执行的select语句,真正从数据库中加载Customer对象的所有数据,getId()方法例外。
1-N检索策略
<set>元素的lazy和fetch属性
lazy属性 | fetch属性 | 检索策略 |
---|---|---|
false | select | 采用立即加载,当使用Hibernate的二级缓存是,可以考虑使用立即加载方式 |
false | fetch | 采用预先抓取方式检索,这是Hibernate4.x默认的检索方式 |
true | join | 采用预先抓取方式检索,由此可见预先抓取的优先级别比延迟加载的级别高 |
true | select | 采用延迟加载策略 |
批量检索
<set>元素有一个batch-size属性,用于为延迟加载或立即加载策略设置的批量检索数量,批量检索可以减少select语句的数目,提高延迟或立即加载的性能。
1、批量立即加载
会将与当前检索数据相关联的数据全部查询处理来,Customer与Order对象是1-N的,如果采用立即加载得到Customer对象,Customer对象或通过雷冠希导航取得所有的Order数据。
Session session = HibernateUtils.getSession();
String hql = "from Csutomer";
Query query = session.createQuery(hql);
List list = query.list();
...//提交事务,关闭session
没有设置之前,需要如果有100个订单需要执行100条order的查询语句
<set name="orders" lazy="false" batch-size="2">
设置之后,执行50条查询语句。
select o.* from t_order o_where o_.CUSTOMER_ID in(?,?);
批量延迟加载
<set name="orders" lazy="true" batch-size="2">
Session session = HibernateUtils.getSession();
String hql = "from Customer c";
Query query = session.createQuery(hql);
List list = query.list();
Customer c1 = (Customer)list.get(0);
c1.getOrders().iterator();
当执行c1.getOrders.iterator()的是偶,由于batch-size的属性值为2,会批量初始化2个orders集合代理实例。
预先抓取
当fetch设置为join的时候,语句改变
select c.,o. from t_customer c left outer join t_order o on c.id = o.CUSTOMER_ID where c.id = ?
提高效率