MongoDB事物使用简单总结
工作时间繁忙,过了一个多月了好久才有时间做总结。。。。
假如有写的不对的地方请告诉我,不胜感激涕零 !
Jdk :1.8
MongoDB:4.0.3
SpringBoot 2.0+
提供接口供对方调用。批量处理集合对象。每秒大概达到三千到五千左右。
对象中有某些属性是唯一的(filedId),当同一个集合中有相同的field时,对某些属性更新替换,既更新时有些信息需要更新有些则不需要更新。
数据集合中有某个属性(entityType),处理时根据该属性分集合保存。
每次调用要么成功,要么失败既支持事物。
Mongodb的事务是依靠 Mongodb连接的客户端 session 实现,事务执行的流程大致是 建立 session,通过 session startTransaction 启动事务,如果一系列事务都完成,那么 commitTransaction 完成事务操作,并结束当前事务 session;如果一系列事务中有任意事件失败, 那么 abortTransaction 中止事务,内部将已完成的任务回退到修改之前,并结束当前事务 session。
整个事物处理过程如下:
session = client.startSession();
session.startTransaction();
session.commitTransaction();
session.abortTransaction();
session.endSession();
# mongodb配置
spring.data.mongodb.uri=mongodb://192.168.101.110:27027/admin
## 库名称
spring.data.mongodb.dbname=file_info-test
@Configuration
public class MongoDBConifg {
private MongoClient client;
@Value("${spring.data.mongodb.uri}")
private String mongodbURI;
@Value("${spring.data.mongodb.dbname}")
private String databaseName;
private MongoDatabase mongoDatabase;
// 设置MongoDB的一些配置
@PostConstruct
public void initMongoDB() {
getLogger("org.mongodb.driver").setLevel(Level.SEVERE);
CodecRegistry codecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(), fromProviders(
PojoCodecProvider.builder().register("com.mongodb.models").build()));
CodecRegistry pojoCodecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
MongoClientOptions.Builder options = new MongoClientOptions.Builder().codecRegistry(pojoCodecRegistry);
MongoClientURI uri = new MongoClientURI(mongodbURI, options);
client = new MongoClient(uri);
mongoDatabase = client.getDatabase(databaseName);
mongoDatabase.withCodecRegistry(codecRegistry);
}
public MongoClient getClient() {
return client;
}
public MongoDatabase getMongoDatabase() {
return mongoDatabase;
}
@Autowired
private MongoDBConifg mongoDBConifg;
public boolean bathInsertLayoutFile(List layoutFiles) throws MongoCommandException {
MongoClient client = mongoDBConifg.getClient();
ClientSession session = client.startSession();
try {
session.startTransaction(TransactionOptions.builder().writeConcern(WriteConcern.MAJORITY).build());
Map> fileList = layoutFiles.stream().collect(Collectors.groupingBy(LayoutFile::getEntityType));
for (String layoutFile : fileList.keySet()) {
List temp = fileList.get(layoutFile);
MongoCollection collection = mongoDBConifg.getMongoDatabase().getCollection(layoutFileUtils.getCollectionName(layoutFile), LayoutFile.class);
repository.insetLayoutFileList(session, collection, temp); // 入库动作
}
session.commitTransaction();
} catch (MongoCommandException e) {
session.abortTransaction();
log.error("rollback transaction , insert failure error message {}", e.getMessage(), e);
return false;
} catch (Exception e) {
log.error(" insert failure, error message {}", e.getMessage(), e);
session.abortTransaction();
return false;
} finally {
session.close();
}
return true;
}
public com.mongodb.bulk.BulkWriteResult insetLayoutFileList(ClientSession session, MongoCollection collection, List layoutFiles) {
com.mongodb.bulk.BulkWriteResult bulkWriteResult = null;
UpdateOptions updateOptions = new UpdateOptions().upsert(true);
List> updates = new ArrayList>();
// 构建数据
for (LayoutFile layoutFile : layoutFiles) {
Bson filter = new Document("fileId", layoutFile.getFileId()); // 根据fileId ,若是数据存在则更新,不存在插入
if (log.isDebugEnabled()) {
log.info("filedId:" + layoutFile.getFileId());
}
UpdateOneModel updateOneModel = new UpdateOneModel(filter, convertToBson(layoutFile), updateOptions);
updates.add(updateOneModel);
}
try {
bulkWriteResult = collection.bulkWrite(session, updates, new BulkWriteOptions().ordered(false));
} catch (Exception e) {
log.error("insetLayoutFileList error message {}", e.getMessage(), e);
throw e;
}
return bulkWriteResult;
}
String json = JSON.toJSONString(layoutFile);
Document document = Document.parse(json);
(2)这种情况下适用于update
// 将对象转换,从新构造一个新的document
private Document convertToBson(LayoutFile layoutFile) {
Document newdoc = new Document();
newdoc.put("status", layoutFile.getStatus());
newdoc.put("entityType", layoutFile.getEntityType());
newdoc.put("updatetime", layoutFile.getUpdatetime());
newdoc.put("dt", layoutFile.getDt());
return new Document("$set", newdoc).
append("$setOnInsert", new Document("createtime", layoutFile.getCreatetime())). // 在第一次插入是赋值。
append("$currentDate", new BasicDBObject("updateTime", true)); // 每次修改一条记录时会更新
}
在复制集合中,不能自动的创建集合,并且在给多个集合创建多个信息(如唯一索引)时,需要初始化集合,编写初始化脚本(一个文件)。执行插入数据是报错(第二次插入数据时)。报错信息大体如下: ** 具体某个集合DuplicateKey
当时处理方法:也不知道什么原因。处理方式就是先执行创建集合的脚本。确保集合创建完成之后再进行创建索引信息。
待后续补充完整。。。