用Spring、Java、Hibernate、Gradle和CockroachDB构建一个应用程序(详细教程)

319 阅读8分钟

SpringBoot这样的应用开发框架已经做得很好了,它使开发者能够快速开始用Java开发应用。将对象关系映射分层到SQL,以消除专有语法,进一步简化了数据库应用的开发。

CockroachDB允许开发者在全球分布式数据的发展中利用简单的SQL界面。但是每个数据库都会带来它自己的特定语法,导致开发者在开始使用一个新数据库时犹豫不决。

你如何开始呢?

这篇博客将使用SpringBootHibernateJAVAGradle来展示一个使用CockroachDB的简单端到端解决方案。

解读CockroachDB数据源

如果你已经用Postgres开发了一个应用程序,那么用Cockroach开发将是轻而易举的。CockroachDB是为兼容Postgres 9.6方言而编写的。用于连接CockroachDB的连接字符串URL是与Postgres的JDBC驱动插件兼容的。这使得你可以使用各种工具如dbeaver来连接和运行各种SQL语句。

对于像Hibernate这样的ORM,你可以像连接Postgres一样进行连接。目前,Hibernate与PostgreSQL95Dialect兼容。所以要连接到CockroachDB,应该在SpringBoot的application.properties 文件中进行如下配置。

spring.datasource.url=jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect

这真的是这样!

本博客的其余部分将引导你完成SpringBoot快速启动的步骤。

第1步:用SpringBoot快速启动

打开快速启动,创建所需的基本框架。在这个例子中使用了以下选项:

  • 项目:Gradle项目
  • 语言:项目语言: Java
  • SpringBoot: 2.2.4
  • 项目元数据
    • 群组: example.com
    • 工件:first_cockroach /w Options...
      • name: first_cockroach
      • 描述。Spring Boot的演示项目
      • 包名称: com.example.first_cockroach
      • 包装:JAR, Java 8

该页面应该是这样的:

选择依赖项下的汉堡包下拉菜单,添加以下项目:

  • 开发者工具
    • Spring Boot DevTools
    • Lombok
  • 网络
  • SQL
    • Spring Data JPA
    • Flyway迁移
    • PostgreSQL驱动

和...

一旦选择了这些,你可以简单地点击生成快速启动包。如果你使用上面的工件名称,你应该有一个first_cockroach.zip 文件来开始。

第2步:解压工件并添加连接资源

在你的工作环境中解压步骤1中创建的工件,并导航到src/main/resources 目录。一旦进入该目录,创建application.properties 文件,该文件定义了如何连接到数据库并通过flyway迁移数据。

### Setup Postgres driver
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
spring.datasource.username=root
spring.datasource.password=
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
### Connect URL for localhost with port 26257 /w insecure connection
### Database name is defaultdb
spring.datasource.url=jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable
### Set baseline-on-migrate with Flyway
spring.flyway.baseline-on-migrate=true
### Set baseline-version for Flyway to execute migrations at version 1 or more

对于这个简单的测试,我在我的笔记本电脑上创建了一个简单的蟑螂测试集群。对于一个更简单的演示集群,你可以简单地运行cockroach demo。

第3步:创建flyway迁移文件

简单地在src/main/resources/db/migration 目录中创建适当的飞道迁移文件。对于这个简单的测试,我创建了一个文件V1__AddPetsTable.sql来创建和填充pets表。

--##
--##     Flyway Migration File
--##         src/main/resources/db/migration/V1__AddPetsTable.sql
--##
--## Create pets table
--##
CREATE TABLE pets
(
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name STRING,
type STRING,
indoor BOOLEAN DEFAULT TRUE
);
--##
--## Define the herd
--##
INSERT INTO pets (name, type)
VALUES ('tula', 'cat'),('ruby','dog'),('rosie','dog');
INSERT INTO pets (name, type, indoor)

在一个典型的项目中,这是使用Cockroach特定的语法来定义表和索引,以利用地理分区重复索引倒置索引等功能。

第4步:实体、控制器、存储库和服务

