JavaRush /Java 博客 /Random-ZH /Spring并不可怕,还是如何问数据库问题
Павел
第 11 级

Spring并不可怕,还是如何问数据库问题

已在 Random-ZH 群组中发布
文章周期的内容 今天,作为我们项目的一部分,我们正在完成数据库的工作。如果你做的一切正确,那么你应该有一个具有以下依赖项的 pom:
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <java.version>1.8</java.version>
</properties>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.0.RELEASE</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
这就是该项目的结构: Spring并不可怕,还是如何问数据库问题 - 1 你知道我们已经很久没有记住谁了吗?这是application.yml,我们在之前的一篇文章中没有过多谈论它。现在让我们继续删除它!是的,是的,删除就是这样!如果我们现在启动该项目,一切都会像以前一样工作,试试这个。发生这种情况是因为 Spring 本身配置了默认设置。现在我们需要将 yml 文件返回到 resources 文件夹,我们仍然需要它:application.yml(名称应该相同)
spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:test;
    username: sa
    password:
    h2:
      console:
        enabled: true
  jpa:
    hibernate.ddl-auto: create
    generate-ddl: true
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
上次,我们使用 JpaRepository<> 接口的方法实现了对数据库的多个查询:
//сохранить одну запись в таблицу фруктов
public void save(FruitEntity fruitEntity){
    fruitRepository.save(fruitEntity);
}
//получить все записи из таблицы фруктов
public List<FruitEntity> getAll(){
   return fruitRepository.findAll();
}
//сохранить несколько записей в таблицу фруктов
public void saveAll(List<FruitEntity> fruits){
    fruitRepository.saveAll(fruits);
}
如果您像我上次要求您那样阅读有关SQL 的内容,那么您应该知道此类数据库操作必须使用 SQL 查询来执行。但项目中没有任何暗示;即使在控制台日志中也没有类似的内容。让我们找到它们,打开 application.yml,找到 show-sql: 行(show sql)并将 false 更改为 true。我们启动项目,看一下控制台,日志中充满了与SQL非常相似的新条目,其实大部分都不难理解,例如:
Hibernate: drop table fruit_table if exists //удалить таблицу fruit_table  если она есть
Hibernate: drop table provider_table if exists
Hibernate: create table fruit_table (id_fruit integer not null, fruit_name varchar(255), provider_code integer, primary key (id_fruit))//создать таблицу fruit_table с полями id_fruit тип integer not null, fruit_name  тип varchar(255), provider_code тип integer, назначить первичным ключем поле id_fruit
Hibernate: create table provider_table (id_provider integer not null, provider_name varchar(255), primary key (id_provider))
但这个条目可能会因为它的问号而引起很多疑问:
Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?)
让我们逻辑思考一下:首先,我们看到Hibernate这个词,这意味着这个神秘的家伙把他毛茸茸的爪子放在这里了。在网上了解了他的相关信息后,我们了解到Hiber先生 是 ORM 模型的实现。对象关系模型描述了软件对象和数据库中的记录之间的关系。固定了这个想法,我们继续逻辑思考:一方面,我们有一个FruitEntity对象,它有三个字段:Integer id;字符串水果名称;整数提供商代码。 另一方面,我们在数据库Fruit_table中有一个表,其中字段id_fruit类型为整数 fruit_name 类型为varchar(255)provider_code类型为整数。 粗略地说,Hibernate 获取一个FruitEntity对象,提取该对象字段的值并将它们写入相应的表字段。我有一个问题想问你:你看,在InitiateUtils类中我们实现了填充水果表,但由于某种原因我们只将值设置为两个字段,第三个字段在哪里?
new FruitEntity()
        .setFruitName("Fruit1")//раз
        .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два
                                            //три???
