# 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使用的表 ![下面是demo使用的表](https://images.gitee.com/uploads/images/2020/0106/162938_58fe9281_5496301.png "屏幕截图.png") 创建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(); ``` 结果展示 ![结果展示](https://images.gitee.com/uploads/images/2020/0106/163225_0e90050c_5496301.png "屏幕截图.png"). 这样第一个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的话,结果集会被封装成字符串集合. ![输入图片说明](https://images.gitee.com/uploads/images/2020/0107/095038_a8f1eeb4_5496301.png "屏幕截图.png") ``` Query query = entityManager.createQuery("select name from User where name like :name1"); ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/0107/095339_56dbe3fc_5496301.png "屏幕截图.png") 其他操作如下(以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; } } ``` 上述的封装方法会将结果集以数组的形式进行封装 ![](https://images.gitee.com/uploads/images/2020/0107/103311_aeb25e39_5496301.png "屏幕截图.png") 如果需要封装进入对象, ``` Query query = entityManager.createNativeQuery("select * from user where name like :na",User.class); ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/0107/103421_ad2275e2_5496301.png "屏幕截图.png") 其他需要进行事务管理的操作方法与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查询出想要的数据。 - ![输入图片说明](https://images.gitee.com/uploads/images/2020/0107/112917_3d519efa_5496301.png "屏幕截图.png") - 重要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以后): - ![输入图片说明](https://images.gitee.com/uploads/images/2020/0107/112934_85e7c883_5496301.png "屏幕截图.png") - 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; } } ```