Hibernate
是一款开源的ORM框架,hibernate是在我们的MVC设计模式中,充当的是持久化层,负责数据的操作交互。
Jboss
2001-2004
搭建步骤:
1:导包
<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.21.Final</version>
</dependency>
2:加载hibernate配置文件
hibernate.cfg.xml
note.hbm.xml
hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 方言 -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- 数据库连接信息 -->
<property name="connection.url">
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 显示底层sql语句 -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping resource="hbm/Note.hbm.xml" />
</session-factory>
</hibernate-configuration>
note.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>
<!-- name:代表数据库表所对应的java实体对象信息
table:代表的是数据库表名称
-->
<class name="com.xdl.entity.Note" table="note">
<!-- 必须要指定主键ID -->
<id name="id" type="integer" column="id"></id>
<!-- 其它字段使用property属性标签定义,其中:
name:代表数据库表中的字段所对应的实体对象中的属性名称
type:代表数据库表中的字段类型,注意:首字母必须小写
column:代表数据库表中的字段名称
-->
<property name="context" type="string" column="context"></property>
<property name="publishTime" type="date" column="publishTime"></property>
<property name="likeCount" type="integer" column="likeCount"></property>
<property name="userId" type="integer" column="userId"></property>
</class>
</hibernate-mapping>
演变:
jdbc--->jdbTemplate--->mybatis---->hibernate
hibernate与mybatis的区别?
1:hibernate学习难度大于mybatis
2:hibernate的扩展性和移植性要比mybatis强
3:hibernate支持count、sum、avg函数,但是不支持一些类型转换,比如:日期转换,字符转换等
4:hibernate支持事务,并且自支持缓存,如:一级缓存、二级缓存和查询缓存,可以使用第三方缓存技术
5:hibernate不建议使用left join,而mybatis可以支持
6:hibernate自支持分页条件,而mybatis需要配置分页插件
7:hibernate一般应用与老系统的维护和开发,目前流行的企业解决方案为mybatis
8:hibernate不需要写sql语句,是自动生成的,而mybatis需要写sql语句
数据库工具类
/**
* 数据库工具类,获取数据库连接session
* @author likang
* @date 2018-1-11 上午9:58:18
*/
public class HibernateUtils {
public static Session getSession(){
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");
SessionFactory sessionFactory = conf.buildSessionFactory();
Session session = sessionFactory.openSession();
return session;
}
}
增删改查操作
问题:(session.close())
1:数据库游标越界
2:too many connect
解决方式:
1:重启数据库----命令重启---service mysqld stop/start/restart
2:使用命令查询当前连接数据库的进程号,直接kill
3:经常在开发环境使用--借助连接数据库的客户端
TestHibernate.java:
/**
* 测试hibernate框架操作
* @author likang
* @date 2018-1-11 上午10:24:19
*/
public class TestHibernate {
/**
* 查询操作
*/
@Test
public void test1(){
Session session = HibernateUtils.getSession();
//Note.hbm.xml中指定的表,查询数据库中note表id为16条的信息,自动生成sql语句,不需要手写sql语句
Note note = (Note) session.get(Note.class, 16);
if (note != null) {
System.out.println(note.getContext());
}else{
System.out.println("查询数据为空");
}
}
/**
* 增加操作
* 写操作:需要开启事务,执行完毕之后,需要关闭
*/
@Test
public void test2(){
Session session = HibernateUtils.getSession();
Note note = new Note();
note.setId(201);
note.setContext("java13测试数据2");
note.setLikeCount(100);
note.setUserId(1);
note.setPublishTime(new Date(System.currentTimeMillis()));
Transaction ts = session.beginTransaction();//开启事务
session.save(note);
ts.commit();//提交----flush---commit
session.close();
}
/**
* 删除操作
* 后台实际执行了两步sql
* 1:先执行查询操作,如果数据存在,则继续执行delete语句,如果不存在,则不执行删除语句
*/
@Test
public void test3(){
Session session = HibernateUtils.getSession();
Note note = new Note();
note.setId(200);
Transaction ts = session.beginTransaction();//开启事务
session.delete(note);
ts.commit();//提交----flush---commit
session.close();
}
/**
* 修改操作
* 在修改数据之前,一般是先进行查询,将数据结果集,赋值给note
*
*/
@Test
public void test4(){
Session session = HibernateUtils.getSession();
Note note = (Note) session.get(Note.class, 201);
// Note note = new Note();
// note.setId(201);
note.setLikeCount(300);
Transaction ts = session.beginTransaction();//开启事务
session.update(note);
ts.commit();//提交----flush---commit
session.close();
}
}
Hibernate主键管理
1.sequence 序列
一般适用于oracle数据库
2.identity 主键自增
一般用于mysql、SqlServer数据库
3.native 自动匹配
可以自动匹配当前数据库类型,
如果当前数据库是mysql,则自动将主键设置为identity,
如果当前数据库为oracle,则自动将主键识别为sequence
4.increment 自动获取主键+1
自动的去数据库获取最大值的ID,然后+1,设置为主键ID
5.uuid/hilo 随机算法和高低位算法
32---varchar(32)
6.assigned
需要我们自动的去设置主键ID,需要添加setId();
配置主键的位置:
note.hbm.xml中:
<id name="id" type="integer" column="id">
<!-- 指定表的主键策略 -->
<generator class="identity"></generator>
</id>
Hibernate查询操作
HQL查询
HQL:hibernate query Language(面向对象的查询)----对象化 (实体)
select * from Note(实体类名)
SQL:Structured Query Language(面向结构的查询)---结构化 (数据库表和表字段)
select * from note(数据库表名)
HQL与SQL有什么区别?
1:HQL是面向对象的查询,SQL是面向结构的查询
2:HQL对查询语句的大小写非常敏感,而SQL对查询语句的大小写字段属性依赖于我们的数据库配置信息
3:HQL在进行查询的时候,使用的是类名和属性名称,而SQL在查询的时候,使用的是数据库表名和字段名
4:如果我们是需要查询表中所有的数据,那么HQL,可以省略select *,直接使用 from Note,SQL则不能省略
5:HQL不支持类型转换,如:日期转换、字符转换等,SQL支持
6:HQL不能进行特别复杂的查询操作,也就是说,不建议使用left join,而SQL,可以无限制的使用left join等关联,进行复杂查询
示例:
public class TestHQL {
/**
* 查询操作
*/
@Test
public void test1(){
Session session = HibernateUtils.getSession();
String hql = "from Note";//‘Note’代表类名,如果查询全部,则可以省略select *
Query query = session.createQuery(hql); //返回的是Query对象
List<Note> list = query.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println("笔记内容为:"+list.get(i).getContext()+"--------时间为:"+list.get(i).getPublishTime());
}
}
}
/**
* 带有where条件的查询
*/
@Test
public void test2(){
Session session = HibernateUtils.getSession();
String hql = "from Note where publishTime >?";
Query query = session.createQuery(hql);
query.setDate(0, Date.valueOf("2017-12-01"));//第一个参数代表hql中参数的下标,从0开始,第二个参数为赋值
List<Note> list = query.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println("id:"+list.get(i).getId()+"笔记内容为:"+list.get(i).getContext()+"--------时间为:"+list.get(i).getPublishTime());
}
}
}
/**
* 分页查询
*/
@Test
public void test3(){
Session session = HibernateUtils.getSession();
String hql = "from Note";//‘Note’代表类名,如果查询全部,则可以省略select *
Query query = session.createQuery(hql);
query.setFirstResult(6);//代表的是从数据库第几条数据开始,不包含当前条数
query.setMaxResults(2);//一共获取多少条
List<Note> list = query.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println("id:"+list.get(i).getId()+"笔记内容为:"+list.get(i).getContext()+"--------时间为:"+list.get(i).getPublishTime());
}
}
}
/**
* 查询个数
*/
@Test
public void test4(){
Session session = HibernateUtils.getSession();
String hql = "select count(*) from Note";
Query query = session.createQuery(hql);
Long count = (Long) query.uniqueResult();
System.out.println("一共有:"+count);
}
}
Criteria查询
复杂条件查询:
示例:
public class TestCriteria {
/**
* 查询操作
*/
@Test
public void test1(){
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Note.class);//直接实体对象映射就可以查询note表
List<Note> list = criteria.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println("内容为:"+list.get(i).getContext());
}
}
}
/**
* 1:select * from note where note.publishTime > '2017-12-01'
*/
@Test
public void test2(){
Session session = HibernateUtils.getSession();
Criteria criteria = session.createCriteria(Note.class);
//select * from note where note.publishTime > '2017-12-01'
// criteria.add(Restrictions.gt("publishTime", Date.valueOf("2017-12-01")));//publishTime > '2017-12-01'
//select * from note where note.publishTime > '2017-12-01' and userId = 1
// criteria.add(Restrictions.eq("userId", 1));// 时间publishTime 和userId拼接成一个sql语句了
select * from note where note.publishTime > '2017-12-01' or userId = 1
criteria.add(Restrictions.or(Restrictions.gt("publishTime", Date.valueOf("2017-12-01")),
Restrictions.eq("userId", 1)));
criteria.addOrder(Order.desc("publishTime"));//倒序
//Order.asc("publishTime");正序
List<Note> list = criteria.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println("时间为:"+list.get(i).getPublishTime()+"--------"+"内容为:"+list.get(i).getContext());
}
}
}
}
NativeSQL查询
原生sql查询:
/**
* 原生sql查询
* @author likang
* @date 2018-1-11 下午2:41:15
*/
public class TestNativeSQL {
@Test
public void test1(){
Session session = HibernateUtils.getSession();
String sql = "select * from note";//note 是数据库表名
SQLQuery query = session.createSQLQuery(sql);
/*List<Note> list = query.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getContext());
}
}*/ //会提示类型转换异常,
List<Object[]> list = query.list();
if (list != null && list.size() > 0) {
for (Object[] obj : list) {
System.out.println(obj[1]);
}
}
}
/**
* 推荐使用的查询方式
*/
@Test
public void test2(){
Session session = HibernateUtils.getSession();
String sql = "select * from note";//note 是数据库表名
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Note.class);//加载数据库表映射文件信息
List<Note> list = query.list();
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getContext());
}
}
}
}
Hibernate注解应用
类名:
@Entity//指定当前实体为一个映射关系
@Table(name="note")//映射到数据库note表
属性字段名:
主键:
@Id//指定实体对象主键
@Column(name="id")//指定对应到数据库表中的字段名称
@GeneratedValue(strategy=GenerationType.IDENTITY)//设置主键的生成策略
其它字段:
@Column(name="context")
需要将hibernate.cfg.xml中的加载映射文件修改为:
<mapping class="com.xdl.entity.Note"/>
Hibernate特性
延迟加载
hibernate中有一些特定的api具有延迟加载的特性,在使用了具有延迟加载特性的api之后,不会立刻去开启事务并指定hql语句,直到使用对象的时候,才会去调用事务,执行查询。
load:具有延迟加载特性
find:具有延迟加载的特性
iterate:具有延迟加载的特性
get:没有延迟加载特性
list:没延迟加载的特性
问题:(使用了延迟加载的特性API)
org.hibernate.LazyInitializationException: could not initialize proxy ...no session
解决:
明天讲(opensessionviewFilter)
示例:
@Test
public void test1(){
Session session = HibernateUtils.getSession();
// Note note2 = (Note) session.get(Note.class, 16);
Note note1 = (Note) session.load(Note.class, 16);
}
缓存(性能优化)
-
一级缓存
hibernate默认开启一级缓存,并且不需要做任何的配置 session独享
示例:
@Test
public void test1(){
//Session独享 打印第一条sql语句,后面的直接得到数据
Session session = HibernateUtils.getSession();
Note note = (Note) session.get(Note.class, 16);
System.out.println(note.getContext());
// Session session1 = HibernateUtils.getSession();
//
// Note note1 = (Note) session1.get(Note.class, 16);
// System.out.println(note1.getContext());
}
- 二级缓存
- 查询缓存
持久化(session)
hibernate 数据状态
状态值:
transient:临时状态
Note note = new Note();
此状态的数据,可以随时被GC //GC垃圾回收机制回收
persistent:持久化状态
session.save(note);---将临时状态数据--->持久化状态数据
session.delete(note);--->将持久化状态数据-->临时状态数据--->删除
持久化状态的数据,永远不会自动gc的
detached:游离状态/托管状态
session.close();---将持久---》托管
session.update();---将托管---》持久
游离状态可以随时被GC