我相信您会自己弄清楚这一点,此外,我们在上一篇文章中简要讨论了这个问题。首先弄清楚哪个字段不在这里,然后你就明白了一切。好吧,干得好,Hiber 为我们生成了一堆请求。但我们并不盲目,让我们在FruitService类中的JpaRepository<>接口中再实现一些方法
//возвращает запись из таблицы по id
public Optional<FruitEntity> getById(Integer id){
   return fruitRepository.findById(id);
}

//удаляет запись из таблицы по id
public void delById(Integer id){
    fruitRepository.deleteById(id);
}

//возвращает true or false при поиске в таблице Фруктов an object который соответствует типу FruitEntity or принадлежит к типу an object который наследуется от FruitEntity
public Boolean exist(Example<? extends FruitEntity> example){
    return fruitRepository.exists(example);
}
在 ProviderService 类中实现相同的方法。然后在FruitEntityProviderEntityInitiateUtils类中使用它们,并将结果打印到控制台。(顺便说一句,如果您不知道,您可以通过输入 sout 并按 Enter 键来快速编写“System.out.println()”,同样的操作也适用于“public static void main(String[] args){}” “只需输入 psvm 即可,等等)。我认为您已经解决了这个问题,我们已准备好继续前进。让我们转到FruitRepository接口并开始在其中键入(即键入而不是复制)以下方法: List<FruitEntity> f 您应该得到以下内容。 只需像编写查询一样调用该方法: findById(Integer id ) - 通过 id 查找对象;countFruitEntityByFruitName(String name) - 将计算具有特定名称的水果的数量;这些是由方法名称生成的查询; 请务必阅读它们并在FruitService类中实现Between(Integer from, Integer to)方法,以通过包含在中的provider_code字段的值搜索List<FruitEntity>一定的时间间隔,并在控制台中显示工作结果。例如:找到所有供应商编号在 5 到 7 之间的水果。在实现方法之前先不要急于继续阅读,不会花很长时间。正如您可能在有关按方法名称查询的文章中读到的那样:“您不能像这样编写所有查询,但可以编写简单的查询。” 对于更复杂的查询,使用@Query注解,并使用JPQL代替SQL (也请注意这篇文章),对于我们的项目,您可以进行JOIN查询,如下所示: Spring并不可怕,还是如何问数据库问题 - 2
package ru.java.rush.repositories;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import ru.java.rush.entities.FruitEntity;

import java.util.List;

@Repository
public interface FruitRepository extends JpaRepository<FruitEntity,Integer> {

    @Query("select f.fruitName, p.providerName from  FruitEntity f left join ProviderEntity p on f.providerCode = p.id")
    List<String> joinSting();

}
标准 SQL 查询为: “selectfruit_table.fruit_name,provider_table.provider_name fromfruit_table left joinprovider_table onfruit_table.provider_code =provider_table.id”。 这里可以很容易地建立对应关系:f ruit_tableFruitEntiy f,其中FruitEntiy是变量的类型,f是变量的名称,即 SQL 处理表和字段,而 JPQL 处理对象及其字段。同样,fruit_table.fruit_namef.fruitName;由于我们使用对象,因此我们可以输出对象:让我们编写另一个 FruitRepository 方法
@Query("select f from  FruitEntity f  join ProviderEntity p on f.providerCode = p.id")
List<FruitEntity> joinFruit();
让我们在 FruitService 类中实现这两个方法
public List<String> joinString(){
   return fruitRepository.joinSting();
}

public List<FruitEntity> joinFruit(){
    return fruitRepository.joinFruit();
}
听起来不错,但他们仍然使用旧的 SQL 来进行复杂的查询
@Query(
        value = "select fruit_table.fruit_name, provider_table.provider_name from  fruit_table  join provider_table on fruit_table.provider_code = provider_table.id_provider",  //по идее эту портянку надо засунуть в Howой нибудь  Enum
        nativeQuery = true) //нужно только пометить только nativeQuery = true
ListList<String> joinSqlFruit();
我们在InitiateUtils类中使用它们
System.out.println("\nТаблица фруктов и их поставщиков");
for (String join : fruitService.joinString()) {
    System.out.println(join);
}

