国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot MongoDB 索引沖突分析及解決方法

SpringBoot MongoDB 索引沖突分析及解決方法

2021-06-18 13:58美碼師 Java教程

這篇文章主要介紹了SpringBoot MongoDB 索引沖突分析及解決方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、背景

spring-data-mongo 實現了基于 mongodb 的 orm-mapping 能力,

通過一些簡單的注解、query封裝以及工具類,就可以通過對象操作來實現集合、文檔的增刪改查;

在 springboot 體系中,spring-data-mongo 是 mongodb java 工具庫的不二之選。

二、問題產生

在一次項目問題的追蹤中,發現springboot 應用啟動失敗,報錯信息如下:

error creating bean with name 'mongotemplate' defined in class path resource [org/bootfoo/bootconfiguration.class]: bean instantiation via factory method failed; nested exception is org.springframework.beans.beaninstantiationexception: failed to instantiate [org.springframework.data.mongodb.core.mongotemplate]: factory method 'mongotemplate' threw exception; nested exception is org.springframework.dao.dataintegrityviolationexception: cannot create index for 'deviceid' in collection 't_mdevice' with keys '{ "deviceid" : 1}' and options '{ "name" : "deviceid"}'. index already defined as '{ "v" : 1 , "unique" : true , "key" : { "deviceid" : 1} , "name" : "deviceid" , "ns" : "appdb.t_mdevice"}'.; nested exception is com.mongodb.mongocommandexception: command failed with error 85: 'exception: index with name: deviceid already exists with different options' on server 127.0.0.1:27017. the full response is { "createdcollectionautomatically" : false, "numindexesbefore" : 6, "errmsg" : "exception: index with name: deviceid already exists with different options", "code" : 85, "ok" : 0.0 }
at org.springframework.beans.factory.annotation.autowiredannotationbeanpostprocessor$autowiredfieldelement.inject(autowiredannotationbeanpostprocessor.java:588)
at org.springframework.beans.factory.annotation.injectionmetadata.inject(injectionmetadata.java:88)
at org.springframework.beans.factory.annotation.autowiredannotationbeanpostprocessor.postprocesspropertyvalues(autowiredannotationbeanpostprocessor.java:366)
at org.springframework.beans.factory.support.abstractautowirecapablebeanfactory.populatebean(abstractautowirecapablebeanfactory.java:1264)
at org.springframework.beans.factory.support.abstractautowirecapablebeanfactory.docreatebean(abstractautowirecapablebeanfactory.java:553)

...

caused by: org.springframework.dao.dataintegrityviolationexception: cannot create index for 'deviceid' in collection 't_mdevice' with keys '{ "deviceid" : 1}' and options '{ "name" : "deviceid"}'. index already defined as '{ "v" : 1 , "unique" : true , "key" : { "deviceid" : 1} , "name" : "deviceid" , "ns" : "appdb.t_mdevice"}'.; nested exception is com.mongodb.mongocommandexception: command failed with error 85: 'exception: index with name: deviceid already exists with different options' on server 127.0.0.1:27017. the full response is { "createdcollectionautomatically" : false, "numindexesbefore" : 6, "errmsg" : "exception: index with name: deviceid already exists with different options", "code" : 85, "ok" : 0.0 }
at org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.createindex(mongopersistententityindexcreator.java:157)
at org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.checkforandcreateindexes(mongopersistententityindexcreator.java:133)
at org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.checkforindexes(mongopersistententityindexcreator.java:125)
at org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.<init>(mongopersistententityindexcreator.java:91)
at org.springframework.data.mongodb.core.index.mongopersistententityindexcreator.<init>(mongopersistententityindexcreator.java:68)
at org.springframework.data.mongodb.core.mongotemplate.<init>(mongotemplate.java:229)
at org.bootfoo.bootconfiguration.mongotemplate(bootconfiguration.java:121)
at org.bootfoo.bootconfiguration$$enhancerbyspringcglib$$1963a75.cglib$mongotemplate$2(<generated>)
at sun.reflect.delegatingmethodaccessorimpl.invoke(unknown source)
at java.lang.reflect.method.invoke(unknown source)
at org.springframework.beans.factory.support.simpleinstantiationstrategy.instantiate(simpleinstantiationstrategy.java:162)
... 58 more

caused by: com.mongodb.mongocommandexception: command failed with error 85: 'exception: index with name: deviceid already exists with different options' on server 127.0.0.1:27017. the full response is { "createdcollectionautomatically" : false, "numindexesbefore" : 6, "errmsg" : "exception: index with name: deviceid already exists with different options", "code" : 85, "ok" : 0.0 }
at com.mongodb.connection.protocolhelper.getcommandfailureexception(protocolhelper.java:115)
at com.mongodb.connection.commandprotocol.execute(commandprotocol.java:114)
at com.mongodb.connection.defaultserver$defaultserverprotocolexecutor.execute(defaultserver.java:168)

關鍵信息: org.springframework.dao.dataintegrityviolationexception: cannot create index

從異常信息上看,出現的是索引沖突( command failed with error 85 ),spring-data-mongo 組件在程序啟動時會實現根據注解創建索引的功能。

查看業務實體定義:

?
1
2
3
4
5
6
7
8
@document(collection = "t_mdevice")
public class mdevice {
 
  @id
  private string id;
 
  @indexed(unique=true)
  private string deviceid;

deviceid 這個字段上定義了一個索引, unique=true 表示這是一個唯一索引。

我們繼續 查看 mongodb中表的定義:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
db.getcollection('t_mdevice').getindexes()
 
>>
[
  {
    "v" : 1,
    "key" : {
      "_id" : 1
    },
    "name" : "_id_",
    "ns" : "appdb.t_mdevice"
  },
  {
    "v" : 1,
    "key" : {
      "deviceid" : 1
    },
    "name" : "deviceid",
    "ns" : "appdb.t_mdevice"
  }
]

發現數據庫表中同樣存在一個名為 deviceid的索引,但是并非唯一索引!

三、詳細分析

為了核實錯誤產生的原因,我們嘗試通過 mongo shell去執行索引的創建,發現返回了同樣的錯誤。

通過將數據庫中的索引刪除,或更正為 unique=true 之后可以解決當前的問題。

從嚴謹度上看,一個索引沖突導致 springboot 服務啟動不了,是可以接受的。

但從靈活性來看,是否有某些方式能 禁用索引的自動創建 ,或者僅僅是打印日志呢?

嘗試 google spring data mongodb disable index creation

發現 jira-datamongo-1201 在2015年就已經提出,至今未解決。

SpringBoot MongoDB 索引沖突分析及解決方法

stackoverflow 找到許多  同樣問題 

但大多數的解答是不采用索引注解,選擇其他方式對索引進行管理。

這些結果并不能令人滿意。

嘗試查看 spring-data-mongo 的機制,定位到 mongopersistententityindexcreator 類:

初始化方法中,會根據 mappingcontext(實體映射上下文)中已有的實體去創建索引

?
1
2
3
4
5
6
7
8
public mongopersistententityindexcreator(mongomappingcontext mappingcontext, mongodbfactory mongodbfactory,
      indexresolver indexresolver) {
    ...
    //根據已有實體創建
    for (mongopersistententity<?> entity : mappingcontext.getpersistententities()) {
      checkforindexes(entity);
    }
  }

在接收到mappingcontextevent時,創建對應實體的索引

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void onapplicationevent(mappingcontextevent<?, ?> event) {
 
   if (!event.wasemittedby(mappingcontext)) {
     return;
   }
 
   persistententity<?, ?> entity = event.getpersistententity();
 
   // double check type as spring infrastructure does not consider nested generics
   if (entity instanceof mongopersistententity) {
     //創建單個實體索引
     checkforindexes((mongopersistententity<?>) entity);
   }
 }

mongopersistententityindexcreator是通過mongotemplate引入的,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public mongotemplate(mongodbfactory mongodbfactory, mongoconverter mongoconverter) {
 
  assert.notnull(mongodbfactory);
 
  this.mongodbfactory = mongodbfactory;
  this.exceptiontranslator = mongodbfactory.getexceptiontranslator();
  this.mongoconverter = mongoconverter == null ? getdefaultmongoconverter(mongodbfactory) : mongoconverter;
  ...
 
  // we always have a mapping context in the converter, whether it's a simple one or not
  mappingcontext = this.mongoconverter.getmappingcontext();
  // we create indexes based on mapping events
  if (null != mappingcontext && mappingcontext instanceof mongomappingcontext) {
    indexcreator = new mongopersistententityindexcreator((mongomappingcontext) mappingcontext, mongodbfactory);
    eventpublisher = new mongomappingeventpublisher(indexcreator);
    if (mappingcontext instanceof applicationeventpublisheraware) {
      ((applicationeventpublisheraware) mappingcontext).setapplicationeventpublisher(eventpublisher);
    }
  }
}
 
 
...
//mongotemplate實現了 applicationcontextaware,當applicationcontext被實例化時被感知
public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
 
  prepareindexcreator(applicationcontext);
 
  eventpublisher = applicationcontext;
  if (mappingcontext instanceof applicationeventpublisheraware) {
    //mappingcontext作為事件來源,向applicationcontext發布
    ((applicationeventpublisheraware) mappingcontext).setapplicationeventpublisher(eventpublisher);
  }
  resourceloader = applicationcontext;
}
 
