# Springboot-Hibernate
**Repository Path**: luzhizero/Springboot-Hibernate
## Basic Information
- **Project Name**: Springboot-Hibernate
- **Description**: 为准备老项目重构,整理了Heibernate的相关资料以备后续,基于Springboot下JPA的Hibernate整合,包括sql,hql,Criteria,一对多一对一映射查询.
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2020-01-06
- **Last Updated**: 2023-02-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Springboot-Hibernate
#### 介绍
为准备老项目重构,整理了Heibernate的相关资料以备后续,基于Springboot下的Hibernate整合,包括sql,hql,Criteria,一对多一对一映射查询.本次对应数据库为mysql.
基于springboot下整合Heibernate
spring框架中提供Spring Data JPA作为开发者应用Hibernate框架的接口工具。我们的Spring Boot则提供了一款全自动的“自动依赖模块”:spring-boot-starter-data-jpa
创建springboot项目后引入pom
```
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
com.alibaba
druid-spring-boot-starter
1.1.10
```
在配置文件中配置数据源,连接池以及方言.
```
server.port=8091
#mysql
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
#连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager
#spring.jpa.properties.hibernate.dialect为Hibernate的数据库方言。
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
```
下面是demo使用的表

创建model层实体类
```
@Entity
@Table(name = "user")//数据库的表名
public class User implements Serializable {
/**
* 必须加ID、GeneratedValue 否则报错
*/
@Id
@GeneratedValue
private Integer id;
private String name;
private Integer age;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
```
创建dao层继承JpaRepository
```
@Repository
public interface HibernateHqlDao extends JpaRepository {
}
```
后面就直接在业务层和控制层进行注入.
通过在业务层调用findAll()提供的方法进行所有数据的查询
```
hibernateHqlDao.findAll();
```
结果展示
.
这样第一个HibernateDemo就正式完成.
在JpaRepository内置的Api无法满足某些特殊需求的查询时,可以通过自行书写HQL在注解上添加来执行sql.(如果需要进行事务操作,则需要在方法上添加@Transactional注解.)
```
@Repository
public interface HibernateHqlDao extends JpaRepository {
@Query("FROM User WHERE name LIKE %:name%")
List selectLike(String name);
}
```
关于Hql
HQL查询语句中只能出现类名和属性名,不能出现表名和字段名,不能出现*
HQL查询语句中出现的类名,必须是进行了对象关系映射的类,没有映射的类不能出现在HQL语句中
HQL查询语句中如果要使用别名,必须使用as关键字,不能省略
HQL语法结构:
select
属性列表、聚合函数、投影查询
from 类名
Inner join 类 on 连接条件
where 条件
group by 属性名称 having 条件
order by 属性名称 desc/asc
查询语句示例:
查询所有数据:
查询学生表的所有学生对象:from Student (不能写成select * from Student)
投影查询(查询表的一部分字段或者聚合函数):
查询学生表中的学生姓名属性:select name from Student(当查询的是单个属性时,查询的集合中保存的就是该属性值)
查询学生表中的学生姓名和年龄:select name,age from Student (当查询的是多个属性时,查询的集合中保存的是Object数组,一个数组表示一行数据)
查询学生表中的学生姓名和年龄并封装为学生类对象:select new Student(name,age)from Student
(学生类中需要提供对应的带参构造函数)。
where子句:别名需要加as
where子句可以对数据进行筛选,查询出满足条件的数据,具体的条件判断方式和SQL类似。
>、<、>=、<=、=、<>、is null、 is not null、 in、 between and、like
group by having子句:
分组子句用法和SQL一致
order by子句:
排序子句用法和SQL一致
实现类中使用Hibernate
在正常的Hibernate中,通过Hibernate中的SessionFactory来创建session,利用Session来进行增删改查的操作.
而通过Jpa整合后Session的功能被Jpa自带的EntityManager进行了封装,使用方法如下.
```
@Repository
public class HibernateHqlDaoImpl implements MyHibernateHqlDao {
//通过注入将EntityManager注入到数据层
@Resource
private EntityManager entityManager;
@Override
public List selectCondition(String name, Integer pageIndex, Integer pageCount) {
Query query = entityManager.createQuery("select new User(name) from User where name like :name1",User.class);
query.setParameter("name1","%"+name+"%");
query.setFirstResult((pageIndex-1)*pageCount+1);
query.setMaxResults(pageCount);
List list = query.getResultList();
return list;
}
}
```
上述方法会直接将结果集封装进入User的集合,关键代码new User(name),这里必须提供相应的构造函数,如果直接name的话,结果集会被封装成字符串集合.

```
Query query = entityManager.createQuery("select name from User where name like :name1");
```

其他操作如下(以update操作为例)
```
//如果执行新增等需要事务管理的操作,需要 @Transactional注解打开事务管理
@Transactional
@Override
public boolean updateUser(User user) {
Query query = entityManager.createQuery("update User set name = :name,age = :age,email = :email where id = :id");
query
.setParameter("name",user.getName())
.setParameter("age",user.getAge())
.setParameter("email",user.getEmail())
.setParameter("id",user.getId());
int i = query.executeUpdate();
if(i<=0){
return false;
}
return true;
}
```
关于Sql
sql就是自行书写sql语句进行操作,该sql不会被方言进行处理.
HQL调用方法为createQuery,sql调用方法为createNativeQuery.
```
@Repository
public class MyHibernateSqlDaoImpl implements MyHibernateSqlDao {
@Resource
private EntityManager entityManager;
@Override
public List selectCondition(String name,Integer pageIndex ,Integer pageCount) {
Query query = entityManager.createNativeQuery("select * from user where name like :na");
query.setParameter("na","%"+name+"%");
query.setFirstResult((pageIndex-1)*pageCount+1);
query.setMaxResults(pageCount);
List resultList = query.getResultList();
return resultList;
}
}
```
上述的封装方法会将结果集以数组的形式进行封装

如果需要封装进入对象,
```
Query query = entityManager.createNativeQuery("select * from user where name like :na",User.class);
```

