欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解在Spring Boot中使用JPA

程序员文章站 2024-02-22 20:06:04
前面关于spring boot的文章已经介绍了很多了,但是一直都没有涉及到数据库的操作问题,数据库操作当然也是我们在开发中无法回避的问题,那么今天我们就来看看spring...

前面关于spring boot的文章已经介绍了很多了,但是一直都没有涉及到数据库的操作问题,数据库操作当然也是我们在开发中无法回避的问题,那么今天我们就来看看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的介绍个人觉得倒是比较清晰,有兴趣的小伙伴可前去了解下。另外,spring框架为我们提供了spring data jpa这样一个东东,可以减少我们使用jpa时的代码量。

使用流程

创建工程并添加相关依赖

在spring boot中使用jpa,我们在创建工程的时候需要选择jpa依赖,如下:

详解在Spring Boot中使用JPA

其他的步骤和我们创建一个普通的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地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。