像SpringBoot这样的应用开发框架已经做得很好了,它使开发者能够快速开始用Java开发应用。将对象关系映射分层到SQL,以消除专有语法,进一步简化了数据库应用的开发。
CockroachDB允许开发者在全球分布式数据的发展中利用简单的SQL界面。但是每个数据库都会带来它自己的特定语法,导致开发者在开始使用一个新数据库时犹豫不决。
你如何开始呢?
这篇博客将使用SpringBoot、Hibernate、JAVA和Gradle来展示一个使用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用你的例子和指针提供的指导。