System.out.println("\nТаблица фруктов и их поставщиков");
for (FruitEntity join : fruitService.joinFruit()) {
    System.out.println(join);
}

System.out.println("\nТаблица фруктов и их поставщиков");
        for (String join : fruitService.joinSqlFruit()) {
            System.out.println(join);
        }
我们启动该项目,并在控制台中看到新日志: Table offruits and their sellers Fruit1,null Fruit2,Provider5 Fruit3,Provider2 Fruit4,Provider5 Fruit5,null Fruit6,null Fruit7,null Fruit8,null Fruit9,null Table offruits and Their供应商 FruitEntity(id= 2,fruitName=Fruit2,providerCode=5) FruitEntity(id=3,fruitName=Fruit3,providerCode=2) FruitEntity(id=4,fruitName=Fruit4,providerCode=5) 水果及其供应商表 Fruit2 ,Provider5 Fruit3,Provider2 Fruit4 ,Provider5 是的,如果你已经厌倦了控制台中的“伪”和只是 SQL 查询,你可以在 yaml 文件中的位置返回 false。为什么第一个表中有null,如果你读过JOIN SQL就会发现。这样,我们就完成了对数据库的查询,我相信您仍然有很多问题,但我希望您能找到这些问题的答案,我试图突出显示搜索路径。让我们尝试总结一下我们这段时间所学到的一切: 1. 您可以在 Spring 中运行 Web 服务器,这并不困难。2. 要了解这一切是如何运作的,您需要深入研究理论。 关于这本书 关于 spring 的 文章 关于有用的东西的 文章 3. 为了将理解转化为物理代码,您需要编写代码,在继续之前,先了解一下 spring-boot 上的简单项目。而且最好不要复制写好的代码,而是重写它。我将在这里发布你和我一直在做的项目,但我将依靠你的意识,我相信你不会盲目地复制粘贴。 链接到 git 克隆存储库 https://FromJava@bitbucket.org/FromJava/jd.git 对于那些不知道如何使用此链接的人, 我建议实施两个培训项目: 关于喷漆汽车的项目: 第一类: CarEntity{ Integer ID; 字符串模型名称;字符串颜色;第二 类: ColorEntity{ Integer id; 字符串颜色;整数价格;填充 数据库(起一个现实的名字,这样会更容易理解),实现:,实体,存储库,服务,创建标准和跨表查询(把一辆宝马漆成红色需要多少钱?什么颜色最贵的?按字母顺序将模型写入控制台等); 图书馆项目: 第一类: BookEntity{ Integer id; 字符串名称Book;整数年份创建;整数 autord;第二 类: AutorEntity{ Integer id; 字符串firstNameAutor;字符串姓氏Autor;填充 数据库(起一个现实的名字,这样会更容易理解),实现:实体,存储库,服务,创建标准和表间查询(谁写了哪本书?哪本书先写的?哪本书写的从 1800 年到 1900 年?哪位作家写的书最多?);“Library”项目数据库填写示例 图书表 BookEntity(id=1, nameBook=Woe from Wit,yearCreat=1824,authorId=1) BookEntity(id=2,nameBook=战争与和平,yearCreat=1863,authorId=2) BookEntity(id=3,nameBook= Mtsyri,yearCreat = 1838,authorId = 3)BookEntity(id = 4,nameBook = Eugene Onegin,yearCreat = 1833,authorId = 4)作者表AuthorEntity(id = 1,firstNameAuthor = Alexander,lastNameAuthor = Griboyedov)AuthorEntity(id = 2) ,firstNameAuthor=Lev,lastNameAuthor=Tolstoy)AuthorEntity(id=3,firstNameAuthor=Mikhail,lastNameAuthor=Lermontov)AuthorEntity(id=4,firstNameAuthor=Alexander,lastNameAuthor=Pushkin) 祝大家好运,再见!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION