前面关于Spring Boot的文章已经介绍了很多了,但是一直都没有涉及到数据库的操作问题,数据库操作当然也是我们在开发中无法回避的问题,那么今天我们就来看看Spring Boot给我们提供了哪些疯狂的方式来解决数据库的操作问题。

如果小伙伴想要读懂这篇博客,必须要对Spring Boot有一定了解,如果你还不太了解,可以先移步这里从Spring到Spring Boot,如果已经很了解,那么请忽略。

OK,废话不多说,让我们愉快的开启今天的数据库操作之旅吧!

什么是JPA

一说JavaWeb,很多小伙伴都知道SSH,这个H代表的就是Hibernate框架,这个小伙伴们都知道,可是什么又是JPA呢?相信许多刚入门的小伙伴听说过但不是特别清楚,首先JPA的全称叫做Java Persistence API,JPA是一个基于O/R映射的标准规范,在这个规范中,JPA只定义标准规则,不提供实现,使用者则需要按照规范中定义的方式来使用。目前JPA的主要实现有Hibernate、EclipseLink、OpenJPA等,事实上,由于Hibernate在数据访问解决技术领域的绝对霸主地位,JPA的标准基本是由Hibernate来主导的。虽然做开发的小伙伴不怎么喜欢度娘,不过度娘关于JPA的介绍个人觉得倒是比较清晰,有兴趣的小伙伴可前去了解下。JPA_百度百科。另外,Spring框架为我们提供了Spring Data JPA这样一个东东,可以减少我们使用JPA时的代码量。

使用流程

创建工程并添加相关依赖

在Spring Boot中使用JPA,我们在创建工程的时候需要选择JPA依赖,如下:



其他的步骤和我们创建一个普通的Spring Boot项目是一样的,如果小伙伴不了解如何创建一个Spring Boot项目可以参考这篇文章初识Spring Boot框架

项目创建成功之后,我这里是使用MySql做演示,因此还需要添加MySql驱动,在pom.xml文件中添加如下依赖:

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

配置基本属性

接下来需要我们在application.properties中配置数据源和jpa的基本的相关属性,如下:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpatest
spring.datasource.username=root
spring.datasource.password=123456

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true

关于这里的配置我说如下几点:

1.第一行表示驱动的名称,这个和具体的数据库驱动有关,视情况而定,我这里使用了MySql数据库,所以驱动名为com.mysql.jdbc.Driver

2.第二行表示数据库连接地址,当然也是视情况而定

3.第三四行表示数据库连接的用户名和密码

4.第五行则配置了实体类维护数据库表结构的具体行为,update表示当实体类的属性发生变化时,表结构跟着更新,这里我们也可以取值create,这个create表示启动的时候删除上一次生成的表,并根据实体类重新生成表,这个时候之前表中的数据就会被清空;还可以取值create-drop,这个表示启动时根据实体类生成表,但是当sessionFactory关闭的时候表会被删除;validate表示启动时验证实体类和数据表是否一致;none表示啥都不做。

5.第六行表示hibernate在操作的时候在控制台打印真实的sql语句

6.第七行表示格式化输出的json字符串

OK,以上就是我们在application.properties中对JPA进行的一个简单配置。

定义映射实体类

接下来,定义相应的实体类,在Project启动时,系统会根据实体类创建相应的数据表,我的实体类如下:

@Entity
@NamedQuery(name = "Person.withNameAndAddressNamedQuery",
        query = "select p from Person p where p.name=?1 and p.address=?2")
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private Integer age;
    private String address;

    public Person() {
    }

    public Person(Long id, String name, Integer age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long 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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

首先在实体类上我们使用了@Entity注解,这个表示这是一个和数据库表映射的实体类,在属性id上我们添加了@Id注解,表示该字段是一个id,@GeneratedValue注解则表示该字段自增。@NamedQuery注解表示一个NamedQuery查询,这里一个名称代表一个查询语句,我们一会可以在控制器中直接调用@NamedQuery中的withNameAndAddressNamedQuery方法,该方法代表的查询语句是select p from Person p where p.name=?1 and p.address=?2。

定义数据访问接口

OK,做好上面几个步骤之后,接下来我们就可以定义数据访问接口了,我们的数据访问接口需要继承JpaRepository类,我在数据访问接口中一共定义了四个方法,如下:

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByAddress(String name);

    Person findByNameAndAddress(String name, String address);

    @Query("select p from Person p where p.name=:name and p.address=:address")
    Person withNameAndAddressQuery(@Param("name") String name, @Param("address") String address);

    Person withNameAndAddressNamedQuery(String name, String address);

}

关于这个数据访问接口,我说如下几点:

1.当我们继承JpaRepository接口后,我们就自动具备了如下数据访问方法:

List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAll(Iterable<ID> var1);
<S extends T> List<S> save(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);

2.我们可以在接口中定义查询方法,可以按照属性名来查询,但是方法的命名方式是固定的,比如第一个方法和第二个方法,第一个方法表示根据一个属性查询,第二个方法表示根据多个属性查询,findBy、And等可以算作是这里的查询关键字了,如果写作其他名称则系统不能识别,类似的关键字还有Like、Or、Is、Equals、Between等,而这里的findBy关键字又可以被find、read、readBy、query、queryBy、get、getBy等来代替。

3.在查询的过程中我们也可以限制查询结果,这里使用的关键字是top、first等,比如查询前10条数据我们可以写作:

List<Person> findFirst10ByName(String name);

4.使用NamedQuery来查询,就是我们直接在实体类上使用@NamedQuery注解来定义查询方法和方法名,一个名称对应一个查询语句,具体可以参考我们上文的实体类

5.我们也可以向第三个方法那样添加@Query注解,当我调用这个方法的时候使用这个注解中的sql语句进行查询,方法的参数则是注解中的占位符的值。

编写测试Controller

数据访问接口都有了,接下来就是一个Controller了,我们写一个简单的Controller,用来测试一下上文中的数据访问接口是否正确,如下:

@RestController
public class DataController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/save")
    public Person save(String name,String address,Integer age) {
        Person person = personRepository.save(new Person(null, name, age, address));
        return person;
    }

    @RequestMapping("/q1")
    public List<Person> q1(String address) {
        List<Person> people = personRepository.findByAddress(address);
        return people;
    }

    @RequestMapping("/q2")
    public Person q2(String name, String address) {
        Person people = personRepository.findByNameAndAddress(name, address);
        return people;
    }

    @RequestMapping("/q3")
    public Person q3(String name, String address) {
        Person person = personRepository.withNameAndAddressQuery(name, address);
        return person;
    }

    @RequestMapping("/q4")
    public Person q4(String name, String address) {
        Person person = personRepository.withNameAndAddressNamedQuery(name, address);
        return person;
    }
    @RequestMapping("/sort")
    public List<Person> sort() {
        List<Person> people = personRepository.findAll(new Sort(Sort.Direction.ASC, "age"));
        return people;
    }
    @RequestMapping("/page")
    public Page<Person> page(int page,int size){
        Page<Person> all = personRepository.findAll(new PageRequest(page, size));
        return all;
    }
    @RequestMapping("/all")
    public List<Person> all(){
        return personRepository.findAll();
    }
}

这里的代码都很简单,我就不再一一进行解释了,值得说的是第36行代码表示根据age对查询结果进行排序然后显示出来,第40行的方法表示一个分页查询,第一个参数表示页数,从0开始计,第二个参数表示每页的数据量。最后在浏览器中分别测试这几个接口就可以了,我这里就不再展示测试页面了,小伙伴们自行测试。

本文源码下载:

本文GitHub地址

更多关于Spring Boot资料请移步这里

参考资料:

《JavaEE开发的颠覆者 Spring Boot实战》第八章

