Hibernate与MyBatis都是流行的持久层开发框架,前一遍介绍了怎样在SpringBoot中集成MyBatis,本篇来介绍如何集成Hibernate作为DAO层。
Hibernate 是一个高性能的对象/关系映射(ORM)持久化存储和查询的服务,不仅负责从Java类到数据库表的映射
(还包括从Java数据类型到SQL数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短了手动处理SQL和JDBC上的开发时间。
同时,Hibernate还实现了JPA规范,在SpringBoot中,JPA的默认实现就是使用的Hibernate。
JPA和Hibernate 在讲解如何在SpringBoot中使用Hibernate框架之前,先要弄清几个基本概念以及它们之间的关系。
JPA
Hibernate
Spring Data
Spring Data JPA
JPA JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。
上面已经描述很清楚了,JPA是一种规范和标准,也就是类似于Java中的接口,由Sun公司官方定义,但是并没有指定谁来实现。
现在几个主要的JPA实现技术有Hibernate、EclipseLink、OpenJPA等。
Hibernate Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架。
Hibernate可以自动生成SQL语句、自动执行,从而使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
实际上,JPA规范制定过程中就是借鉴了Hibernate等这些开源的持久框架,也就是说Hibernate的出现比JPA还要早些。
在Hibernate中使用的注解就是JPA注解,Hibernate实现了JPA规范。
Spring Data Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得数据库的访问变得方便快捷,
并支持map-reduce框架和云计算数据服务。此外,它还支持基于关系型数据库的数据服务,如Oracle RAC等。
所以Spring Data本身就是一个开源的框架。
Spring Data JPA 上面说过Spring Data是一个开源框架,在这个框架中Spring Data JPA只是这个框架中的一个模块。
它可以极大的简化JPA的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。
好了,现在你应该对这些概念有一个基本认识了,接下来进入正题,演示如何在SpringBoot中使用Hibernate。
maven依赖 第一步添加maven依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-jpa</artifactId > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql-connector.version}</version > <scope > runtime</scope > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > ${druid.version}</version > </dependency >
注意,使用mysql数据库来演示的话还要添加数据库驱动包,另外还添加了druid连接池。
准备数据库 如何安装mysql,配置用户名和密码之类我就不在这里讲了,请自行google。
下面是我的schema.sql文件,创建一个pos数据库,并创建一个article表,插入几条初始数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 CREATE DATABASE IF NOT EXISTS `pos` default charset utf8 COLLATE utf8_general_ci; SET FOREIGN_KEY_CHECKS= 0 ; USE `pos`; CREATE TABLE IF NOT EXISTS `articles`( `article_id` int ( 5 ) NOT NULL AUTO_INCREMENT, `title` varchar ( 200 ) NOT NULL , `category` varchar ( 100 ) NOT NULL , PRIMARY KEY ( `article_id` ) ) ENGINE= InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8 COMMENT= '文章表' ; INSERT INTO `articles` (`article_id`, `title`, `category`)VALUES (1 , 'Java Concurrency' , 'Java' ), (2 , 'Hibernate HQL ' , 'Hibernate' ), (3 , 'Spring MVC with Hibernate' , 'Spring' );
注意,Hibernate可以根据实体类自动创建表,本篇我不介绍这个功能,还是手动创建表结构。
修改配置文件 数据库创建好后,修改application.yml配置文件,新增如下数据库连接配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 spring: profiles: active: dev jpa: properties: hibernate: dialect: org.hibernate.dialect.MySQLDialect new_generator_mappings: false format_sql: true datasource: url: jdbc:mysql://127.0.0.1:3306/pos?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 username: root password: 123456
实体类 article表对应的实体类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Entity @Table(name = "articles") public class Article implements Serializable { private static final long serialVersionUID = 1L ; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "article_id") private int articleId; @Column(name = "title") private String title; @Column(name = "category") private String category; }
DAO设计 先创建一个DAO的接口类:
1 2 3 4 5 6 7 8 9 10 11 12 13 public interface IArticleDAO { List<Article> getAllArticles () ; Article getArticleById (int articleId) ; void addArticle (Article article) ; void updateArticle (Article article) ; void deleteArticle (int articleId) ; boolean articleExists (String title, String category) ; }
然后写一个实现类,在这类中注入EntityManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Repository public class ArticleDAO implements IArticleDAO { @PersistenceContext private EntityManager entityManager; @Override public Article getArticleById (int articleId) { return entityManager.find(Article.class, articleId); } @SuppressWarnings("unchecked") @Override public List<Article> getAllArticles () { String hql = "FROM Article as atcl ORDER BY atcl.articleId" ; return (List<Article>) entityManager.createQuery(hql).getResultList(); } @Override public void addArticle (Article article) { entityManager.persist(article); } @Override public void updateArticle (Article article) { Article artcl = getArticleById(article.getArticleId()); artcl.setTitle(article.getTitle()); artcl.setCategory(article.getCategory()); entityManager.flush(); } @Override public void deleteArticle (int articleId) { entityManager.remove(getArticleById(articleId)); } @Override public boolean articleExists (String title, String category) { String hql = "FROM Article as atcl WHERE atcl.title = ? and atcl.category = ?" ; int count = entityManager.createQuery(hql).setParameter(0 , title) .setParameter(1 , category).getResultList().size(); return count > 0 ; } }
业务Service 编写业务逻辑Service类,注入DAO类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Service public class ArticleService { @Resource private IArticleDAO articleDAO; public Article getArticleById (int articleId) { Article obj = articleDAO.getArticleById(articleId); return obj; } public List<Article> getAllArticles () { return articleDAO.getAllArticles(); } public synchronized boolean addArticle (Article article) { if (articleDAO.articleExists(article.getTitle(), article.getCategory())) { return false ; } else { articleDAO.addArticle(article); return true ; } } public void updateArticle (Article article) { articleDAO.updateArticle(article); } public void deleteArticle (int articleId) { articleDAO.deleteArticle(articleId); } }
编写测试用例 OK,一切写完后,就来编写我们的测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @RunWith(SpringRunner.class) @SpringBootTest public class ApplicationTests { private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class); @Resource private ArticleService articleService; @Test public void test () { Article article = articleService.getArticleById(1 ); assertThat(article.getTitle(), is("Java Concurrency" )); List<Article> list = articleService.getAllArticles(); assertThat(list, notNullValue()); assertThat(list.size(), is(3 )); boolean flag = articleService.addArticle(article); assertThat(flag, is(false )); article.setTitle("Python Concurrency" ); articleService.updateArticle(article); Article article1 = articleService.getArticleById(1 ); assertThat(article1.getTitle(), is("Python Concurrency" )); articleService.deleteArticle(1 ); Article article2 = articleService.getArticleById(1 ); assertThat(article2, nullValue()); } }
上面先查询id=1的文章,看看标题是否为Java Concurrency
,然后查询所有文章列表,之后更新文章标题后再次查询看看是否更新成功。
最后删除这篇文章,再次查询结果为null。
运行结果green bar,测试通过。
更多Hibernate相关文档,请参考 官网 。
GitHub源码 springboot-hibernate