...
//注入事件監聽
private void prepareindexcreator(applicationcontext context) {
 
  string[] indexcreators = context.getbeannamesfortype(mongopersistententityindexcreator.class);
 
  for (string creator : indexcreators) {
    mongopersistententityindexcreator creatorbean = context.getbean(creator, mongopersistententityindexcreator.class);
    if (creatorbean.isindexcreatorfor(mappingcontext)) {
      return;
    }
  }
 
  if (context instanceof configurableapplicationcontext) {
    //使 indexcreator 監聽 applicationcontext的事件
    ((configurableapplicationcontext) context).addapplicationlistener(indexcreator);
  }
}

由此可見, mongotemplate 在初始化時,先通過 mongoconverter 帶入 mongomappingcontext,

隨后完成一系列初始化,整個過程如下:

  • 實例化 mongotemplate;
  • 實例化 mongoconverter;
  • 實例化 mongopersistententityindexcreator;
  • 初始化索引(通過mappingcontext已有實體);
  • repository初始化 -> mappingcontext 發布映射事件;
  • applicationcontext 將事件通知到 indexcreator;
  • indexcreator 創建索引

在實例化過程中,沒有任何配置可以阻止索引的創建。

四、解決問題

從前面的分析中,可以發現問題關鍵在 indexcreator,能否提供一個自定義的實現呢,答案是可以的!

實現的要點如下

  • 實現一個indexcreator,可繼承mongopersistententityindexcreator,去掉索引的創建功能;
  • 實例化 mongoconverter和 mongotemplate時,使用一個空的 mongomappingcontext對象避免初始化索引;
  • 將自定義的indexcreator作為bean進行注冊,這樣在prepareindexcreator方法執行時,原來的 mongopersistententityindexcreator不會監聽applicationcontext的事件
  • indexcreator 實現了applicationcontext監聽,接管 mappingevent事件處理。

實例化bean

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@bean
 public mongomappingcontext mappingcontext() {
   return new mongomappingcontext();
 }
 
 // 使用 mappingcontext 實例化 mongotemplate
 @bean
 public mongotemplate mongotemplate(mongodbfactory mongodbfactory, mongomappingcontext mappingcontext) {
   mappingmongoconverter converter = new mappingmongoconverter(new defaultdbrefresolver(mongodbfactory),
       mappingcontext);
   converter.settypemapper(new defaultmongotypemapper(null));
 
   mongotemplate mongotemplate = new mongotemplate(mongodbfactory, converter);
 
   return mongotemplate;
 }

自定義indexcreator

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 自定義indexcreator實現
@component
public static class customindexcreator extends mongopersistententityindexcreator {
 
  // 構造器引用mappingcontext
  public customindexcreator(mongomappingcontext mappingcontext, mongodbfactory mongodbfactory) {
    super(mappingcontext, mongodbfactory);
  }
 
  public void onapplicationevent(mappingcontextevent<?, ?> event) {
    persistententity<?, ?> entity = event.getpersistententity();
 
    // 獲得mongo實體類
    if (entity instanceof mongopersistententity) {
      system.out.println("detected mongoentity " + entity.getname());
      
      //可實現索引處理..
    }
  }
}

在這里 customindexcreator繼承了 mongopersistententityindexcreator ,將自動接管mappingcontextevent事件的監聽。

在業務實現上可以根據需要完成索引的處理!

小結

spring-data-mongo 提供了非常大的便利性,但在靈活性支持上仍然不足。上述的方法實際上有些隱晦,在官方文檔中并未提及這樣的方式。

orm-mapping 框架在實現schema映射處理時需要考慮校驗級別,比如 hibernate便提供了 none/create/update/validation 多種選擇,畢竟這對開發者來說更加友好。

期待 spring-data-mongo 在后續的演進中能盡快完善 schema的管理功能!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/littleatp/p/10043447.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 午夜精品一区二区三区在线视频 | 黄色免费网站在线观看 | 无码一区二区三区视频 | 精品一级 | 99在线视频播放 | 精品无码久久久久久久动漫 | 日韩国产欧美 | 在线欧美视频 | 国产精品久久久久久久9999 | 国产中文字幕在线观看 | 99久久精品国产一区二区三区 | 久久综合九色综合网站 | 久久久美女| 日日干夜夜骑 | 婷婷综合五月天 | 日韩精品一区二区三区中文字幕 | 欧美一区二区三区在线看 | 视频在线一区二区 | 国产一级黄 | 性色蜜桃x88av | 一区二区三区视频在线观看 | 国产欧美精品 | 日韩欧美国产一区二区 | 亚洲视频第一页 | 亚洲日韩成人 | 一区二区在线 | 国产精品成人av | 高清二区 | av片在线观看| 色淫av| 国产精品福利午夜在线观看 | 亚洲男女在线 | 亚洲视频欧美视频 | 一色视频| 亚洲欧美v国产一区二区 | 人人人人澡人人爽人人澡 | 一区二区三区四区日韩 | 日韩看片| 精品欧美一区二区三区久久久 | 日韩在线精品视频 | 久久精品综合 |