Spring已经创建了src/main/java/com/example/first_cockroach 目录和FirstCockroachApplication.java 文件,作为这个项目的起点。在这个目录中,创建用于定义各种对象和服务的目录。

cd src/main/java/com/example/first_cockroach
mkdir entities
mkdir controllers
mkdir repositories
mkdir services

第5步:为宠物创建实体

现在表被定义了,我们可以创建一个对象,映射到宠物表在src/main/java/com/example/first_cockroach/entities 目录中创建Pets.java 文件。

//
// Pets.java
//
package com.example.first_cockroach.entities;
//
import lombok.Data;
//
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.UUID;
//
@Entity(name = "PETS")
@Data
public class Pets {
@Id
@GeneratedValue
private UUID id;
private String name;
private String type;
private Boolean indoor = true;
}

第6步:为Pets创建控制器

这个控制器定义了如何通过restful控制器向pets表插入数据。在src/main/java/com/example/first_cockroach/controllers 目录下创建PetsController.java 文件:

// PetsController.java
//
package com.example.first_cockroach.controllers;
//
import com.example.first_cockroach.entities.Pets;
import com.example.first_cockroach.services.PetsService;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
//
import static org.springframework.web.bind.annotation.RequestMethod.POST;
//
@RepositoryRestController
public class PetsController {
//
private final PetsService petsService;
//
public PetsController(PetsService petsService) {
this.petsService = petsService;
}
//
@RequestMapping(method = POST, value = "/pets")
public @ResponseBody ResponseEntity createPets(@RequestBody Pets pet, HttpServletRequest request) {
Pets createdPet = petsService.save(pet);
//
URI createdUri = URI.create(request.getRequestURL().toString() + "/" + createdPet.getId());
return ResponseEntity.created(createdUri).body(createdPet);
}
}

第7步:为Pets创建存储库

这个控制器定义了如何通过restful控制器向pets表中查询数据。在src/main/java/com/example/first_cockroach/repositories 目录下创建PetsRepository.java 文件:

// PetsRepository.java
//
package com.example.first_cockroach.repositories;
//
import com.example.first_cockroach.entities.Pets;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
//
import java.util.List;
import java.util.UUID;
//
@RepositoryRestResource(collectionResourceRel = "pets", path = "pets")
public interface PetsRepository extends PagingAndSortingRepository {
//
List findByName(@Param("name") String name);
}

第8步:为宠物创建服务

这定义了如何为宠物提供服务。在src/main/java/com/example/first_cockroach/services 目录下创建PetsService.java 文件:

// PetsService.java
//
package com.example.first_cockroach.services;
//
import com.example.first_cockroach.entities.Pets;
import com.example.first_cockroach.repositories.PetsRepository;
import org.springframework.stereotype.Service;
//
@Service
public class PetsService {
//
private final PetsRepository petsRepository;
//
public PetsService(PetsRepository petsRepository) {
this.petsRepository = petsRepository;
}
//
public Pets save(Pets pet) {
return petsRepository.save(pet);
}
}

第9步:是时候运行了!

现在我们可以用SpringBoot和CockroachDB来启动和运行你的应用程序了!只需输入./gradlew bootRun 来运行。你应该看到下面的画面:

./gradlew bootRun
> Task :bootRun
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.4.RELEASE)
2020-02-28 11:22:41.907  INFO 4390 --- [  restartedMain] c.e.f.FirstCockroachApplication          : Starting FirstCockroachApplication on MacBook-Pro-9.local with PID 4390 (/Users/glenn/git/misc_projects_glenn/workshop_java_corelogic/java_gradle_glenn_v1/first_cockroach/build/classes/java/main started by glenn in /Users/glenn/git/misc_projects_glenn/workshop_java_corelogic/java_gradle_glenn_v1/first_cockroach)
...
<=========----> 75% EXECUTING [1m 28s]
> :bootRun

一旦运行,打开另一个数据库的SQL会话,检查是否已经创建了表,并且已经添加了初始宠物:


cockroachdb sql --insecure
root@localhost:26257/defaultdb> select * from pets;
id                  |  name  |   type   | indoor
+--------------------------------------+--------+----------+--------+
333cf0c1-8245-4b90-9f17-6c059de57fb7 | tula   | cat      |  true
6f61408f-9074-4d00-80ac-2e189aacf62c | virgil | squirrel | false
7e4dfb73-9f3d-4e64-aade-1b7a8457ac51 | ruby   | dog      |  true
ce32bd86-6485-4846-af14-55e66eaf792a | rosie  | dog      |  true
(4 rows)

现在让我们试试RESTFUL接口来检索宠物数据,从 [http://localhost:8080/pets](http://localhost:8080/pets):


curl http://localhost:8080/pets
{
  "_embedded" : {
    "pets" : [ {
      "name" : "tula",
      "type" : "cat",
      "indoor" : true,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/pets/333cf0c1-8245-4b90-9f17-6c059de57fb7"
        },
        "pets" : {
          "href" : "http://localhost:8080/pets/333cf0c1-8245-4b90-9f17-6c059de57fb7"
        }
      }
    }, {
      "name" : "virgil",
      "type" : "squirrel",
      "indoor" : false,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/pets/6f61408f-9074-4d00-80ac-2e189aacf62c"
        },
        "pets" : {
          "href" : "http://localhost:8080/pets/6f61408f-9074-4d00-80ac-2e189aacf62c"
        }
      }
    }, {
      "name" : "ruby",
      "type" : "dog",
      "indoor" : true,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/pets/7e4dfb73-9f3d-4e64-aade-1b7a8457ac51"
        },
        "pets" : {
          "href" : "http://localhost:8080/pets/7e4dfb73-9f3d-4e64-aade-1b7a8457ac51"
        }
      }
    }, {
      "name" : "rosie",
      "type" : "dog",
      "indoor" : true,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/pets/ce32bd86-6485-4846-af14-55e66eaf792a"
        },
        "pets" : {
          "href" : "http://localhost:8080/pets/ce32bd86-6485-4846-af14-55e66eaf792a"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/pets{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/pets"
    },
    "search" : {
      "href" : "http://localhost:8080/pets/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 5,
    "totalPages" : 1,
    "number" : 0
  }
 }

现在让我们测试一下通过POST向宠物应用程序插入数据的情况:

curl -i -X POST -H "Content-Type:application/json" -d '{"name": "Mazie","type": "dog","inside": "true"}' http://localhost:8080/pets
HTTP/1.1 201
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Location: http://localhost:8080/pets/45234458-6468-4d24-8a2d-b0dad6b8881d
Content-Type: application/hal+json
Transfer-Encoding: chunked
Date: Fri, 28 Feb 2020 19:42:24 GMT

{
  "id" : "45234458-6468-4d24-8a2d-b0dad6b8881d",
  "name" : "Mazie",
  "type" : "dog",
  "indoor" : true
}

最后,我们可以查询到宠物表,以确保数据存储在CockroachDB中:


root@localhost:26257/defaultdb> select * from pets;
id                  |  name  |   type   | indoor
+--------------------------------------+--------+----------+--------+
333cf0c1-8245-4b90-9f17-6c059de57fb7 | tula   | cat      |  true
45234458-6468-4d24-8a2d-b0dad6b8881d | Mazie  | dog      |  true
6f61408f-9074-4d00-80ac-2e189aacf62c | virgil | squirrel | false
7e4dfb73-9f3d-4e64-aade-1b7a8457ac51 | ruby   | dog      |  true
ce32bd86-6485-4846-af14-55e66eaf792a | rosie  | dog      |  true
(5 rows)

最后的思考

这只是一个简单的例子,说明如何开始使用SpringBoot和Cockroach。如果你正在用CockroachDB开发一个高并发的应用程序,你需要考虑用可序列化的事务来编写重试代码。这通常是通过Springboot的重试操作来处理这一事件。

我希望这篇文章对展示如何开始开发使用CockroachDB的SpringBoot应用程序很有用。

下面是关于用SpringBoot、Hibernate、Java和Gradle构建Restful应用的各种链接。感谢Vinh Thai用你的例子和指针提供的指导。