目录
一、Hiberate框架概述
二、Hibernate入门
1.搭建Hibernate环境
1.1 导入Hibernate的jar包
1.2 导入Hibernate依赖的jar包
2.编写测试Demo
2.1 Entity类
2.2 创建数据库
2.3 配置Entity和数据库表的映射关系
2.3.1 创建xml配置文件
2.3.2 配置文件xml引入dtd约束
2.3.3 配置映射关系
2.4 创建Hibernate的核心配置文件
2.4.1 创建hibernate.cfg.xml配置文件
2.4.2 引入dtd约束
2.4.3 配置hibernate.cfg.xml
2.5 代码实现数据库CRUD操作
2.6 Hibernate细节注意
三、Hibernate查询
1.Query查询
2.Criteria查询
3.SQLQuery查询
一、Hiberate框架概述
本篇文章主要记录学习hibernate框架的笔记,hibernate框架应用于javaEE三层结构中的DAO层(数据持久化),使用orm(object relational mapping:对象关系映射)思想对数据库进行crud操作,底层封装了jdbc,使用hibernate不需要写sql语句。
orm:object relational mapping----对象关系映射
1.实体类(javaBean/entity)与数据库中表一一对应
1)实体类和表对应
2)实体类中成员变量与表中字段对应
2.操作实体类对象更新表中记录,不需要直接操作数据库表
本篇博客中用到的hibernate版本是:hibernate-release-5.0.7.Final.zip
二、Hibernate入门
1. 搭建Hibernate环境
1.1 导入Hibernate的jar包
Hibernate的lib/required下的所有jar包
Hibernate的lib/jpa下的jar包
1.2 导入Hibernate依赖的jar包
主要是打印日志的jar包,因为Hibernate本身没有打印日志的jar包,还有mysq的驱动jar包
以上,Hibernate开发环境搭建完毕,接下来就可以使用Hibernate进行DAO层的开发了
2. 编写测试Demo
2.1 Entity类
entity类的写法与javaBean一样,需要提供set/get方法,但是entity类中必须要包含一个值唯一的id
package cn.wh.entity;
public class User {
/*hibernate要求实体类中必须有一个属性的值是唯一的,类似于主键*/
private int uid;
private String username;
private String password;
private String address;
/*生成set和get方法*/
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUserName() {
return username;
}
public void setUserName(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.2 创建数据库
这里使用SQLyog创建数据库
数据库中的表可以自己创建,也可以不创建,由hibernate来创建
2.3 配置Entity和数据库表的映射关系
2.3.1 创建xml配置文件
配置文件名称及位置没有特定要求,建议把配置文件放在Entity类的包下,且名称为*.hbm.xml(hibernate mapping)
eg:
User.hbm.xml
2.3.2 配置文件xml引入dtd约束
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
该约束文件在hibernate zip包里有,hibernate-mapping-3.0.dtd
2.3.3 配置映射关系
<?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>
<!-- 1.配置Entity类和数据库表的对应
class标签属性:name,table
name : Entity类名称,必须是全路径,即包名.类名
table : 表名称
-->
<class name="User" table="t_user">
<!-- 2.配置entity类id和表id对应
hibernate要求entity类必须有一个成员的值唯一
hibernate要求表中必须有一个字段的值唯一
-->
<!-- id标签属性:name,column
name : entity类中的id属性名称
column : 表中id字段名称,建议跟entity中对应的属性名称一致
-->
<id name="uid" colum="uid">
<!-- 3.设置表id的增长策略
native : 设置表中id字段为主键,且自增长
uuid : 使用uuid作为表的主键
-->
<generator class="native"></generator>
</id>
<!-- 4.配置entity类和表中其他属性的对应关系
name : entity类中的属性名称
column : 表中字段名称,建议跟entity中对应的属性名称一致
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
2.4 创建Hibernate的核心配置文件
作用:配置映射的数据库信息、hibernate信息和映射关系xml文件,该配置文件是hibernate默认加载的配置文件
核心配置文件的名称及位置是固定的
名称 :hibernate.cfg.xml
位置 :src目录下
2.4.1 创建hibernate.cfg.xml配置文件
在工程的src目录下创建hibernate.cfg.xml配置文件
2.4.2 引入dtd约束
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
该约束文件在hibernate zip包里也有,hibernate-configuration-3.0.dtd
2.4.3 配置hibernate.cfg.xml
在hibernate zip文件的hibernate-release-5.0.7.Final\project\etc目录下有hibernate.properies文件,里面有需要配置的数据库参数,根据MYSQL/ORACLE,需要配置的数据库参数略有不同
<?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>
<!-- 1.配置数据库信息(必须配置) -->
<!-- 数据库驱动类 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url,hibernate_demo为我们创建的数据库名称 -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_demo</property>
<!-- 登录数据库的名称及密码 -->
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- 2.配置hibernate信息(可选配置) -->
<!-- 输出sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化输出的sql语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 根据hbm配置文件里的数据库表,对数据库进行ddl操作,创建、删除...
update : 如果数据库中不存在hbm中配置的表,则先创建该表;
如果数据库中存在hbm中配置的表,则直接更新
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库方言
例如:如果对数据库进行分页查询,根据该配置,让hibernate识别数据库自身的关键字
mysql分页使用limit
oracle分页使用rownum
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 支持thread local session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 3.添加映射配置文件(必须配置) -->
<!-- *.hbm.xml文件相对于src目录的路径 -->
<mapping resource="cn/wh/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
小技巧:
eclipse引入dtd约束文件方法:Preference-->xml catalog--->add--->catalog entry--->location/uri key
2.5 代码实现数据库CRUD操作
首先编写HibernateUtils类,提供静态方法,由于Hibernate中构造SessionFactory时可能会帮我们创建映射的数据表,因此导致该过程耗资源,所以在项目中一般SessionFactory只创建一次,参照以下写法:
HibernateUtils:
package cn.wh.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private final static Configuration cfg;
private final static SessionFactory sessionFactory;
static{
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
/*获取与本地线程绑定的session--单线程变量*/
public static Session getThreadLocalSession(){
return sessionFactory.getCurrentSession();
}
/*/*获取普通session*/
public static Session getSession(){
return sessionFactory.openSession();
}
}
JUnit测试:
@Test
public void testTransaction(){
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
/*解析配置文件,创建数据库表*/
sessionFactory = HibernateUtils.getSessionFactory();
/*建立连接*/
session = HibernateUtils.getThreadLocalSession();
/*开启事务*/
tx = session.beginTransaction();
/*数据库操作*/
/*insert*/
User userI = new User();
userI.setUsername("wang");
userI.setAddress("hangzhou");
userI.setPassword("123456");
session.save(userI);
/*query:根据id查询*/
User userQ = session.get(User.class, 4);
System.out.println(userQ);
/*update*/
userQ.setUsername("huang");
session.update(userQ);
/*delete:默认根据id删除,所以只要输入的entity对象有id即可*/
User userD = new User();
userD.setUid(5);
session.delete(userD);
/*提交事务*/
tx.commit();
}catch(Exception e){
/*事务回滚*/
System.out.println(e);
tx.rollback();
}finally {
/*关闭连接*/
session.close();
sessionFactory.close();
}
}
输出:
Hibernate:
insert
into
t_user
(username, password, address)
values
(?, ?, ?)
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
t_user user0_
where
user0_.uid=?
User [uid=4, username=huang, password=123456, address=hangzhou]
Hibernate:
delete
from
t_user
where
uid=?
2.6 Hibernate细节注意
saveOrUpdate方法:
/*saveOrUpdate:uid存在则update,此时uid必须存在数据表中;uid不存在则save*/
User userSU = new User();
userSU.setUid(8);
userSU.setUsername("zhang");
userSU.setAddress("huangshan");
userSU.setPassword("0909");
session.saveOrUpdate(userSU);
一级缓存:
1.读取的数据存到内存中,下次再读取时直接从内存取
2.Hibernate一级缓存默认打开
3.Hibernate一级缓存使用范围:session范围
4.只存储持久态的entity对象(托管态、瞬时态entity对象对此无效)
验证:
User userFirst = session.get(User.class, 8);
System.out.println(userFirst);
User userSecond = session.get(User.class, 8);
System.out.println(userFirst == userSecond);
输出:
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
t_user user0_
where
user0_.uid=?
User [uid=8, username=zhang, password=0909, address=huangshan]
true
持久态对象自动update:
现象:
在一个事务提交之前,如果修改了数据库中的entity(持久态),在事务提交时还没有调用update更新数
据库,则Hibernate会自动提交update,更新数据表
原理:
因为Hibernate除了维护一块一级缓存外,还维护了一个一级缓存的副本,当查询数据库时,会在一级缓
存和副本中个保存一份返回的entity对象,当修改entity持久化对象时,会修改一级缓存里对应entity
对象,但是不会修改副本里的entity对象,在事务commit的时候会对比一级缓存和副本,发现entity不
相等,则把一级缓存中的数据更新到数据库
验证:
/*开启事务*/
tx = session.beginTransaction();
/*持久态对象自动update*/
User uC = session.get(User.class, 8);
uC.setUsername("LI");
/*未调用update方法,直接commit*/
/*提交事务*/
tx.commit();
输出:
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
t_user user0_
where
user0_.uid=?
Hibernate:
update
t_user
set
username=?,
password=?,
address=?
where
uid=?
三、Hibernate查询
1.Query查询
特点:
不需要写sql语句,但是要写hql语句(hibernate query language),from + 实体类名
Demo:
/*1.创建Query对象*/
/*参数为hql语句,from + 实体类名*/
Query query = session.createQuery("from User");
/*2.调用Query对象的方法,得到查询结果*/
List<User> users = query.list();
for(User user : users){
System.out.println(user);
}
输出:
Hibernate:
select
user0_.uid as uid1_0_,
user0_.username as username2_0_,
user0_.password as password3_0_,
user0_.address as address4_0_
from
t_user user0_
User [uid=4, username=huang, password=123456, address=hangzhou]
User [uid=7, username=wang, password=123456, address=hangzhou]
User [uid=8, username=LI, password=0909, address=huangshan]
2.Criteria查询
特点:
不需要写语句
Demo:
/*1.创建Criteria对象*/
Criteria criteria = session.createCriteria(User.class);
/*2.调用Criteria对象方法查询*/
List<User> users = criteria.list();
for(User user : users){
System.out.println(user);
}
输出:
Hibernate:
select
this_.uid as uid1_0_0_,
this_.username as username2_0_0_,
this_.password as password3_0_0_,
this_.address as address4_0_0_
from
t_user this_
User [uid=4, username=huang, password=123456, address=hangzhou]
User [uid=7, username=wang, password=123456, address=hangzhou]
User [uid=8, username=LI, password=0909, address=huangshan]
3.SQLQuery查询
特点:
可以写sql语句
Demo:
/*1.创建SQLQuery对象*/
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
/*2.调用SQLQuery对象方法查询*/
/*返回结果为每行记录的组成的数组的list*/
List<Object[]> users = sqlQuery.list();
for(Object[] user : users){
/*以字符串形式输出数组*/
System.out.println(Arrays.toString(user));
}
/*设置entity属性,返回entity类的list集合*/
sqlQuery.addEntity(User.class);
List<User> usersEntity = sqlQuery.list();
for(User user : usersEntity){
System.out.println(user);
}
输出:
Hibernate:
select
*
from
t_user
[4, huang, 123456, hangzhou]
[7, wang, 123456, hangzhou]
[8, LI, 0909, huangshan]
Hibernate:
select
*
from
t_user
User [uid=4, username=huang, password=123456, address=hangzhou]
User [uid=7, username=wang, password=123456, address=hangzhou]
User [uid=8, username=LI, password=0909, address=huangshan]