-
什么是框架
框架就是一个半成品的项目,我们书写项目可以从半成品的项目开始写,这样能够大大的提高开发效率。
不必纠结于框架本身的实现,只要学会如何使用这个框架即可。
- 什么是Hibernate框架
这个框架应用于DAO层
ORM:Object relaction mapping
实体类和数据表之间建立了联系,通过操作对象,直接对数据库进行修改。
Hibernate框架搭建
1、导包
导入required目录下的所有包,然后在导入数据库驱动包
2、准备一个实体类
-
所有的属性应该设置为私有,并添加get-set方法
-
构造函数要么不写,如果要写至少要写两个(必须包含一个空的)
-
属性的类型应是包装类型
-
必须拥有一个主键
3、准备数据库
数据库必须由我们自己建立,数据库表,可以由hibernte自动创建,如果手动创建,表中的字段要和实体类一一对应。
4、创建实体类和数据库表之间的映射配置文件
创建一个 实体类名+.hbm+.xml
建议这个文件的目录和实体类在同一目录下
Column:与数据库字段有关
<hibernate-mapping>
<class name="cn.hd.bean.User" table="t_user">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<property name="sex" column="sex"></property>
<property name="age" column="age"></property>
<property name="balance" column="balance"></property>
</class>
</hibernate-mapping>
5、书写核心配置文件
名字必须为hibernate.cfg.xml
文件的位置必须放在src目录下
导入约束
<!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://localhost:3306/hibernate01</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">123456</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="hibernate.connection.isolation">4</property>
<mapping resource="cn/hd/bean/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
6、书写测试代码
public static void main(String[] args) {
//读取配置文件
Configuration cfg = new Configuration();
cfg.configure();
//创建sessionFaction
SessionFactory sessionFactory = cfg.buildSessionFactory();
//获得一个session
Session session = sessionFactory.openSession();
//开启事务
Transaction transaction=session.beginTransaction();
User user = new User();
user.setName("大红");
user.setSex("女");
user.setAge(20);
user.setBalance(28000);
session.save(user);
//提交事务
transaction.commit();
//释放资源
session.close();
sessionFactory.close();
}
配置文件详解
1、映射文件
<!--下面class中的类的路径,下面的class name属性可以简写-->
<hibernate-mapping>
<!--映射类和数据库表之间的关系-->
<!--name属性是实体类名 写完整路径名-->
<!--table属性 数据库表名字-->
<class name="cn.hd.bean.User" table="t_user">
<!--映射文件中必须拥有主键-->
<id name="id" column="id">
<!--主键生成策略
identity:mysql自动递增
increment:
sequence:Orancel数据库中的自动递增
native:自动递增(3和1)
assigned
uuid:百度
-->
<generator class="native"></generator>
</id>
<!--基本属性 在这里可以设置数据表属性
字段类型 长度 不为空 默认值
-->
<property name="name" column="name"></property>
<property name="sex" column="sex"></property>
<property name="age" column="age"></property>
<property name="balance" column="balance"></property>
</class>
</hibernate-mapping>
2、核心配置文件详解
名字和位置都必须按照规定来
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate01</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">123456</property>
<!--方言 必须要设置
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--在控制台展示sql语句 不必须-->
<property name="hibernate.show_sql">true</property>
<!--sql语句格式化输出-->
<property name="hibernate.format_sql">true</property>
<!--
1、update 如果映射文件和数据库表保持一致就不修改,
如果没有就自动创建表
2、create 每次执行都会重新创建一个表
3、create-drop 先将原来表删除 然后重新创建
4、validate 只做校验,不修改表
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--事务的隔离界别
1
2
4
8
脏读
幻读
不可重复读
串行化
-->
<property name="hibernate.connection.isolation">4</property>
<!--扫描映射文件
class 必须 映射文件和配置文件名字和路径保持一致
package 扫描该报下的所有配置文件
resource 指定某个确定xml配置文件
-->
<mapping resource="cn/hd/bean/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
3、HibernateAPI详解
package cn.fdw.test;
import cn.fdw.bean.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class Demo {
public static void main(String[] args) {
//1、读取配置文件
Configuration cfg = new Configuration().configure();
//2、创建sessionFactory类
/*
* 1、创建 session 、connection
* 2、创建的时候会检查数据的信息,去更新数据库的结构
* */
SessionFactory sessionFactory = cfg.buildSessionFactory();
//3、获得一个session
/*
* 1、获得事务 crud(增查改删)
* */
Session session = sessionFactory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//---------------------------------------------
User user = new User();
user.setName("大红");
user.setAge(20);
user.setSex("女");
user.setBalance(28000);
session.save(user);
//---------------------------------------------
//提交事务
transaction.commit();
//回滚·事务
// transaction.rollback();
//释放资源
session.close();
sessionFactory.close();
}
}
Crud
保存 save(里面不允许有id)
更新 update
删除 delete
查找 get
Hibernate对象的状态
(下面id为主键)
瞬时状态:一个对象既没有id也没有和session绑定的对象
持久化状态:一个对象没有id也和session绑定在一起
游离状态:有id没有和session绑定
Hibernate提供的四个crud不是增删改查的意思,而是改变对象的状态从而达到修改数据库的目的
saveOrUpdate
持久化状态的对象,随着对象的数据更该,数据库会自动更新。
Hibernate 查询
- hql
hql是hibernate的独家语言。
@Test
public void fun(){
//select * from t_user
String hql = "from User";
Query query = session.createQuery(hql);
List<User> list = query.list();
System.out.println(list);
}
//占位符查询
@Test
public void fun1(){
//select * from t_user where name = ?
//不会出现表名字和字段名,只会出现类名和类的属性名
String hql = "from User where name = ?";
Query query = session.createQuery(hql);
//设置参数的时候,下标是从0开始
query.setParameter(0,"狗子");
List<User> list = query.list();
System.out.println(list);
}
//占位符的方式有两种
//字符串的方式:+str
@Test
public void fun2(){
/*String hql = "from User where name = :name";
Query query = session.createQuery(hql);
//设置参数的时候,下标是从0开始
query.setParameter("name","狗子");
//List<User> list = query.list();
//System.out.println(list);
User user= (User) query.uniqueResult();
System.out.println(user);*/
String hql="from User where name = :name and balance< :balance";
Query query=session.createQuery(hql);
//设置参数的时候, 下标是从0 开始
query.setParameter("balance",12900);
query.setParameter("name","张三");
// List<User> list=query.list();
// System.out.println(list);
User user=(User)query.uniqueResult();
System.out.println(user);
}
@Test
public void fun3(){
String hql = "from User";
Query query = session.createQuery(hql);
//从第0条数据查找两个
query.setFirstResult(0);
query.setMaxResults(2);
List<User> list = query.list();
System.out.println(list);
}
- Criteria
or() 或者
and() 并且
equal() 等于
notEqual 不等于
like 模糊
isNull 为空
in()
gt()大于
ge() 大于等于
lt 小于
lt()小于等于
Between 在,,,,之间
- 使用session创建criteriaBuilder
使用工厂类 创建criteriaQuery
指定根元素
添加条件
将条件封装到query
把query传给session.createrQuery
得到结果集
3、sql原生态的查询方式
应用的环境
hql 推荐使用 适用于一些简单的查询
criteria 推荐使用 只适用于单表查询
sql 不推荐 非常非常复杂的查询,推荐使用sql
事务
事务的出现就是为了解决事务安全
同时对两张表进行操作,当操作完第一张表,然后出现了异常导致第二张表的数据出现了问题,这样的情况就叫做事务安全。
事务特性:
原子性 一致性 持久性
由于有了事务,就有了问题叫做事务线程安全。
- 脏读数据
张三 发货1 和李四 付钱2
2开启的事务
1 发货 事务的提交
2 事务回滚
- 不可重复读
酒店 两个柜台 A B 客户C
C找到了A柜台 2201
身份证找到了 2201房间没有了
客户D 找到了柜台B 住房2201
- 虚读(幻读)
数据库中又100条订单,读取了一次100条
另外一个事务插入进来增加了一条订单,101
有读取一次 发现前后读取的数据不一致
为了解决以上3个问题,事务隔离,隔离性 4中级别
1读未提交 哪种都不解决 (效率最高 最不安全)
2读已提交 脏读
4可重复读 脏读和不可重复读(最常用的Mysql默认的级别就是4)
8串行化 所有的问题都解决(效率最低)
Hibernate中事务的应用
事务应该在service层开启和提交或者回滚
事物的开启需要 session
获得session有两种方式:
openSession 每次打开都是一个新的线程
getCurrentSession 线程绑定的session
service层有session
dao层也有session 这两个session必须保证是同一个session
这样的事务的提交才能起作用
Hibernate框架中所有增删改 都必须提交事务才能最终修改到数据库,所以在增删改操作中必须使用getCurrentSession
使用currentSession必须再配置文件中假如属性
<property name="hibernate.current_session_context_class">thread</property>
表与表之间的关系
1对1关系 账号
1对多关系
多对多关系
Hibernate维护一对多关系
- 在实体类中加上对应的属性
职工类 加入一个 企业类型属性
企业类 假如职工的集合 set
- 在配置文件中增加以下代码
多的一方
<many-to-one name="enterprise" class="cn.hd.bean.Enterprise" column="enterpriseId"></many-to-one>
一的一方
<set name="employees">
<key column="enterpriseId"></key>
<one-to-many class="cn.hd.bean.Employee"></one-to-many>
</set>
- 在代码中维护关系时
要为两方都添加对应的属性
级联操作
cascade
delete
create
save-update
加在多的一方 在代码中就要使用多的一方维护或者一的一方维护
<many-to-one cascade="save-update" name="enterprise" class="cn.hd.bean.Enterprise" column="enterpriseId"></many-to-one>
el.setEnterprise(enterprise);
e2.setEnterprise(enterprise);
加在一的一方就要用一的一方维护
<set name="employees" cascade="save-update">
enterprise.getEmployees().add(el);
enterprise.getEmployees().add(e2);
关系的维护
inverse true 就是放弃维护关系
让一的一方放弃(字段存在多的一方)
多对多关系
<set name="teachers" table="teacher_student" inverse="true">
<key column="stuId"></key>
<many-to-many column="teaId" class="cn.hd.bean.Teacher"></many-to-many>
</set>
Hibernate查询的方式
- crud
get方法 需要主键和.class文件
- hql 比较常见(一般查询)
- criteria 适用于表单
- sql 适用于复杂查询
- 对象导航查询
分页查询
排序查询
基本条件查询
模糊查询
多表查询
- 笛卡尔积
A集合 B集合
A集合中和B集合中所有的元素,自由组合生成新的数据
- 内连接
隐式内连接
SELECT * from t_employee,t_enterprise WHERE t_employee.enterpriseId=t_enterprise.id;
显示内连接
SELECT * from t_employee t1 INNER JOIN t_enterprise t2 on t1.enterpriseId = t2.id;
- 外连接
右外连接
SELECTSELECT * from t_employee t1 RIGHT JOIN t_enterprise t2 on t1.enterpriseId = t2.id;
左外连接和右外连接没有什么太大的区别
Hibernate实现多表查询
迫切内连接
String hql = "from Enterprise e inner join fetch e.employess";
内连接
String hql = "from Enterprise e inner join e.employess";
区别就是:结果的封装一个是数组(普通),一个是对象(迫切);
检索策略
Hibernate缓存技术
Hibernate默认开启一级
二级缓存(废弃)redis
Hibernate批量抓取