关于springboot:记录遇到的mongDb问题-以及restTemplate请求重试

6次阅读

共计 3618 个字符,预计需要花费 10 分钟才能阅读完成。

最近应用 mongDb 的时候,呈现了一些问题。

mongDb 实体 id 自增

在保留实体的时候报了这个错

Cannot aotogenerate id of type java.lang.Long for entity
不能主动生成 id

之后就带着报错去谷歌了一下。失去了如下后果:

Mongo ObjectIds 与 jave Long 类型不匹配。

先来介绍一下 MongoDB 的对象 Id(ObjectId)

ObjectId

ObjectId 是一个 12 字节 BSON 类型数据,有以下格局:

前 4 个字节示意工夫戳
接下来的 3 个字节是机器标识码
紧接的两个字节由过程 id 组成(PID)
最初三个字节是随机数。

例如 62ee651f cabe7f 59dc f10372

从 MongoDB 3.4 开始(最早公布于 2016 年 12 月),ObjectId 的设计被批改了,两头 5 字节的值由原先的“机器标识码 + 过程号”改为单纯随机值。

a 4-byte value representing the seconds since the Unix epoch,
a 5-byte random value, and
a 3-byte counter, starting with a random value.


MongoDB 中存储的文档必须有一个 ”_id” 键。这个键的值能够是任何类型的,默认是个 ObjectId 对象。

在一个汇合外面,每个文档都有惟一的 ”_id” 值,来确保汇合外面每个文档都能被惟一标识。

MongoDB 采纳 ObjectId,而不是其余比拟惯例的做法(比方主动减少的主键)的次要起因,因为在多个 服务器上同步主动减少主键值既费劲还费时。

找出起因

之后就在实体定义中发现,我定义的 id 是 Long 类型。
因为 mongoDb 主动进行 id 自增的时候,生成的 id 并不能转换为 Long,所以报了错

@JsonIgnoreProperties(ignoreUnknown = true)
@Document
public class System {

  @Id
  @JsonView
  private Long id;
}

之后改为 String 类型之后报错隐没。

在数据库中查看数据,查看到的是ObjectId 类型

传到前台,是 string 类型的数据

总结

在 mongoDb 中想要让主动设置 id 的话,须要设置 @Id 正文,并设置为 string 类型。

抉择应用 String 属性作为 ID,那么 Mongo 会在保留时主动为其赋值(如果它是空的)。通过抉择 String,您能够取得一个由数据库治理的主动调配的 ID,而不用费神手动设置该属性。

然而目前的我的项目中,id 都是从 gitlab 获取的数据,所以不须要主动设置 id,若采纳 Long 类型, 并本人设置 id , 失去数据就是这样,示意 id 为 22。

MongoDB 长久化实体映射

在网上查了无关实体正文时,遇到了一问题。

spring-data-mongodb 次要有以下罕用的注解.

@Id
主键,不可反复,自带索引

@Document
标注在实体类上,相似于 hibernate 的 entity 注解,表明由 mongo 来保护该表

@Document(collection=”mongodb 对应 collection 名 ”)

@Document
public class System {

  @Id
  @JsonView
  private String id;

跟以前不同的是,不必 @Entity 注解,用 @Document 注解。

@Field :属性

存储到数据库中的字段名。

加这个注解,就是以注解的值对应 mongo 的 key
不加这个注解,默认以参数对应 mongo 的 key

@Field("user_name")
private String userName;

另外 @CompoundIndex 联结索引和 @Transient:属性就不具体说了。


关联实体

一个比拟重要的点就是关联实体。

在 JPA 中,咱们能够用 @ManyToMany,@OneToMany 等正文,生成两头表等操作。

然而在 mongo 中,这些正文貌似并不起作用。

我在尝试增加 @ManyToMany 后,并没有生成两头表

@DBRef注解

而在 mongo 实体中,相似 @OneToMany 等成果的注解是: @DBRef

这个正文示意关联另一个 document 对象。相似于 mysql 的表关联。

没有加该正文的状况下,是这样子。作为一般的数据存到 labels 里。


加了正文的状况,是这样。
这里拿了其余文章的测试后果,我还没测试

能够发现而是只保留了它的 id 和 namespace. 相当于一个援用,或者说是外键。

另外值得注意的是,
这个注解并且 不会解决级联保留,你必须独自先保留 @DBRef 关联的对象。

你须要先 respority.save(@DBRef 关联的对象), 而后再保留原来的对象。

这是其余文章的测试后果:

小结:
看上去 mongo 解决的形式有点不同。然而目前我的项目中尽管应用了 mongo, 然而还在应用 @Entity 以及 @ManyToMany 等注解,也没有产生什么报错。

然而从后果来看,@ManyToMany 没有生成两头表。对 mongo 没有用。

restTemplate 申请重试

在后盾向 gitlab 申请数据的时候,无论尝试了几遍,都会报这个谬误。然而他人却能申请。

SSL 异样敞开了。

在之前也报过这个错,网上给出了解决办法个别都是如下。设置一下 https 协定类型。

System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSLv3");

然而尝试了几次都没有成果。


之后查看代码,须要获取 35 个 issue 下的评论。猜想到可能是因为申请次数和数据量相干。

于是就尝试了,当 restTemplate 申请失败时,减少重试机制

1,装置配置

编辑 pom.xml 文件,增加 相干依赖

<!-- 重试机制 -->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

2. 退出 @EnableRetry 注解

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@EnableRetry
@EnableAsync
public class NonlycodeApplication {

3. 应用 @Retryable 注解

 @Override
 @Retryable(value = {RestClientException.class, EOFException.class}, maxAttempts = 3,
          backoff = @Backoff(delay = 1000L,multiplier = 1))
  public <T> List<T> httGetWithPageRequest(String url, Map<String, String> variables, Integer latestPage, Class<T[]> valueType) throws JsonProcessingException {

@Retryable 注解的办法在产生异样时会重试,参数阐明:
value:指定重试异样
maxAttemps:最大重试次数,默认 3
backoff:重试期待策略,默认没有

@Backoff 注解为重试期待策略,参数阐明:
delay:指定重试的延时工夫,默认为 1000L,1 秒
multiplier:指定提早的倍数,默认为 0。比方 delay=5000l,multiplier=2 时,第一次重试为 5 秒后,第二次为 10 秒,第三次为 20 秒。

这样就能在调用这个办法的时候,只有其中某个异样产生时,被注解的办法就会进行重试。

抛出异样

当超过重试次数是异样会被抛出

 // 发动申请
    RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());
    ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.GET, new HttpEntity<String>(headers), String.class, variables);

    // 判断申请是否产生异样
    if(!response.getStatusCode().is2xxSuccessful()){System.out.println("申请失败...");
      // 抛出异样
      throw new RestClientException(response.getBody());
    }
正文完
 0