初识在Spring Boot中使用JPA的更多相关文章

  1. 使用spring boot中的JPA操作数据库

    前言 Spring boot中的JPA 使用的同学都会感觉到他的强大,简直就是神器一般,通俗的说,根本不需要你写sql,这就帮你节省了很多时间,那么下面我们来一起来体验下这款神器吧. 一.在pom中添 ...

  2. Spring Boot 中使用 jpa

    本文原文版权归 CSDN Hgihness 所有,此处为转载+技术收藏,如有再转请自觉于篇头处标明原文作者及出处,这是大家对作者劳动成果的自觉尊重!! 作者:Hgihness 原文:http://bl ...

  3. Spring Boot中使用Jpa的findOne方法不能传入id

    最近通过慕课网学习spring boot,视频中通过jpa的findOne方法以id为参数查询出对应的信息, 而当我自己做测试的时候却发现我的findOne方法的参数没有Integer类型的id,而是 ...

  4. spring boot 中使用 jpa以及jpa介绍

    1.什么是jpa呢?JPA顾名思义就是Java Persistence API的意思,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中.12.jpa具有什么 ...

  5. spring boot中注入jpa时报could not autowire.No beans of 'PersonRepository' type found

    解决方法,在repository加一个注解.如下图所示: @Component

  6. Spring boot中应用jpa jpa用法

    https://blog.csdn.net/u012582402/article/details/78717705

  7. 在Spring Boot中使用数据缓存

    春节就要到了,在回家之前要赶快把今年欠下的技术债还清.so,今天继续.Spring Boot前面已经预热了n篇博客了,今天我们来继续看如何在Spring Boot中解决数据缓存问题.本篇博客是以初识在 ...

  8. 在Spring Boot中使用数据库事务

    我们在前面已经分别介绍了如何在Spring Boot中使用JPA(初识在Spring Boot中使用JPA)以及如何在Spring Boot中输出REST资源(在Spring Boot中输出REST资 ...

  9. 在Spring Boot中输出REST资源

    前面我们我们已经看了Spring Boot中的很多知识点了,也见识到Spring Boot带给我们的各种便利了,今天我们来看看针对在Spring Boot中输出REST资源这一需求,Spring Bo ...

随机推荐

  1. css水平垂直居中的方法与 vertical-align 的用法

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 1. 已知元素宽度 方法一:已知宽高,可以用position定位 + margin负值的方法 : 绝对定位 ...

  2. JS事件练习题

    1.点击按钮连续弹窗5次 <div class="noe"> <div class="noe1" onClick="n()" ...

  3. Git的本地仓库与GitHub的远程仓库

    gitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名gitHub.GitHub 是目前为止最大的开源 Git 托管服务,并且还是少数同时提供公共代码 ...

  4. 关于python 使用腾讯云OCR 通用印刷体识别

    腾讯的python SDK没有通用印刷体识别,所以参考了别人识别网上图片的方式:https://www.cnblogs.com/semishigure/p/7690789.html 但是咱们使用的基本 ...

  5. 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting(树链剖分)

    题解:仍然是无脑树剖,要注意一下边权,然而这种没有初始边权的题目其实和点权也没什么区别了 代码如下: #include<cstdio> #include<vector> #in ...

  6. [ZJOI 2006]书架

    Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下 ...

  7. [HNOI2004]L语言

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  8. codevs3990:中国剩余定理2

    好久没做codevs啦 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cst ...

  9. Python3 中 random模块

    Python中的random模块用于生成随机数. 下面具体介绍random模块的功能: 1.random.random() #用于生成一个0到1的 随机浮点数:0<= n < 1.0 im ...

  10. udacity/CarND-Path-Planning-Project 工程详细配置过程——吐血整理

    本人原创,转载请注明地址 学习udacity/CarND-Path-Planning-Project 工程过程 1.首先登陆 jeremy-shannon/CarND-Path-Planning-Pr ...