介绍
概述
ORM体现
是JBoss公司的产品
下载
http://www.hibernate.org
http://hibernate.org/orm/downloads/
https://sourceforge.net/projects/hibernate/files/hibernate-orm/
https://sourceforge.net/projects/hibernate/files/
解压后文件夹说明
documentation : 全部的文档
devguide : 开发指导.
javadocs : api文档.
manual : 开发指南.
quickstart : 快速开始.
lib: 存放了所有的jar(第三方的、自己的).
required : 必须要的jar.
jpa : jpa实现的jar.
optional: 可选的.
c3p0 : 连接池(现在企业用得最多的连接池).
ehcache : 缓存框架.
proxool : 连接池.
project : 存放了Hibernate框架的源码、测试用例、资源文件、示例.
project/etc : 存放了配置文件的模版.
基础的jar包
required + jpa + mysql数据库连接
使用步骤:
1.建库、建表
2.写实体类
3.映射实体类
1.映射文件(不流行)-hibernate包中搜索*.hbm.xml。配置文件要和实体类在一个包下。
2.使用jpa注解(流行)
4.写hibernate配置文件
配置属性 hibernate-release-4.3.11.Final\project\etc\hibernate.properties
5.测试api
hibernate配置文件说明
参考 hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties
hibernate.connection.driver_class
指定数据库连接参数
com.mysql.jdbc.Driver
hibernate.connection.url
如果数据库不存在就建库
jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true
hibernate.connection.username
数据库用户名
hibernate.connection.password
数据库密码
hibernate.dialect
配置数据库方言(指定使用哪一种数据库,hibernate会根据这里指定的方言,生成符合当前数据库语法的sql语句)
org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql
显示hibernate在运行的时候生成的sql语句!
true
hibernate.format_sql
格式化sql
true
hibernate.hbm2ddl.auto
自动建表
update
表不存在则创建,如果表已经存在就不创建表
create
先删除表,再创建一个新表
create-drop
在创建SessionFactory时候建表;在执行其close方法的时候删除表
validate
验证;检查映射配置与表结构是否一致,不一致报错!更严格!
javax.persistence.validation.mode
关闭java对象注解验证!(如果新建web项目,使用javaee6.0以上版本,必须要加上这行!)
none
基本使用代码一
User.java
public class User {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
User.hbm.xml
<?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.shuai.domain.User" table="t_user">
<id name="id" column="uid">
<generator class="uuid"></generator>
</id>
<property name="name" column="uname"></property>
</class>
</hibernate-mapping>
hibernate.cfg.xml
<?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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="javax.persistence.validation.mode">none</property>
<mapping resource="cn/itcast/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
AppTest.java
@Test
public void Save() throws Exception {
User user = new User();
user.setName("Jack");
//1. 创建配置管理器对象
Configuration config = new Configuration();
//2. 加载主配置文件:hibernate.cfg.xml
config.configure();
//3. 创建SessionFactory对象
SessionFactory sf = config.buildSessionFactory();
//4. 创建Session (会话,与数据库的连接的会话)
Session session = sf.openSession();
//5. 开启事务
Transaction tx = session.beginTransaction();
//6. -- 执行操作--
session.save(user);
//7. 提交事务/关闭
tx.commit();
session.close();
}
@Test
public void get() throws Exception {
Configuration config = new Configuration();
config.configure();
SessionFactory sf = config.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
User user = (User) session.get(User.class, 1);
System.out.println(user);
tx.commit();
session.close();
}
基本使用代码二
User.java
@Entity
public class User {
@Id
private int id;
private String name;
private int age;
//getter/setter
}
hibernate.cfg.xml
<?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="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">32147</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">2</property>
<mapping class="org.fkjava.hibernate.domain.User"/>
</session-factory>
</hibernate-configuration>
App.java
public void testAdd(){
// 第一步:创建Configuration配置信息对象 (加载全局的配置文件)
Configuration configuration = new Configuration() // 默认会加载src/hibernate.properties属性文件
.configure(); // 默认会加载src/hibernate.cfg.xml
// 第二步:创建服务注册对象
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
// 第三步:创建SessionFactory
SessionFactory sf = configuration.buildSessionFactory(serviceRegistry);
// 第四步:创建Session
Session session = sf.openSession();
// 第五步:开启事务,得到事务对象
Transaction transaction = session.beginTransaction();
// 第六步:利用Session完成所有的持久化操作
User user = new User();
user.setId(1);
user.setAge(20);
user.setName("帅哥");
session.save(user);
// 第七步:事务提交或回滚 commit|rollback
transaction.commit();
// 第八步:关闭Session、SessionFactory
session.close();
sf.close();
}
API
hibernate3API
Configuration 管理管理文件的类
Configuration configure()
加载主配置文件,默认加载src/hibenrate.cfg.xml
SessionFactory buildSessionFactory()
创建session的工厂(hibernate.cfg.xml中就是session工厂的配置!)
一个应用程序只需要一个session工厂即可!单例对象!
SessionFactory addClass(..)
加载指定类的字节码对应的映射文件! (User.hbm.xml)
注意:
1.去对象所在的包下去找对应的映射文件;
2. 映射文件必须是*.hbm.xml后缀
3. 测试使用才去使用,比较方便!
SessionFactory session工厂
Session openSession()
创建新的session对象
Session getCurrentSession()
创建session (使用时候需要配置hibernate.cfg.xml)
(<property name="hibernate.current_session_context_class">thread</property>)
Session 与数据库连接的会话!(里面维护了一个数据库连接)
hibernate中操作数据库就是通过session对象操作的!
Serializable save(obj);
保存对象 【主键自增长,就不用设置主键,设置了也没有!】
void delete(obj);
删除对象 【对象的主键一定要存在】
void update(obj);
修改对象 【对象的主键一定要存在】
void saveOrUpdate(obj);
保存或修改【有设置主键执行更新,如果设置主键不存在就报错! 没有设置主键就保存!】
Object get(Class clazz,Serializable id);
主键查询
查询方式
1.写HQL语句查询【面向对象查询】
hibernate query language
hibernate提供的面向对象的查询语句
实现:session.createQuery(arg0);
2.Criteria查询【面向对象查询】
session.createCriteria(sql);
3.本地sql查询【支持原生态的sql语句查询】
session.createSQLQuery(sql)
Transaction 事务
hibernate要求对数据库数据的操作必须在一个事务环境内进行!
Query
List list();
执行的查询的hql
int executeUpdate();
执行的更新的hql
hibernate4
Configuration
专门负责加载全局的配置文件,产生SessionFactory.
ServiceRegistry
SessionFactory
它是当前数据库在内存中镜像。一个SessionFactory对应一个数据库,所以SessionFactory只能有一个,
当应用一启动就获取SessionFactory,当应用关闭时才关闭SessionFactory.
它是线程安全的.
它是创建Session的工厂。
它底层封装了数据源(连接池)。
它还有一个可选的二级缓存. (默认是关闭的).
Session
概述
它是应用程序与持久层进行交互的单线程对象。
它是线程不安全。
它存活的时间比较短.(因为它底层封装得是Connection,用完就要关闭).
它是事务工厂.
有一个必须开启的一级缓存. (一级缓存永远都是开启的).
方法
contains(object);
判断一级缓存中是否包含这个对象,true为持久化状态
Transaction
Hibernate事务对象.
JDBC事务(局部事务) : 只能对一个数据库中的表做事务. (web容器) tomcat jetty
JTA事务(全局事务、分布式事务) : 可以对多个数据库中的表做事务.(EJB容器)
WebSphere(IBM)、WebLogic(Oracle)、JBoss(jboss)
ConnectionProvider
数据库连接的提供者.
一般指得是数据源DataSource(连接池).
持久化类的状态
Transient 瞬态
new 持久化类(),刚new出来的,从来没有与Session关联过.
Persistent 持久化状态
正在被Session管理中。调用Session的方法对它进行操作过,这个时候Session没有关闭.
该对象在Session一级缓存中. (在内存中).
如果你调用持久化状态对象的set方法,它会影响数据库表中的数据.
你对持久化状态对象做的修改,会同步到底层的数据库表中,它不是立即同步到底层的数据库,默认是在事务提交时才同步。
Detached 脱管状态
脱离了Session的管理,曾经被Session管理过,现在没被Session管理。
Hibernate的CRUD操作
Hibernate4添加:
a. Serializable id = session.save();
User user = new User(); // 瞬态
user.setXxx();
session.save(user); // user --> 持久化状态
b. void session.persist();
User user = new User(); // 瞬态
user.setXxx();
session.persist(user); // user --> 持久化状态
c. session.saveOrUpdate(); // 添加与修改
User user = new User(); // 瞬态
user.setXxx(); // 不要设置主键列对应的属性.
void = session.saveOrUpdate(user); // user --> 持久化状态
d. session.merge(); // 混合集成了添加与修改.
User user = new User(); // 瞬态
user.setXxx(); // 不要设置主键列对应的属性.
User u = session.merge(user); // user --> 瞬态,u --> 持久化状态
注意:
save()与persist()区别
1.save方法有返回值,它返回的是主键id。
persist没有返回值,需要通过对象的getId来获取
2.save方法会立即往数据库表中插入数据
persist方法会延迟往数据库表中插入数据(跟事务是否开启有关)
在事务开启之后执行这两个方法做添加都会立即生成sql语句
Hibernate4根据主键查询:
session.get(): 根据主键id查询
User user = (User)session.get(User.class, 1); // user : 持久化状态
立即从数据库表查询数据,返回对象.
session.load(): 根据主键id查询
User user = (User)session.load(User.class, 1); // user : 持久化状态
延迟从数据库表查询数据,一开始返回代理对象,当你真正要用到它的属性时,
才会生成查询语句到数据库表中查询数据。
当你要用到它的时候,要保证Session不能关闭。
Hibernate4修改:
持久化状态下:
User user = (User)session.get(User.class, 1); // user : 持久化状态
user.setXxx();
脱管状态下:
User u = new User(); // 瞬态
u.setId(1); // 脱管
session.update(u); // u --> 持久化状态
session.saveOrUpdate(u); // u --> 持久化状态
User user = session.merge(u); // u --> 脱管 user --> 持久化状态
Hibernate4删除:
持久化状态下:
User user = (User)session.get(User.class, 1); // user : 持久化状态
session.delete(user); // user --> 瞬态
脱管状态下:
User u = new User(); // u -> 瞬态
u.setId(3); // u -> 脱管
session.delete(u); // 瞬态
注解实现方式详细介绍
注解作用
将持久化类转换成表的相关信息.(表名,索引,唯一约束,列名的相关信息、关联)
基础映射(注解加在持久化类上)
entity/table/DynamicInsert/DynamicUpdate/SelectBeforeUpdate
主键映射/复合主键映射
id/GeneratedValue/EmbeddedId
基本属性映射(持久化类中属性转化成数据库表中列的相关信息)
Column/Lob/Temporal/Transient
集合属性映射
关联映射
继承映射
注解
第一类
类名上
@Entity
将POJO转化成持久化类。
@Table
把持久化类转化成表的相关信息
name:指定表名
schema :指定将数据表存入哪个数据库,schema或者catalog只能指定一个.
catalog:指定将数据表存入哪个数据库,schema或者catalog只能指定一个.
indexes: 用于指定表的引索列
@Index(columnList="数据表中的列名", name="索引名")
indexes={@Index(), @Index()}
uniqueConstraints:用于指定唯一约束
@uniqueConstraint(columnNames={"列名","列名"}, name="唯一约束名")
@DynamicInsert
动态插入,根据持久化对象的属性是否有值明确生成insert语句。
@DynamicUpdate
动态修改,它会判断持久化对象中属性,哪些属性值发生了改变就会生成update的语句。(持久化状态下做修改)
@SelectBeforeUpdate
修改之前先查询,查询得到持久化对象再与脱管状态下的对象进行比较,哪些属性值发生了改变就会生成update的语句。(脱管状态下做修改)
第二类
主键上
@Id
主键列
@GeneratedValue(strategy=GenerationType.AUTO)
指定了主键自增长策略
GenerationType.IDENTITY: 适宜MySQL、SqlServer有自增长列的数据库。
GenerationType.SEQUENCE:适宜Oracle这种没有自增长有sequence的数据库。
GenerationType.AUTO:让Hibernate根据数据库方言自动选择主键生成策略。
GenerationType.TABLE: 适宜所有的数据库,因为它会单独生成一张表来维护主键生成。
@Embedded
复合主键
@AttributeOverrides
指定复合主键中的列表
@AttributeOverrides({@AttributeOverride(name="firstName", column=@Column(name="F_NAME")),@AttributeOverride(name="lastName", column=@Column(name="L_NAME"))})
第三类
普通属性上
@Column
持久化类中属性转化成数据库表中列的相关信息
name:指定列名。
length: 该列支持的长度。
precision:有效的总位数。(BigDecimal类型才有效)
scale:小数点的位数。(BigDecimal类型才有效)
unique: 唯一约束。
nullable:非空约束。
insertable:是否允许插入true:允许 false: 不允许。
updatable:是否允许修改true:允许 false: 不允许。
columnDefinition :指定列的定义。columnDefinition="int(11) not null default 20"
@Lob
映射大的二进制数或者文本
@Temporal
修饰日期类型Date
TemporalType.DATE : yyyy-MM-dd
TemporalType.TIME : HH:mm:ss
TemporalType.TIMESTAMP : yyyy-MM-dd HH:mm:ss
@Transient
指定不是持久化属性
transient关键字修饰不需要序列化的属性,同时用它也能指定不是持久化的属性。
第四类
集合属性上(List/Set/Map/Array)
当持久化中有一个属性是集合(Set、List、Map).
集合属性会单独生成一张表
定义集合属性时面向接口,并且集合属性需要程序员自己初始化
private List<String> list = new ArrayList<String>();
@ElementCollection
指定加载策略/指定集合中的元素类型
@ElementCollection(fetch=FetchType.LAZY,targetClass=String.class)
fetch=FetchType.EAGER: 立即加载 / fetch=FetchType.LAZY: 延迟加载
targetClass 集合中元素的类型
@CollectionTable
指定集合的表名
@CollectionTable(name="info")
List集合(有序集合)
@OrderColumn
指定排序列
@OrderColumn(name="o_id")
@Embeddable
说明此类是集合中的元素
Set集合(无序集合)
@Embeddable
注意:
Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合的元素类的属性上添加非空约束!
@Column(nullable:false)
Set集合生成表的主键列:【外键列 + Set集合的元素列】
Map集合(有Map的key)
@MapKeyColumn
@Embeddable
注意
Map集合生成表的主键列:【外键列 + Map的Key】
第五类
关联映射
单向关联
一对一
//学生表中增加一个关联id
@OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id")
private Teacher teacher;
一对多
//学生表中增加一个关联id
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延迟加载,指定关联的持久化类,指定哪些维护关联关系
@JoinColumn(name="t_id",referencedColumnName="id")
private Set<Student> students = new HashSet<Student>();
多对一
//学生表中增加一个关联id
@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id")
private Set<Student> students = new HashSet<Student>();
多对多
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
private Set<Teacher> teachers = new HashSet<Teacher>();
双向关联
一对一
注解:@OneToOne
@OneToOne(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")
private Student student;
@OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinColumn(name="t_id",referencedColumnName="id",unique=true)
private Teacher teacher;
一对多
一端(主表):@OneToMany
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延迟加载,指定关联的持久化类,指定哪些维护关联关系
private Set<Student> students = new HashSet<Student>();
多端(从表):@ManyToOne
生成外键列
@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)//延迟加载,指定关联的持久化类
@JoinColumn(name="t_id",referencedColumnName="id",foreignKey=@ForeignKey(name="fk_tea_stu"))//生成外键列t_id,关联Teacher类中的id
private Teacher teacher;
保存主表,再保存从表
级联级别
@OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher",cascade=CascadeType.REMOVE,orphanRemoval=true)
CascadeType.REMOVE 级联删除
orphanRemoval=true 删除孤儿记录
在不删除老师的基础上,把学生删除
以后千万不要配置@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class,cascade=CascadeType.REMOVE)
CascadeType.REMOVE 级联删除,以后千万不要配置
多对多
注解
@ManyToMany
生成中间表来维护关联关系
用Set集合定义关联属性, set集合中的元素是关联的持久化类
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teachers")
private Set<Student> students = new HashSet<Student>();
@ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
@JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
private Set<Teacher> teachers = new HashSet<Teacher>();
第六类
继承映射
第一种方式(SINGLE_TABLE):所有子类中属性都生成到父类表中(一张表)
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DC", discriminatorType=DiscriminatorType.INTEGER)// 辨别者列
@DiscriminatorValue("1") // 辨别者列值
public class Person{}
//子类
@Entity
@DiscriminatorValue("2") // 辨别者列值
public class Teacher{}
注意:
所有子类属性中不能加非空约束
第二种方式(JOINED):所有的子类与父类都会单独生成表(子类表的中主键列同时也是外键列,它引用顶级父类表中的主键列).
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.JOINED)
public class Person{}
//子类
@Entity @Table(name="teacher")
public class Teacher{}
注意:查询时会出现很多join语句
第三种方式(TABLE_PER_CLASS):所有的子类与父类都会单独生成表,子类会把父类中的属性继承过来生成在自己的表中。
@Entity @Table(name="parent")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Person{}
//子类
@Entity @Table(name="teacher")
public class Teacher{}
注意:
这种策略主键不能用自增长
查询时会出现union运算
映射文件说明
hibernate-mapping 根元素
package
指定包名,如果没有指定,本文件出现的所有实体类必须带上完整包名.如果指定,就可以不带完整包名。
auto-import
默认为true 自动导入,在进行hql查询的时候不用写包名!
如果设置为false,在hql查询的时候需要指定包名,如:session.createQuery("from cn.itcast.entity.User");
schema
库名
class 类映射一个表
name 类名,是否指定完整路径看package
table 表名
id 主键映射
name 属性名
column 表字段名,不写也可以
generator 主键策略
native 自增长(根据底层数据库的能力选择 identity、sequence )
identity MySql中自增长的方式
sequence Oracle中以序列的方式实现自增长!
increment 也是自增长但不能处理并发问题!
assigned 手动指定主键的值
uuid uuid值作为主键
foreign 外键策略(一对一映射时候用到)
property 其它字段映射
name 属性名
column 表字段名,不写也可以。如果字段是数据的关键字使用反引号 `desc`
length 指定字符类型的长度,默认255
type 指定字段类型
hibernate支持的类型默认都是小写
string/java.lang.String
date/timestamp/ 如果属性是java.util.Date类型,字段映射没有指定类型,默认是datetime类型
unique
唯一约束
not-null
不能为空约束
代码方式建表
加载hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
工具类
SchemaExport export = new SchemaExport(cfg);
建表-参数1:是否打印生成的sql到控制台-参数2:是否执行生成的sql
export.create(true, true);
查询方式
get主键查询
User user = (User) session.get(User.class, 1);
立即从数据库表中查询数据
load对象导航查询(懒加载查询)
user = (User) session.load(User.class, 1);
延迟从数据库表查询数据,一开始返回一个代理对象,当真正用到属性的时候,再到数据库表中查询
注意:用它时保证session不要被关闭
Hql查询
Hibernate Query Language
Hibernate查询语句
步骤:
获得Session
写hql语句
查询数据库获得Query对象
如果有占位符,就需要对占位符赋值 query.setParameter();
如果需要分页limit赋值 query.setFirstResult(start); query.setMaxResults(size);
获取查询查询结果
如果本次查询有多条记录返回:query.list();
如果本次查询只有一条记录返回:query.uniqueResult();
from字句
List<Student> students = session.createQuery("from Student").list();
List<Student> students = session.createQuery("from Student as stu").list();
List<Student> students = session.createQuery("from Student stu").list();
User user =(User) session.createQuery("from User where id=1").uniqueResult();
select字句
List<Student> students = session.createQuery("select s from Student as s").list();
List<String> names = session.createQuery("select s.name from Student s").list();
List<Object[]> lists = session.createQuery("select s.name,s.age from Student s").list();
List<Object[]> lists = session.createQuery("select name,age from Student").list();
分页
Query query = session.createQuery("select s from Student s");
query.setFirstResult(0);
query.setMaxResults(5);
List<Student> students = query.list();
select new 字句
可以改变List集合中存放什么
List<Map<String,Object>> list = session.createQuery("select new map(s.name,s.age) from Student s").list();
List<List<Object>> list = session.createQuery("select new list(s.name,s.age) from Student s").list();
List<User> list = session.createQuery("select new com.shuai.domain.User(name,age) from Student").list();
关联(持久化类)与连接(数据库表)
隐式关联(不需要写join语句)
查询时,关联的属性是一个持久化类。
List<Student> students = session.createQuery("select s from Student s where s.teacher.id=?").setParameter(0,1).list();
显示关联(需要写join语句)
查询时,关联属性是一个Set集合
Teacher t = (Teacher)session.createQuery("select t from Teacher t inner join t.students where t.students.id=?").setParameter(1,1).uniqueResult();
抓取连接(查询延迟的属性)
查询时,关联属性配置了延迟加载的,但本次查询要查询出来 join fetch关联的属性
List<Student> students = session.createQuery("select s from Student s join fetch s.teacher").list();
排序 order by
List<Student> students = session.createQuery("select s from Student s order by s.age asc").list();
分组 group by
List<Object[]> list = session.createQuery("select count(s),s.teacher.name from Student s group by s.teacher.name").list();
分组过滤 having
List<Object[]> list = session.createQuery("select count(s),avg(s.score),sum(s.score),s.teacher.name from Student s group by s.teacher.name having s.teacher.id=?").setParameter(0,1).list();
聚合函数 count/sum/max/min/avg
count
Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();
sum
Double sum = (Double)session.createQuery("select sum(score) from Student").uniqueResult();
max
Float max = (Float)session.createQuery("select max(score) from Student").uniqueResult();
min
Float min = (Float)session.createQuery("select min(score) from Student").uniqueResult();
avg
Float avg = (Float)session.createQuery("select avg(score) from Student").uniqueResult();
where字句部分(查询过滤部分)
Hibernate的where子句部分能支持的运算符,表达式、函数特别多,用法与sql语句是一样的
常用的表达式、运算符、函数
=、<、<=、>、>=、!=、and、or、distinct、between...and 、like、concat()、is null, is not null, is empty, is not empty、second(...),minute(...), hour(...), day(...), month(...)
支持EJB-QL 3.0的函数
trim(), lower(), upper(), length(), abs(), sqrt(), bit_length(), mod()
支持操作集合属性的函数
size()|size, minelement(), maxelement(), minindex(), maxindex()
使用
List<Student> students = session.createQuery("select s from Student s where s.name like ?8").setParameter("9","%小%").list();
List<Student> students = session.createQuery("select s from Student s where s.name like concat('%',?2,"%")").setParameter("2","小").list();
List<Student> students = session.createQuery("select s from Student s where s.name is not null").list();
List<Student> students = session.createQuery("select s from Student s where trim(s.name) like ?").setParameter(0,"%帅%").list();
List<Student> students = session.createQuery("select s from Student s where length(s.name) = ?").setParameter(0,"%帅%").list();
List<Student> students = session.createQuery("select s from Student s where sqrt(s.id)=?").setParameter(0,1.0d).list();
List<Student> students = session.createQuery("select s from Student s where bit_length(s.name)=?").setParameter(0,32L).list();
List<Student> students = session.createQuery("select s from Student s where mod(s.id,?)=?").setParameter(0,2).setParameter(1,0).list();
List<Order> orders = session.createQuery("select o from Order o where size(o.orderItems) =?").setParameter(0,3).list();
List<Order> orders = session.createQuery("select o from Order o where minelement(o.orderItems) =?").setParameter(0,100).list();
List<Order> orders = session.createQuery("select o from Order o where maxelement(o.orderItems) =?").setParameter(0,100).list();
List<Order> orders = session.createQuery("select o from Order o where maxindex(o.orderItems) =?").setParameter(0,1).list();
List<Order> orders = session.createQuery("select o from Order o where minindex(o.orderItems) =?").setParameter(0,1).list();
子查询
hibernate的子查询与SQL语句的中子查询一样,子查询部分放在in、not in里面
使用
List<Student> students = session.createQuery("select s from Student as s where s.id in(select t.id from Teacher t)").list();
多态查询
当你的持久化类存在继承关系时,你查询父类时,它会把父类所有的对象查询出来,而且也会把所有子类对象查询出来。
使用
List<Object> lists = session.createQuery("from java.lang.Object").list();
命名查询
把所有hql语句写在一个单独的配置文件中
一般在实际的项目中用得比较多,它会把比较复杂的hql语句写在一个单独的配置文件中
方便以后对hql语句进行优化,也方便统一管理
第一种方式
1.创建xxx.hbm.xml
<?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>
<query name="hql_1">select s from Student s where s.name like ?</query>
</hibernate-mapping>
2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
<mapping resource="com/shuai/domain/xxx.hbm.xml"/>
3.使用
List<Student> students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
第二种方式
1.在持久化类上加注解
@NamedQuery(name="hql_1", query="select s from Student s where s.name like ?");
public class Student{}
2.使用
List<Student> students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
Criteria查询
说明
完全面向对象的,不需要写任可查询语句
查询步骤
1.获取Session
2.Criteria criteria = session.createCriteria(持久化类)
3.如果需要分页查询就需要为limit ?,? 这两个问号赋值
第一个问号:criteria.setFirstResult(start);
第二个问号:criteria.setMaxResults(size);
4.获取查询查询结果
如果本次查询有多条记录返回:criteria.list();
如果本次查询只有一条记录返回:criteria.uniqueResult();
API
add(Criterion criterion)
添加查询条件.Criterion : 代表一个查询条件.
Restrictions 工具类,专门负责生成查询条件对象,它把where部分都改成了静态方法。
Property工具类,专门负责生成查询条件对象.
addOrder(Order order)
添加排序
Order.asc("属性名") | Order.desc("属性名")
Property.forName("age").asc()|Property.forName("age").desc()
setProjection(Projection projection)
查询哪些列
createAlias(String associationPath, String alias)
创建关联查询
用它创建出来的关联查询,添加查询条件时,如果不加别名,它是为目标持久类添加查询条件.
createCriteria(String associationPath)
创建关联查询
用它创建出来的关联查询,添加查询条件时,它是为关联的持久化类添加查询条件.
setFetchMode(String associationPath, FetchMode mode)
抓取连接(join fetch)
FetchMode: 抓取模式
FetchMode.JOIN FetchMode.EAGER 立即查询
FetchMode.SELECT FetchMode.LAZY 延迟查询
DetachedCriteria.
离线查询
用它就可以定义一条查询语句.
用得时候需要与Session关联起来.
离线查询的主要作用就是为了做子查询. in 、not in(离线查询对象)
使用
List<Student> students = session.createCriteria(Student.class).list();
List<Student> students = session.createCriteria("com.shuai.domain.Student").list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.like("name","%帅%")).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.like("name","%帅%")).add(Restrictions.between("age",20,30)).list();
List<Student> students = session.createCriteria(Student.class).add(Property.forName("name").like("%帅%")).list();
List<Student> students = session.createCriteria(Student.class).add(Property.forName("age").between(20,30)).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.sqlRestriction("length(name)=4")).list();
List<Student> students = session.createCriteria(Student.class).addOrder(Order.asc("age")).list();
List<Student> students = session.createCriteria(Student.class).addOrder(Property.forName("age").asc()).list();
List<String> names = session.createCriteria(Student.class).setProjection(Projections.property("name")).list();
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("name"));
pl.add(Projections.property("age"));
List<Object[]> names = session.createCriteria(Student.class).setProjection(pl).list();
Object res = session.createCriteria(Student.class).setProjection(Projections.rowCount()).uniqueResult();
Object res = session.createCriteria(Student.class).setProjection(Projections.avg("score")).uniqueResult();
Object res = session.createCriteria(Student.class).setProjection(Projections.max("score")).uniqueResult();
List<Object[]> lists = session.createCriteria(Student.class).setProjection(Projections.projectionList().add(Projections.rowCount()).add(Projections.property("teacher.id")).add(Projections.groupProperty("teacher.id"))).list();
List<Student> students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).createCriteria("teacher").add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.gt("age",100)).add(Restrictions.eq("t.id",1)).list();
List<Student> students = session.createCriteria(Student.class).add(Restrictions.gt("age",100)).createCriteria("teacher").add(Restrictions.eq("id",1)).list();
List<Student> students = session.createCriteria(Student.class).setFetchMode("teacher",FetchMode.JOIN).list();
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
List<Student> students = dc.getExecutableCriteria(session).list();
DetachedCriteria dc = DetachedCriteria.forClass(Teacher.class);
dc.setProjection(Projections.property("id"));
List<Student> students = session.createCriteria(Student.class).add(Property.forName("id").in(dc)).list();
本地sql查询
说明
Native Sql Query原生的sql查询
要求写sql语句
SQLQuery 是 Query的子类
步骤
1.获取Session
2.写sql语句
3.SQLQuery sqlquery = session.createSQLQuery(sql);
4.如果hql语句中有占位符,就需要为占位符赋值. sqlquery.setParameter("索引号", "值");
如果需要分页查询就需要为limit ?,? 这两个问号赋值
第一个问号:sqlquery.setFirstResult((pageIndex - 1) * pageSize);
第二个问号:sqlquery.setMaxResults(pageSize);
5.获取查询查询结果
如果本次查询有多条记录返回:sqlquery.list();
如果本次查询只有一条记录返回:sqlquery.uniqueResult();
API
addEntity(Class entityType)
实体查询
addScalar(String columnAlias)
标量查询
addJoin(String tableAlias, String path)
关联查询
使用
List<Student> students = session.createSQLQuery("select * from student").addEntity(Student.class).list();
List<Student> students = session.createSQLQuery("select * from student").addEntity("com.shuai.domain.Student").list();
List<Object[]> lists = session.createSQLQuery("select s.name,s.age from student as s").list();
List<Object[]> lists = session.createSQLQuery("select * from student as s").addScalar("s.name").addScalar("s.age").list();
List<Object[]> lists = session.createSQLQuery("select s.*,t.* from student s,teacher t where s.id = t.id").addEntity("s",Student.class).addEntity("t",Teacher.class).addJoin("t","s.teacher").addScalar("s.name").list();
命名查询
第一种方式
用xxx.hbm.xml
步骤
1.提供一个配置文件(xxx.hbm.xml)
<?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>
<sql-query name="sql_1">
SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id
<!-- addEntity: 实体查询 -->
<return alias="s" class="com.shuai.domain.Student"></return>
<return alias="t" entity-name="com.shuai.domain.Teacher"></return>
<!-- addJoin : 关联查询 -->
<return-join alias="t" property="s.teacher"></return-join>
<!-- addScalar : 标量查询 -->
<return-scalar column="s.stu_name"/>
</sql-query>
<sql-query name="call_proc">
{call query_stu(?)}
<return class="com.shuai.domain.Student"></return>
</sql-query>
</hibernate-mapping>
2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
<mapping resource="com/shuai/domain/Query.hbm.xml"/>
3.使用
List<Object[]> lists = session.getNamedQuery("sql_1").list();
第二种方式
在持久化类上加注解
步骤
1.在实体类上加注解
@NamedNativeQuery(name="sql_2", resultSetMapping="rs", query="SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id")
@SqlResultSetMapping(name="rs", entities={@EntityResult(entityClass=Student.class), // 实体查询
@EntityResult(entityClass=Teacher.class)},
columns={@ColumnResult(name="s.stu_name")}) // 标量要询
public class Student{}
2.使用
List<Object[]> lists = session.getNamedQuery("sql_2").list();
List<Student> lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
Hibernate调用存储过程
第一种方式:用命名查询的方法
List<Student> lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
第二种方式:直接用session.createSQLQuery()调用.
List<Student> lists = session.createSQLQuery("{call query_stu(?)}").addEntity(Student.class).setParameter(0, 20).list();
hibernate批处理
概述
如果有10w条数据需要一次性插入到数据库表.这个时候用Hibernate做添加的话有可能会出现内存溢出
批量添加
for(int i = 0; i < 100000; i++){
Teacher t = new Teacher();
session.save(t);
// t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
// 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
if (i % 10 == 0){
// 把一级缓存中的对象同步到底层的数据库
session.flush();
// 清空一级缓存,释放内存
session.clear();
}
}
session.commit();
批量修改
for (int i = 1; i <= 100000; i++){
// t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
Teacher t = (Teacher)session.get(Teacher.class, i);
t.setAge(28);
// 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
if (i % 10 == 0){
// 把一级缓存中的对象同步到底层的数据库
session.flush();
// 清空一级缓存,释放内存
session.clear();
}
}
session.commit();
批量删除
for (int i = 1; i <= 100000; i++){
// t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
Teacher t = (Teacher)session.get(Teacher.class, i);
session.delete(t);
// 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
if (i % 10 == 0){
// 把一级缓存中的对象同步到底层的数据库
session.flush();
// 清空一级缓存,释放内存
session.clear();
}
}
session.commit();
DML风格的HQL语句
概述
DML : Data Manipulation Language (DML) the statements: INSERT, UPDATE, DELETE
语法 :( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?.
操作DML风格HQL的步骤
获取Session
写DML风格的hql语句
Query query = session.createQuery(hql);
如果hql语句中有占位符需要设置参数值: query.setParameter(i, "值").
int res = query.executeUpdate();
使用
全部修改
String sql = "update from Teacher set age = ?";
int res = session.createQuery(sql).setParameter(0,20).executeUpdate();
条件修改
String sql = "update from Teacher set age = ? where id < ?";
int res = session.createQuery(sql).setParameter(0,20).setParameter(1,100).executeUpdate();
条件删除
String sql = "delete from Teacher t where t.age = ?";
int res = session.createQuery(sql).setParameter(0,40).executeUpdate();
hibernate数据过滤
概述
当你做查询时,有一个查询条件永远是固定的
使用数据过滤的步骤
1.定义数据过滤
@FilterDef()
2.指定哪些持久类使用该数据过滤
@Filter()
3.开启该数据过滤
session.enableFilter("数据过滤的名称").setParameter("定义的过滤字段名称",过滤字段的值);
使用
1.
@FilterDef(name="ageFilter", parameters={@ParamDef(name="minAge", type="int")})
public class Teacher{}
2.
@Filter(name="ageFilter", condition="age > :minAge")
public class Student{}
3.
session.enableFilter("ageFilter").setParameter("minAge", 20);
List<Student> students = session.createQuery("select t from Student t").list();
hibernate连接池
支持c3p0.
使用时配置hibernate.cfg.xml
<property name="hibernate.c3p0.min_size">3</property>
最小连接数
<property name="hibernate.c3p0.max_size">6</property>
最大连接数
<property name="hibernate.c3p0.max_statements">100</property>
一次执行的最大sql命令的个数
<property name="hibernate.c3p0.acquire_increment">2</property>
连接不够用一次增加多少个连接
<property name="hibernate.c3p0.timeout">5000</property>
连接超时时间
<property name="hibernate.c3p0.idle_test_period">3000</property>
连接空闲测试时间
hibernate缓存
为什么使用缓存
减少数据库访问次数,提高程序运行效率
一级缓存
session
缓存不共享,每个session维护自己独立的缓存区,session关闭后,缓存销毁
特点:缓存时间短范围小,效果不太明显.
跟Session相关(存放在内存中)
默认是开启的
作用:提高CUD操作的性能
操作
boolean contains(Object object)
判断Session的一级缓存中是否包含一个对象,包含的话这个对象就是持久化状态。
void evict(Object object)
从Session的一级缓存中逐出一个对象.(该对象就不是持久化状态的对象).
void flush()
将Session的一级缓存中的对象,同步到底层数据库表中.(立即同步)
void clear()
清空Session的一级缓存,所有的持久化状态的对象都清空。(释放内存)
void close()
关闭Session,先调用flush(),再调用clear().
二级缓存
基于sessionFactory的缓存
二级缓存的内容,可以给多个session访问,二级缓存数据可以给所有的session共享.
跟SessionFactory相关,因为SessionFactory存活的时间长。
默认是关闭的.
作用:提高查询效率.
特点:缓存资源,整个应用程序都可以使用.范围比较大.
使用二级缓存:
1.需要指定哪些类需要放入二级缓存区域
2.放入缓存的数据,要符合这样的特点,不要经常修改
hibernate的二级缓存是以插件的形式提供给开发程序员使用的,且有已经实现好的插件.
用的时候直接引入即可(hibernate.cfg.xml)配置.
二级缓存中的对象存放到哪里,这个需要配置.
一般会配置内存中存放一些对象,超出了内存中放存的对象个数,就写入磁盘.
ehcache.xml (配置二级缓存对象存放的配置文件).
HashtableCacheProvider使用步骤:
1.hibernate.cfg.xml配置开启二级缓存
<property name="hibernate.cache.use_second_level_cache">true</property>
2.hibernate.cfg.xml配置使用哪个二级缓存框架
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
3.配置指定哪些类加入缓存
第一种配置hibernate.cfg.xml
<class-cache usage="read-write" class="cn.shuai.domain.User"/>
read-only/read-write
第二种配置User.hbm.xml
<cache usage="read-write"/>
4.开启对象中的集合缓存-注意集合中的对象也要加入缓存
<class-cache usage="read-write" class="cn.shuai.domain.Address"/>
<collection-cache usage="read-write" collection="cn.shuai.domain.User.addresses"/>
5.注意:
以上配置是对get查询方式配置的.
6.如果需要对Hql查询也可以读取二级缓存,还需要配置
<property name="hibernate.cache.use_query_cache">true</property>
7.并且使用HQL查询时写法要注意
User user =(User) session.createQuery("from User where id=1").setCacheable(true);//数据要加入二级缓存/数据从二级缓存中取
EhCacheRegionFactory使用
1.配置开启二级缓存hibernate.cfg.xml文件中配置开启二级缓存.
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
2.拷贝二级缓存需要的jar包
ehcache-core-2.4.3.jar、hibernate-ehcache-4.3.8.Final.jar、slf4j-api-1.7.2.jar、slf4j-jdk14-1.7.2.jar
3.拷贝ehcache.xml文件
<ehcache>
<diskStore path="F:\\ehcache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="shuaiCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
4.配置哪些持久化类用二级缓存
第一种方式:hibernate.cfg.xml文件中配置
<class-cache usage="read-write" class="com.shuai.domain.Teacher" region="shuaiCache"/>
第二种方式:注解配置
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE,region="shuaiCache")
5.操作二级缓存的方法
Cache cache = SessionFactory.getCache();
获取缓存对象
boolean containsEntity(Class entityClass, Serializable identifier)
判断二级缓存中在是否包含一个对象
boolean containsEntity(String entityName, Serializable identifier)
void evictAllRegions();
清空二级缓存中所有对象
void evictEntity(Class entityClass, Serializable identifier)
从二级缓存中踢出指定的对象
void evictEntity(String entityName, Serializable identifier)
void evictEntityRegion(Class entityClass)
从二级缓存中踢出指定类型所有的对象
void evictEntityRegion(String entityName)
6.查询缓存(缓存的是查询语句)
7.获取二级缓存的统计信息
1.配置生成统计信息(hibernate.cfg.xml)
<property name="hibernate.generate_statistics">true</property>
<property name="hibernate.cache.use_structured_entries">true</property>
2.获取统计信息
Statistics statistics = sessionFactory.getStatistics();
命中的数量:statistics.getSecondLevelCacheHitCount()
错失的数量:statistics.getSecondLevelCacheMissCount()
8.对象在二级缓存中用什么格式保存
Map集合
key:主键列的值
value:缓存对象,该对象对需要缓存的对象中的数据做了封装.
SecondLevelCacheStatistics scs = statistics.getSecondLevelCacheStatistics("com.shuai.domain.Student");
scs.getEntries();
查询缓存(缓存的是查询语句)
概述
默认也是关闭的
它是在二级缓存的基础之上
使用步骤
1.配置开启查询缓存(hibernate.cfg.xml)
<property name="hibernate.cache.use_query_cache">true</property>
2.在创建查询时需要设置是否缓存这条语句.
query.setCacheable(true);
List<Student> students = session.createQuery("select s from Student s join fetch s.teacher").setCacheable(true).list();
查询缓存的缓存数据格式
{"sql语句" : {"org.fkjava.hibernate.domain.Student" : [1,2,3,4,5,6],"org.fkjava.hibernate.domain.Teacher" : [1,2]}}
注意:它要求hql语句要一致,而且hql语句中的占位符赋值也要一致,才能命中!
Session的线程安全问题
概述
如果是Hibernate3.1之前版本,它提供了HibernateUtil工具类可以获取当前线程相关的Session.
如果是Hibernate3.1之后版本,它提供了可配置的方式,让我们把Session配置成线程相关的Session.
把Session配置成线程安全
在hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">jta|thread</property>
org.hibernate.context.internal.JTASessionContext : jta (全局事务)
org.hibernate.context.internal.ThreadLocalSessionContext : thread (jdbc事务)
使用
Session session = session.getCurrentSession();
注意:
不要调用session.close();
面向JPA编程
Hibernate4编程
Configuration
SessionFactory
Session
Transaction
Query query = session.createQuery(hql);
Criteria criteria = session.createCriteria();
SQLQuery sqlquery = session.createSQLQuery(sql);
src/hibernate.cfg.xml
JPA编程
Persistence
EntityManagerFactory
EntityManager
EntityTransaction
Query query = entityManager.createQuery(jpql);
Query query = entityManager.createQuery(CriteriaQuery);
Query query = entityManager.createNativeQuery(sql);
src/META-INF/persistence.xml
JPQL
Java Persistence Query Language
java持久化查询语言.
web项目引入jpa
1.创建JPA项目
new --> jpa --> jpa project --> jpa fact(jpa implementation type:disable library configuration)
需要项目src中的META-INF文件夹和文件夹中的persistence.xml
把这个文件夹拷贝到我们自己的web项目的src目录即可。
2.修改persistence.xml
在hibernate-entitymanager-xxx.jar/org.hibernate.jpa/persistence_2_1.xsd文件中拷贝文件头即可
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
</persistence>
3.配置持久化单元persistence-unit
<persistence-unit name="shuaijpa" transaction-type="RESOURCE_LOCAL">
</persistence-unit>
name : 持久化单元名称
transaction-type : JTA|RESOURCE_LOCAL事务
4.配置JPA的提供商(实现商)
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
5.配置持久化类
<class>com.shuai.domain.Teacher</class>
6.配置属性
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/hibernate"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="32147"/>
<property name="hibernate.c3p0.max_size" value="10"/>
<property name="hibernate.c3p0.min_size" value="2"/>
</properties>
7.使用
public void oneTest(){
// 第一步:创建EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("shuaijpa");
// 第二步:创建EntityManager
EntityManager em = emf.createEntityManager();
// 第三步:获取事务
EntityTransaction transaction = em.getTransaction();
// 第四步:开启事务
transaction.begin();
// 第五步:利用 EntityManager完成所有的持久化操作
Teacher t = new Teacher();
t.setName("帅哥");
t.setDept("开发部");
t.setAge(30);
em.persist(t);
// 第七步:事务提交或回滚
transaction.commit();
// 第八步:关闭EntityManager与EntityManagerFactory
em.close();
emf.close();
}
增加
第一种方式
Teacher t = new Teacher(); // 瞬态
t.setAge(20);
t.setName("帅哥");
t.setDept("开发部");
t.setJob("项目经理");
em.persist(t); // 持久化状态
System.out.println(em.contains(t)); // 判断一个对象是不是持久化状态
第二种方式
Teacher t = new Teacher(); // 瞬态
t.setAge(20);
t.setName("帅哥");
t.setDept("开发部");
t.setJob("项目经理");
Teacher t1 = em.merge(t); // t1 持久化状态
System.out.println(em.contains(t1));
删除
Teacher t = em.find(Teacher.class, 4); // t 持久化状态
em.remove(t);
修改
持久化状态下
Teacher t = em.find(Teacher.class, 1); // t 持久化状态
t.setAge(300);
脱管状态下
Teacher t = new Teacher();
t.setId(1);
t.setAge(100);
t.setName("admin");
em.merge(t);
查询
Teacher t = em.find(Teacher.class, 1); // t 持久化状态
System.out.println(em.contains(t)); // 判断一个对象是不是持久化状态
操作一级缓存中的方法
boolean contains(Object object)
判断EntityManager的一级缓存中是否包含一个对象,包含的话这个对象就是持久化状态。
void detach(Object object)
从EntityManager的一级缓存中逐出一个对象.(该对象就不是持久化状态的对象).
void flush()
将EntityManager的一级缓存中的对象,同步到底层数据库表中.(立即同步)
void clear()
清空EntityManager的一级缓存,所有的持久化状态的对象都清空。(释放内存)
void close()
关闭EntityManager,先调用flush(),再调用clear().
三套查询
第一套查询(JPQL查询)
查询步骤
1.获取EntityManager
2.写jpql语句
3.Query query = entityManager.createQuery(jpql);
4.如果hql语句中有占位符,就需要为占位符赋值. query.setParameter("索引号", "值");
如果需要分页查询就需要为limit ?,? 这两个问号赋值
第一个问号:query.setFirstResult(start);
第二个问号:query.setMaxResults(size);
5.获取查询查询结果
如果本次查询有多条记录返回:query.getResultList();
如果本次查询只有一条记录返回:query.getsingleResult();
使用
List<Student> lists = em.createQuery("select s from Student as s", Student.class).getResultList();
List<Student> lists = em.createQuery("from Student", Student.class).getResultList();
List<Map<String, Object>> lists = em.createQuery("select new map(name as name, age as age) from Student").getResultList();
List<Student> lists = em.createQuery("from Student", Student.class).setFirstResult(start).setMaxResults(size).getResultList();
命名查询
@NamedQuery(name="query_1", query="select s from Student s join fetch s.teacher")
public class Teacher {}
List<Student> lists = em.createNamedQuery("query_1").getResultList();
第二套查询(sql查询)
查询步骤
1.获取EntityManager.
2.写sql语句.
3.查询
Query query = createNativeQuery(String sqlString); // 查询多列
Query query = createNativeQuery(String sqlString, Class resultClass); // 实体查询
Query query = createNativeQuery(String sqlString, String resultSetMapping); // 关联查询
4.如果hql语句中有占位符,就需要为占位符赋值. query.setParameter("索引号", "值");
如果需要分页查询就需要为limit ?,? 这两个问号赋值
第一个问号:query.setFirstResult((pageIndex - 1) * pageSize);
第二个问号:query.setMaxResults(pageSize);
5.获取查询查询结果:
如果本次查询有多条记录返回:query.getResultList();
如果本次查询只有一条记录返回:query.getsingleResult();
使用
List<Student> lists = em.createNativeQuery("select * from stu_info", Student.class).getResultList();
List<Object[]> lists = em.createNativeQuery("select * from stu_info").getResultList();
List<Object[]> lists = em.createNativeQuery("select s.*, t.* from stu_info as s, tea_info as t where s.t_id = t.tea_id", "rs").getResultList();
@SqlResultSetMapping(name="rs" , entities={@EntityResult(entityClass=Student.class),@EntityResult(entityClass=Teacher.class)},columns={@ColumnResult(name="s.stu_name")})
public class Student {}
第三套查询(CriteriaQuery查询)
查询步骤
1.获取EntityManager.
2.Query query = entityManager.createQuery(CriteriaQuery);
3.如果需要分页查询就需要为limit ?,? 这两个问号赋值
第一个问号:query.setFirstResult(start);
第二个问号:query.setMaxResults(size);
4.获取查询查询结果:
如果本次查询有多条记录返回:query.getResultList();
如果本次查询只有一条记录返回:query.getsingleResult();
API
CriteriaBuilder
构建查询对象的类.
构建CriteriaQuery
生成查询条件
生成排序
生成聚集函数
CriteriaQuery
查询对象类
Root from(Class<X> entityClass) : 指定查询哪个持久化类.
groupBy(Expression<?>... grouping) : 分组
multiselect(Selection<?>... selections) : 查询多列
select(Selection<? extends T> selection) : 查询一列
where(Predicate... restrictions) : 添加查询条件
orderBy(Order... o): 排序
Root
对查询的持久化类中的属性做了封装.
Path path = root.get("属性名");
join() : 关联查询 root.join("teacher", JoinType.INNER);
fetch() : 抓取连接.
Path
代表一个属性
使用
查询所有的学生
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
List<Student> lists = em.createQuery(cq).getResultList();
查询一列
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<String> cq = builder.createQuery(String.class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
cq.select(name);
List<String> lists = em.createQuery(cq).getResultList();
查询多列
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Object[]> cq = builder.createQuery(Object[].class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
Path<Integer> age = root.get("age");
cq.multiselect(name, age);
List<Object[]> lists = em.createQuery(cq).getResultList();
添加查询条件
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
Path<String> name = root.get("name");
Path<Integer> age = root.get("age");
cq.where(builder.like(name, "%小%"), builder.between(age, 19, 200));
List<Student> lists = em.createQuery(cq).getResultList();
排序
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
Path<String> age = root.get("age");
cq.orderBy(builder.desc(age));
List<Student> lists = em.createQuery(cq).getResultList();
统计函数
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Integer> cq = builder.createQuery(Integer.class);
Root<Student> root = cq.from(Student.class);
Path<Integer> age = root.get("age");
cq.select(builder.sum(age));
Integer res = em.createQuery(cq).getSingleResult();
关联查询
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
root.join("teacher", JoinType.INNER);
Path<Integer> t_id = root.get("teacher").get("id");
cq.where(builder.equal(t_id, 1));
List<Student> lists = em.createQuery(cq).getResultList();
抓取连接
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Student> cq = builder.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
root.fetch("teacher", JoinType.INNER);
List<Student> lists = em.createQuery(cq).getResultList();
hibernate逆向工程
1.准备myeclipse
2.window-->show view-->DB browser
3.在db browser中 new 数据库
Driver timplate 选择 mysql
Driver name 直接写一个别名
Connection URL :jdbc:mysql:///test
user name:root
password:root
Driver JARS:驱动包位置
Driver className:com.mysql.jdbc.Driver
4.创建一个新的webhibernate项目
5.右键webhibernate项目-->myeclipse-->project facts[capabilities]-->install hibernate facet
6.设置hibernate版本 hibernate specification version :3.3
7.设置targer runtime :myeclipse generic runtime for javaee 6.0
8.需要配置文件hibernate.cfg.xml
9.java源码配置java.package:com.shuai.test
10.className:HibernateSessionFactory
11.设置一个DB driver:第三步配置过了
12.添加包
13.选择要逆向的表
右键-->hibernate reverse Engineering
14.选择java package 选择路径
15.create pojo
16.create data object
17.finish即可
OpenSessionInView
在过滤器/拦截器中开启session,在jsp页面处理完数据之后,再关闭session即可
Interceptor
public class SessionInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Transaction tx = null;
try {
// 1. 创建session
Session session = HibernateUtils.getSession();
// 2. 开启事务
tx = session.beginTransaction();
// 3. 放行
String result = invocation.invoke(); // // execute处理完,就表示 jsp已经处理完毕
return result;
} catch (Exception e) {
tx.rollback();
e.printStackTrace(); // 打印错误信息!
return "error";
} finally {
// 4. (执行完action.execute方法), 提交事务
tx.commit();
}
}
}
HibernateUtils
public class HibernateUtils {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
}
public static Session getSession() {
return sf.getCurrentSession();
}
}
Controller
public class DeptAction extends ActionSupport{
private int id;
public void setId(int id) {
this.id = id;
}
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
// 创建service
private DeptService deptService = new DeptService();
@Override
public String execute() throws Exception {
// 主键查询
dept = deptService.findById(id);
return SUCCESS; // execute处理完,就表示 jsp已经处理完毕
}
}
jsp使用
<s:iterator value="dept.employees">
<tr>
<td><s:property value="id"/></td>
<td><s:property value="name"/></td>
<td><s:property value="age"/></td>
</tr>
</s:iterator>
session的创建方式
第一种方式-openSession
Session session = sf.openSession();
注意:
1.每次获取的Session不同
2.可以不使用事务
第二种方式-线程方式创建Session
Session session = sf.getCurrentSession();
注意:
1.一定要配置以线程的方式创建Session
<property name="hibernate.current_session_context_class">thread</property>
2.创建的Session,提交事务,自动关闭session
3.使用getCurrentSession方法必须要有事务环境
联合主键
Keys.java - 联合主键,必须实现可序列化标记
public class Keys implements Serializable{
private String name;
private String address;
}
User.java
public class User {
private Keys key;
private int age;
}
User.hbm.xml
<?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 package="cn.itcast.composite" auto-import="true">
<class name="User" table="t_user_key">
<composite-id name="key">
<key-property name="name"></key-property>
<key-property name="address"></key-property>
</composite-id>
<property name="age"></property>
</class>
</hibernate-mapping>
AppTest.java
@Test
public void save() {
Session session = sf.openSession();
session.beginTransaction();
Keys key = new Keys();
key.setName("Jack");
key.setAddress("gz");
User user = new User();
user.setKey(key);
user.setAge(20);
session.save(user);
session.getTransaction().commit();
session.close();
}
@Test
public void get() {
Session session = sf.openSession();
session.beginTransaction();
Keys key = new Keys();
key.setName("Jack");
key.setAddress("gz");
User user = (User) session.get(User.class, key);
System.out.println(user.getKey().getName());
System.out.println(user.getKey().getAddress());
System.out.println(user.getAge());
session.getTransaction().commit();
session.close();
}
基础hql查询
//查询全部
@Test
public void queryAll() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("from User");
List<User> list = q.list();
session.getTransaction().commit();
session.close();
}
//删除
@Test
public void delete() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("delete from User where id=1)");
q.executeUpdate();
session.getTransaction().commit();
session.close();
}
//分页
@Test
public void page() {
Session session = sf.openSession();
session.beginTransaction();
Query q = session.createQuery("from User");
// 设置分页参数
q.setFirstResult(0); //相当于 limit 第一个参数 查询的其实行
q.setMaxResults(2); //相当于 limit 第二个参数 查询返回的行数
List list = q.list();
session.getTransaction().commit();
session.close();
}
Hql查询
API
Query
list();//查询全部
Query query = session.createQuery("from User");
List<user> list = query.list();//会懒加载
注意:会有一级缓存,缓存数据.一个id的数据只查询一次
连接查询
Query query = session.createQuery("from Address a inner join a.user");
List<Object[]> list = query.list();//即时查询,连接查询可以解决懒加载问题.
fetch查询
把右表的数据填充到左表
添加fetch查询语句sql没有任何变化,变化的是封装数据的方式
Query query = session.createQuery("from Address a inner join a.user");
Query query = session.createQuery("from Address a inner join fetch a.user");