hibernate学习
运行环境
新建mavenProject工程,引入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hibernate.version>5.4.3.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
新建实体类,和实体类的配置文件
新建实体类
@NoArgsConstructor
@Data
public class User {
private Integer id;
private String name;
private int age;
private String address;
}
新建实体类的配置文件
<hibernate-mapping>
<class name="lamose.entity.User" table="t_user">
<!-- 配置实体类和表名称对应 -->
<!-- name为实体类中的属性名,column为表的字段名 -->
<id name="id" column="id">
<!-- 自动增长策略 -->
<generator class="native"></generator>
</id>
<!-- 生成其他列 -->
<property name="name" column="name"></property>
<property name="age" column="age"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
创建hibernate核心配置文件
<hibernate-configuration>
<session-factory>
<!-- 必选 配置数据库信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/coulddb02</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- 配置hibernate -->
<!-- 打印Sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 输出语句的格式 -->
<property name="hibernate.format_sql">true</property>
<!-- 创建表 -->
<!-- update:如果表存在,即更新,如果不存在,则创建 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 数据库方言,例如limit是mySql方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 把映射文件放到核心配置文件中 -->
<mapping resource="User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
操作步骤
- 加载核心配置文件
- 创建SessionFactory对象
- 使用SessionFactory创建Session对象
- 开启事务
- CRUD
- 提交事务
- 关闭资源
其中123467为固定操作,第五步写具体的数据库操作
public void testAdd() {
// 1、加载核心配置文件
Configuration cfg = new Configuration();
cfg.configure();
// 2、创建SessionFactory对象
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 3、使用SessionFactory创建Session对象
Session session = sessionFactory.openSession();
// 4、开启事务
Transaction tx = session.beginTransaction();
// 5、CRUD
User user = new User();
user.setName("lamose").setAge(22).setAddress("China");
session.save(user);
// 6、提交事务
tx.commit();
// 7、关闭资源
session.close();
sessionFactory.close();
}
Hibernate核心API
Configuration
Configuration cfg = new Configuration();
cfg.configure();
//Configuration cfg = new Configuration().configure("自定义核心配置文件路径");
到根目录下面找到名称为hibernate.cfg.xml文件,创建对象,把配置文件放到对象中(加载核心配置文件)
SessionFactory
使用Configuration对象创建SessionFactory对象
- 创建SessionFactory过程中:
– 更具核心配置文件中,有数据库配置,有映射文件配置部分,到数据库中根据映射关系完成数据库表的创建
<property name="hibernate.hbm2ddl.auto">update</property>
- 在创建SessionFactory过程中,每一次hibernate操作,都会创建或者更新表,这非常消耗资源,解决方法:
public class HibernateUtil {
static Configuration cfg = null;
static SessionFactory sessionFactory = null;
static {
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
public void testAdd() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setName("lamose").setAge(22).setAddress("China");
session.save(user);
tx.commit();
session.close();
sessionFactory.close();
}
Session
1、session类似于jdbc中的connection对象
2、调用session对象中的方法进行CRUD操作
添加: save方法
修改: update方法
删除: delete方法
根据id查询: get方法
3、session对象是单线程对象
session对象不能被共用,只能自己使用
Transaction
1、事务对象
Transaction tx = session.beginTransaction();
2、事务操作,提交和回滚
tx.commit();
tx.rollback();
Hibernate操作数据库
Hibernate主键生成策略
1、native :主键自增长,更具数据库自动匹配
2、uuid: 使用UUID作为主键
3、increment:用于long、short或int,自增长,每次增量为1
4、identity: 采用数据库本身提供的主键自增策略,不能用于oracle数据库
5、sequence:序列增长,只能用到oracle数据库中
CRUD
save增加方法
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setName("lamose").setAge(22).setAddress("China");
session.save(user);
tx.commit();
session.close();
sessionFactory.close();
get查询方法
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 3);
System.out.println(user);
tx.commit();
session.close();
sessionFactory.close();
update修改方法
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 3);
user.setName("Tory").setAge(22).setAddress("DDY");
session.update(user);
tx.commit();
session.close();
sessionFactory.close();
delete删除方法
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 3);
session.delete(user);
tx.commit();
session.close();
sessionFactory.close();
实体类的三种状态
1、瞬时态:对象中没有id值,对象与session没有关系,多为save操作
User user = new User();
user.setName("lamose").setAge(22).setAddress("China");
2、持久态:对象有id值,对象与session有关联,多为get
User user = session.get(User.class, 3);
3、托管态:对象里有id值,对象与session没有关系
User user = new User();
user.setId(3);
session.delete(user);
Hibernate缓存
什么是缓存
1、数据存到数据库中,数据库本身就是文件系统。
2、用流方式操作文件效率很低
3、把数据存放到内存中,不使用流方式,可以直接读取内存数据
4、从内存中读取数据,效率高
Hibernate一级缓存
1、hibernate默认开启一级缓存
2、hibernate的一级缓存使用范围是session,从session创建到session关闭
3、hibernate的一级缓存中,存储数据必须是持久态数据
Hibernate二级缓存
1、默认关闭
2、目前已经不使用了,由redis来替代
3、使用范围为SessionFactory范围
Hibernate一级缓存执行过程
hibernate一级缓存特性
持久态会自动更新数据库
public void testGet() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 4);
System.out.println(user);
user.setAge(22).setName("LLL").setAddress("as");
User user2 = session.get(User.class, 4);
System.out.println(user2);
tx.commit();
session.close();
sessionFactory.close();
}
Hibernate事务操作
推荐使用异常捕获结构来写事务
public void guTransaction() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory=HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
// CRUD操作
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
sessionFactory.close();
}
}
Hibernate绑定
1、在hibernat.cfg.xml中配置本地线程绑定session
<!-- 配置本地线程绑定session -->
<property name="hibernate.current_session_context_class">thread</property>
2、在HibernateUtils中提供返回本地线程对象的session方法
public static Session getSessionObject() {
return sessionFactory.getCurrentSession();
}
3、调用方法,利用本地线程绑定的session后,不需要手动关闭
public void testTx() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSessionObject();
tx = session.beginTransaction();
//CRUD
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
}
}
hibernate其他API
query对象
Query createQuery = session.createQuery("from User");
List<User> list = createQuery.list();
for (User user : list) {
System.out.println(user);
}
criteria对象
Criteria createCriteria = session.createCriteria(User.class);
List<User> list = createCriteria.list();
for (User user : list) {
System.out.println(user);
}
sqlquery对象
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
List<Object[]> list = sqlQuery.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
Hibernate表关系
一对多
Set标签:
name属性:本实体中,对方实体的名称
table属性:数据库表
cascade属性: save-update 级联保存更新,delete 级联删除
inverse属性:双向维护,默认false不放弃双向维护,建议设置为true
Key标签:
column属性:外键名称
one-to-many标签:
class属性:实体的全路径名
column属性:外键名称
一对多映射配置
一:
多:
创建核心配置文件,把一对多关系配置到核心配置文件中
<mapping resource="第一个hbm.xml路径"/>
<mapping resource="第二个hbm.xml路径"/>
一对多级联操作
级联保存
1、在一的一方的Set标签中,配置cascade=“save-update”
2、在一的一方创建两个对应对象
3、将多的对象放到一的里面
4、最终只需要保存一的一方,就可以实现级联保存
public void testAdd() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
User user1 = new User();
User user2 = new User();
User user3 = new User();
user1.setName("lamose1").setAge(11).setAddress("USA1");
user2.setName("lamose2").setAge(12).setAddress("USA2");
user3.setName("lamose3").setAge(13).setAddress("USA3");
Dept dept = new Dept();
dept.setDname("开发部门");
dept.getUserList().add(user1);
dept.getUserList().add(user2);
dept.getUserList().add(user3);
session.save(dept);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
dept.hbm.xml文件内容
<hibernate-mapping>
<class name="lamose.entity.Dept" table="t_dept">
<id name="deptno" column="deptno">
<generator class="native"></generator>
</id>
<property name="dname" column="dname"></property>
<set name="userList" cascade="save-update,delete" >
<key column="did"></key>
<one-to-many class="lamose.entity.User" />
</set>
</class>
</hibernate-mapping>
user.hbm.xml文件内容
<hibernate-mapping>
<class name="lamose.entity.User" table="t_user">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<property name="age" column="age"></property>
<property name="address" column="address"></property>
<many-to-one name="dept" class="lamose.entity.Dept" column="did"></many-to-one>
</class>
</hibernate-mapping>
hibernate.cfg.xml文件内容
<mapping resource="User.hbm.xml"/>
<mapping resource="Dept.hbm.xml"/>
级联删除
1、在一的一方的Set标签中,配置cascade=“save-update,delete”
2、根据id查询一的一方的对象
3、删除一的一方的对象
inverse属性
在更新外键时,根据hibernate会双向维护外键的特性,会出现多次更新外键,这个操作我们不需要,可以在一的一方的Set标签上添加inverse属性
inverse默认为false:表示不放弃维护,改为true即可
多对多
多对多映射配置
1、在实体类中,添加Set集合,创建对方的对象
2、两个hbm.xml都是用Set标签配置
3、生成两个实体类的Get和Set方法
Hibernate查询方式
对象导航查询
根据ID查询某条数据,根据里面的外键,查询其关联数据
需求:查询部门编号为2的所有员工
public static void main(String[] args) {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Dept dept = session.get(Dept.class, 2);
System.out.println(dept.getUserList().size());
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
OID查询
根据ID查询某一条查询
Dept dept = session.get(Dept.class, 2);
HQL查询
根据Query对象来查询
1、创建Query对象session.createQuery(“from User”);
2、调用Query对象的list方法,返回一个List对象
session.createQuery(String arg0); arg0为from 实体名
条件查询
1、创建Query对象session.createQuery(" ");
2、使用占位符来添加条件
3、调用setParameter方法
----- query.setParameter(int position, Object val);
需求:查询出name为lamose1,且age大于10的user
public void testSelect2() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from User u where u.name = ? and u.age > ? ");
query.setParameter(0 , "lamose1");
query.setParameter(1, 10);
List list = query.list();
System.out.println(list.size());
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
排序查询
普通sql实现
SELECT * FROM T_USER ORDER BY ID [DESC]
HQL排序查询
Query query = session.createQuery("from User u order by id desc");
分页查询
普通sql实现
SELECT * FROM T_USER LIMIT 0,5 ;
HQL分页查询
setFirstResult:开始位置
setMaxResults:显示数
public void testSelectLimit() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("from User");
//开始位置
query.setFirstResult(0);
//每页记录数
query.setMaxResults(3);
List list = query.list();
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
HQL投影查询
查询固定字段的值
public void testSelect3() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Query query = session.createQuery("select name from User");
List<Object> list = query.list();
for (Object object : list) {
System.out.println(object.toString());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
聚合函数
普通sql
聚合函数:count, max, avg, min , sum ,
SELECT 聚合函数 FROM 表名
HQL聚合函数的使用
SELECT 聚合函数 FROM 实体名
//返回一个Object对象
Object obj = query.uniqueResult();
//统计个数时,object不能直接转成int类型,先转换为Long类型
QBC查询
根据criteria对象来查询
调用criteria对象的方法
QBC查询全部
criteria的list()方法
public void testSelect3() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
System.out.println(list.size());
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
QBC条件查询
使用Criteria对象里面的方法设置条件
1、使用add方法,表示设置条件值
2、在add方法里面,使用Restrictions类实现条件设置
public void testSelect4() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "lamose1"));
criteria.add(Restrictions.eq("address", "USA1"));
List list = criteria.list();
System.out.println(list.size());
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
sessionFactory.close();
}
}
QBC排序和分页
criteria.addOrder(Order.desc(" 实体属性名")); //降序
criteria.addOrder(Order.asc(" 实体属性名")); //升序
criteria.setFirstResult( int arg0); //开始位置
criteria.setMaxResults( int arg0); //每页记录数
QBC统计和离线查询
统计查询
1、创建Criteria对象
2、设置操作:criteria.setProjection(Projections.rowCount);
3、得到结果: Object obj = criteria.uniqueResult();
离线查询
1、不需要通过Session对象来创建
2、DetachedCriteria detachedCriteria = DetachedCriteria .forClass(User.class);
3、执行时使用Session对象:Criteria criteria = detachedCriteria.getExecutableCriteria(session);
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List list = criteria.list();
System.out.println(list.size());
HQL多表查询
内连接(返回list部分是 数组)
1、创建Query对象
Query query = session.createQuery("from Dept u inner join u.userList ");
List list = query.list();
System.out.println(list.size());
迫切内连接(返回list部分是 对象)
Query query = session.createQuery("from Dept u inner join fetch u.userList ");
List list = query.list();
System.out.println(list.size());
左(右)外连接
Query query = session.createQuery("from Dept u left(right) outer join u.userList ");
List list = query.list();
System.out.println(list.size());
左外迫切连接
没有右外迫切连接
Query query = session.createQuery("from Dept u left outer join fetch u.userList ");
List list = query.list();
System.out.println(list.size());
Hibernate检索策略
立即查询
根据id查询,调用get方法,一调用get方法,立即发送语句到数据库
延迟查询
根据id查询,还有load方法,不会马上发送语句到数据库,只有得到对象里面的值(调用get方法,调用getId除外)时,才会发送到数据库
User user = session.load(User.class, 7);
//不会向数据库发送语句
user.getId();
//回向数据发送语句
user.getName();
类级别延迟
例如上方操作一个User类,就是类级别延迟
关联级别延迟
默认:获取通过关联外键的实体时,不调用关联实体的方法时,不会发送语句
修改:
在Set标签上使用属性
1、fetch:默认值为select
2、lazy:默认值true,延迟是否开
- true开启
- false不开启,效率低
- extra及其懒惰,效率更高,要什么就发什么
批量抓取
在需要通过关联关系多次查询数据库时,可以使用批量抓取来提高效率,减少语句的发送
在Set标签中配置,batch-size=" "
batch-size的属性值为数字,数字越大,性能越高