其他需要进行事务管理的操作方法与hql类似.
```
@Transactional
@Override
public boolean updateUser(User user) {
Query query = entityManager.createNativeQuery("update user set name = :name,age = :age,email = :email where id = :id");
query
.setParameter("name",user.getName())
.setParameter("age",user.getAge())
.setParameter("email",user.getEmail())
.setParameter("id",user.getId());
int i = query.executeUpdate();
if(i<=0){
return false;
}
return true;
}
```
关于属性注入
属性注入有两种方式
1.通过 :参数名称 的方式进行传递,注入通过 query.setParameter("参数名称",对应值)进行注入,参数名称须保持相同.
2.通过 ? 的方式进行传递,注入通过 query.setParameter("参数位置",对应值)进行注入,例如query.setParameter(1,user.getId());(注最新的hibernate需要将位置标记在?后面,例如 ?1)
关于hibernate缓存
当hibernate通过查询的方式创建了一个对象后,在hibernate生命周期内,该对象会作为数据缓存进行保存,如果对该缓存对象进行修改,可以通过flush()方法,将缓存对象的数据同步到数据库中.(因为这里通过了springjpa整合,所以详细情况后续会在jpa那一篇进行补充.)
Criteria查询
- Criteria是Hibernate提出的纯粹的面向对象的查询方式,在使用Criteria查询数据时,不需要书写任何一个SQL语句或者HQL语句,即时是一个完全不懂SQL的人,也完全可以使用Criteria所提供的的各种API来设置查询条件、分页、排序、联合查询等等,也依然可以使用Criteria查询出想要的数据。
- 
- 重要API(5.2以前):
- Criteria(5.2版本以前):标准查询接口,通过该接口来执行查询、添加条件等等。
- Criterion:Criterion是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion) 方法来
- 添加查询条件。
- Restrictions :Restrictions 类中提供了大量的静态方法用于产生Criterion条件对象
- Projection:Projection用来描述一个投影查询项,一个Projection对象就是一个投影查询项
- ProjectionList:ProjectionList是投影查询集合,用来描述多个投影查询项,可以使用add方法添加投影查询项
- Projections:Projections类中提供了大量的静态方法用于产生Projection投影查询项
- Order:描述排序方式
- 使用过程(5.2以前):
- 创建Criteria对象:
- Criteria cri=session.createCriteria(Student.class);
- 参数:表示需要查询表对应的的实体类
- 设置查询条件:(可选)
- 使用Restrictions的静态方法可以快速生成查询条件对象Criterion
- Restrictions.eq :equal,等于.
- Restrictions.gt :great-than > 大于
- Restrictions.ge : great-equal >= 大于等于
- Restrictions.lt :less-than, < 小于
- Restrictions.le : less-equal <= 小于等于
- Restrictions.between: 对应SQL的between子句
- Restrictions.like : 对应SQL的LIKE子句
- Restrictions.in :对应SQL的in子句
- Restrictions.isNull : 判断属性是否为空,为空则返回true
- Restrictions.and :and 关系
- Restrictions.or :or 关系
- 查询条件对象定义好之后需要将查询条件添加到Criteria对象中
- criteria.add(查询条件对象)
- 设置投影查询项:(可选)
- 创建投影查询项:
- Projections.property("属性名"):创建一个投影查询项为一个属性的Projection对象
- Projections.avg(String propertyName):求平均值的投影查询对象
- Projections.count(String propertyName):求属性出现次数总和的投影查询对象
- Projections.max(String propertyName):求属性最大值的投影查询对象
- Projections.min(String propertyName):求最小值的投影查询对象
- Projections.sum(String propertyName):求和的投影查询对象
- Projections.聚合函数(String propertyName,”别名”):当我们要使用聚合函数的结果来排序时,可以给聚合函数的投影结果定义别名,最后通过该别名来实现排序
- Projections.聚合函数(String propertyName).as(”别名”):当我们要使用聚合函数的结果来排序时,可以给聚合函数的投影结果定义别名,最后通过该别名来实现排序
- Projections.projectionList():创建一个投影查询对象集合,一个集合可以保存多个投影查询项对象
- projectionList.add(Projection对象):将投影查询对象添加到投影查询集合中
- projectionList.add(Projection对象,字符串):将投影查询对象添加到查询集合中,并为其添加别名
- Projections.groupProperty(String propertyName):分组
- criteria.setProjection(Projection对象):将投影查询项设置Criteria中
- 设置排序方式:(可选)
- criteria.addOrder(Order.asc(“属性名或者别名”)):升序
- criteria.addOrder(Order.desc(“属性名或者别名”)):降序
- 设置分页:(可选)
- criteria.setFirstResult(); 设置起始位置从0开始
- criteria.setMaxResult(); 设置查询总行数
- 执行查询:
- criteria.list();
- criteria.uniqueResult();
- 重要API(5.2以后):
- 
- CriteriaQuery:查询接口,用于添加查询条件,分组,排序,投影查询
- CriteriaBuilder:创建查询接口的建造者类,用于创建CriteriaQuery对象、查询条件对象、投影查询表达式对象。
- Root:根据属性名称获取字段名称,字段名称可以用于查询条件和投影查询中
- Predicate:条件对象
- Expression:表达式对象,用于表达投影查询的字段,条件中的字段名称
```
@Override
public List criCondition(String name, Integer pageIndex, Integer pageCount) {
Criteria criteria = entityManager.createCriteria(User.class);
SimpleExpression name1 = Restrictions.like("name", "%" + name + "%");
Criterion email = Restrictions.in("email", new Object[]{"test20@baomidou.com", "test19@baomidou.com"});
LogicalExpression and = Restrictions.and(email, name1);
criteria.add(and);
PropertyProjection name2 = Projections.property("name");
PropertyProjection email1 = Projections.property("email");
criteria.setProjection(name2).setProjection(email1);
criteria.setFirstResult((pageIndex-1)*pageCount+1);
criteria.setMaxResults(pageCount);
List list = criteria.list();
return list;
}
```
- 使用过程(5.2以后):
- 创建查询对象
- CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
- CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Class c);
- Root root=criteriaQuery .from(Class c);
- 注意:在创建查询接口CriteriaQuery时,可以指定最终查询出的数据类型,定义好之后后续查询出的数据不需要在进行强转。
- 设置查询条件(可选):
- 创建查询条件:
- criteriaBuilder.equals(root.get(“字段名”),值);
- criteriaBuilder.and();
- criteriaBuilder.or();
- 添加查询条件
- criteriaQuery.where();
- 设置投影查询(可选):
- 创建投影查询项:
- 创建字段投影查询项:
- root.get(“字段名称”)
- 创建聚合函数投影查询项
- criteriaBuilder.avg(root.get("age"));
- 添加投影查询项:
- criteriaQuery.select(投影查询项对象);
- criteriaQuery.multiselect(投影查询项对象1,投影查询项对象2...);
- 设置分组(可选):
- criteriaQuery.groupBy(root.get(""));
- 设置排序(可选):
- 创建排序对象:
- 根据字段升序:
- criteriaBuilder.asc(root.get(""));
- 根据聚合函数升序:
- criteriaBuilder.asc(criteriaBuilder.avg(root.get("")));
-
- 根据字段降序:
- criteriaBuilder.desc(root.get(""));
- 根据聚合函数降序:
- criteriaBuilder.desc(criteriaBuilder.avg(root.get("")));
- 添加排序:
- criteriaQuery.orderBy()
- 封装Query对象:
- Query query=session.createQuery(criteriaQuery);
- 分页查询(可选):
- query.setFirstResult(); 设置起始位置从0开始
- query.setMaxResult(); 设置查询总行数
- 执行查询:
- query.getResultList();
- query.getSingleResult();
- 同样的,投影查询的单个结果以Object封装,多个结果用Object数组封装
-
```
@Repository
public class OldcriteriaDaoImpl implements OldcriteriaDao {
@Resource
private EntityManager entityManager;
@Override
public List criCondition(String name, Integer pageIndex, Integer pageCount) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(User.class);
//创建查询条件
Root userRoot = criteriaQuery .from(User.class);
Predicate name1 = criteriaBuilder.like(userRoot.get("name"), "%" + name + "%");
//in查询
Predicate email = criteriaBuilder.in(userRoot.get("email").in(new Object[]{"test20@baomidou.com","test19@baomidou.com"}));
//多条件拼接
criteriaBuilder.and(name1,email);
//将条件对象封装进入查询对象
Query query=entityManager.createQuery(criteriaQuery);
query.setFirstResult((pageIndex-1)*pageCount+1);
query.setMaxResults(pageCount);
List resultList = query.getResultList();
return resultList;
}
}
```