개요
이 가이드에서는 MongoDB Java 드라이버로 복합 작업 을 수행하는 방법을 배울 수 있습니다.
복합 작업은 하나의 원자 조작 으로 수행되는 읽기 및 쓰기 작업으로 구성됩니다. 원자 조작은 완전히 완료되거나 전혀 완료되지 않는 작업입니다. 원자 조작은 부분적으로 완료할 수 없습니다.
원자 조작은 코드에서 경쟁 상태 를 방지하는 데 도움이 될 수 있습니다. 경쟁 상태는 코드의 동작이 제어할 수 없는 이벤트의 순서에 따라 달라질 때 발생합니다.
MongoDB는 다음과 같은 복합 연산을 지원합니다.
하나의 문서 찾기 및 업데이트
하나의 문서 찾기 및 바꾸기
문서 한 개 찾기 및 삭제
하나 이상의 문서를 읽고 쓰는 것과 같이 더 복잡한 작업을 원자적으로 수행해야 하는 경우 transaction 을 사용하세요. 트랜잭션은 MongoDB 및 기타 데이터베이스의 기능으로, 이를 통해 임의의 데이터베이스 명령 시퀀스를 원자 조작으로 정의할 수 있습니다.
원자성 연산 및 원자성에 대한 자세한 내용은 원자성 및 트랜잭션에 대한 MongoDB 매뉴얼 항목을 참조하세요.
트랜잭션에 대한 자세한 내용은 트랜잭션에 대한 MongoDB 수동 입력을 참조하세요.
복합 연산 사용 방법
이 섹션에서는 MongoDB Java 드라이버에서 각 복합 연산을 사용하는 방법을 설명합니다.
다음 예제에서는 이러한 두 개의 샘플 문서가 포함된 collection을 사용합니다.
{"_id": 1, "food": "donut", "color": "green"} {"_id": 2, "food": "pear", "color": "yellow"}다음 예제의 전체 코드는 Github에서 확인할 수 있습니다.
참고
쓰기 전 또는 후
기본적으로 각 복합 작업은 쓰기 작업 이전의 상태로 찾은 문서를 반환합니다. 복합 작업에 해당하는 옵션 클래스를 사용하여 쓰기 작업 후 상태에서 찾은 문서를 검색할 수 있습니다. 이 구성의 예는 아래의 찾기 및 바꾸기 예제에서 확인할 수 있습니다.
찾기 및 업데이트
하나의 문서를 찾아 업데이트하려면 MongoCollection 클래스의 findOneAndUpdate() 메서드를 사용합니다. findOneAndUpdate() 메서드는 찾은 문서를 반환하거나 쿼리와 일치하는 문서가 없는 경우 null 을 반환합니다.
예시
다음 예제에서는 findOneAndUpdate() 메서드를 사용하여 color 필드가 "green" 로 설정된 문서를 찾고 해당 문서의 food 필드를 "pizza" 로 업데이트합니다.
또한 FindOneAndUpdateOptions 인스턴스를 사용하여 다음 옵션을 지정합니다.
프로젝션을 사용하여 발견된 문서에서
_id필드를 제외합니다.쿼리와 일치하는 문서가 없는 경우 쿼리 필터에 지정된 문서를 삽입하는 업서트를 지정합니다.
// <MongoCollection set up code here>
// Creates a projection to exclude the "_id" field from the retrieved documentsBson projection = Projections.excludeId();
// Creates a filter to match documents with a "color" value of "green"Bson filter = Filters.eq("color", "green");
// Creates an update document to set the value of "food" to "pizza"Bson update = Updates.set("food", "pizza");
// Defines options that specify projected fields and permit upsertsFindOneAndUpdateOptions options = new FindOneAndUpdateOptions() .projection(projection) .upsert(true);
// Updates the first matching document with the content of the update document, applying the specified optionsDocument result = collection.findOneAndUpdate(filter, update, options);
// Prints the matched document in its state before the operationSystem.out.println(result.toJson());앞의 코드의 출력은 다음과 유사합니다.
{"food": "pizza", "color": "green"}Projections 클래스에 대한 자세한 내용은 프로젝션 빌더 가이드를 참조하세요.
업서트 작업에 대한 자세한 내용은 업서트 가이드를 참조하세요.
이 섹션에 언급된 메서드 및 클래스에 대한 자세한 내용은 다음 API 문서를 참조하세요.
찾기 및 바꾸기
하나의 문서를 찾아서 바꾸려면 MongoCollection 클래스의 findOneAndReplace() 메서드를 사용합니다. findOneAndReplace() 메서드는 찾은 문서를 반환하거나 쿼리와 일치하는 문서가 없는 경우 null 을 반환합니다.
예시
다음 예제에서는 findOneAndReplace() 메서드를 사용하여 color 필드가 "green" 로 설정된 문서를 찾아 다음 문서로 바꿉니다.
{"music": "classical", "color": "green"}또한 FindOneAndReplaceOptions 인스턴스를 사용하여 반환된 문서가 대체 작업 후의 상태여야 함을 지정합니다.
// <MongoCollection set up code here>
// Creates instructions to replace the matching document with a new documentBson filter = Filters.eq("color", "green");Document replace = new Document("music", "classical").append("color", "green");
// Defines options specifying that the operation should return a document in its post-operation stateFindOneAndReplaceOptions options = new FindOneAndReplaceOptions(). returnDocument(ReturnDocument.AFTER);
// Atomically finds and replaces the matching document and prints the replacement documentDocument result = collection.findOneAndReplace(filter, replace, options);System.out.println(result.toJson());앞의 코드의 출력은 다음과 유사합니다.
{"_id": 1, "music": "classical", "color": "green"}이 섹션에 언급된 메서드 및 클래스에 대한 자세한 내용은 다음 API 문서를 참조하세요.
찾기 및 삭제
하나의 문서를 찾아 삭제하려면 MongoCollection 클래스의 findOneAndDelete() 메서드를 사용합니다. findOneAndDelete() 메서드는 찾은 문서를 반환하거나 쿼리와 일치하는 문서가 없는 경우 null 을 반환합니다.
예시
다음 예제에서는 findOneAndDelete() 메서드를 사용하여 _id 필드에서 가장 큰 값을 가진 문서를 찾아 삭제합니다.
이 예제에서는 FindOneAndDeleteOptions 인스턴스를 사용하여 _id 필드에 내림차순 정렬을 지정합니다.
// <MongoCollection set up code here>Bson sort = Sorts.descending("_id");
// Creates an empty filter to match all documents in the collectionBson filter = Filters.empty();
// Defines options that specify a descending sort on the "_id" fieldFindOneAndDeleteOptions options = new FindOneAndDeleteOptions(). sort(sort);
// Deletes the document containing the highest "_id" value and prints the deleted documentDocument result = collection.findOneAndDelete(filter, options);System.out.println(result.toJson());앞의 코드의 출력은 다음과 유사합니다.
{"_id": 2, "food": "pear", "color": "yellow"}Sorts 클래스에 대한 자세한 내용은 정렬 빌더 가이드를 참조하세요.
이 섹션에 언급된 메서드 및 클래스에 대한 자세한 내용은 다음 API 문서를 참조하세요.
경쟁 상태 방지
이 섹션에서는 두 가지 예를 살펴봅니다. 첫 번째 예에는 경쟁 상태가 포함되어 있고, 두 번째 예에는 첫 번째 예에 있는 경쟁 상태를 피하기 위해 복합 연산을 사용합니다.
두 예제 모두에서, 우리가 방이 하나인 호텔을 운영하고 있고 이 방을 게스트에게 체크아웃하는 데 도움이 되는 작은 Java 프로그램을 가지고 있다고 가정해 보겠습니다.
MongoDB의 다음 문서는 채팅방을 나타냅니다.
{"_id": 1, "guest": null, "room": "Blue Room", "reserved": false}이 예제의 전체 코드는 여기 Github에서 확인할 수 있습니다.
경쟁 상태가 있는 예제
앱이 이 bookARoom 메서드를 사용하여 게스트에게 객실을 체크아웃한다고 가정해 보겠습니다.
public void bookARoom() { // Creates a filter to match documents representing available rooms Bson filter = Filters.eq("reserved", false);
// Retrieves a document that represents the first available room Document myRoom = this.collection.find(filter).first();
// Prints a message if no documents representing available rooms are found if (myRoom == null){ System.out.println("Sorry, we are booked " + this.guest); return; }
String myRoomName = myRoom.getString("room");
// Prints a message that guest that successfully booked the room System.out.println("You got the " + myRoomName + " " + this.guest);
// Creates an update document to mark a room as reserved Bson update = Updates.combine(Updates.set("reserved", true), Updates.set("guest", guest)); // Creates a filter that matches the "_id" field of the first available room Bson roomFilter = Filters.eq("_id", myRoom.get("_id", Integer.class));
// Updates the first matching document to mark it as reserved this.collection.updateOne(roomFilter, update);}별도의 두 게스트 잔과 펫이 동시에 이 방법으로 객실을 예약하려고 한다고 가정해 보겠습니다.
잔은 다음 출력을 확인합니다.
You got the Blue Room Jan그리고 패트릭은 다음 출력을 확인합니다.
You got the Blue Room Pat데이터베이스를 살펴보면 다음과 같습니다.
{"_id": 1, "guest": "Jan", "room": "Blue Room", "reserved": true}펫은 불행할 것입니다. 패트가 우리 호텔에 나타날 때, 잔은 그녀의 방을 사용할 것입니다. 무엇이 잘못되었나요?
다음은 MongoDB 인스턴스의 관점에서 발생한 이벤트의 일련입니다.
1월의 빈 방 찾기 및 반환
패를 위한 빈 방 찾기 및 반환
Pat의 객실 예약으로 업데이트합니다
1월에 예약된 객실을 업데이트합니다.
잠시 동안 태선씨가 방을 예약했지만 잔의 업데이트 작업이 마지막으로 실행된 문서였으므로 "Jan" 이 게스트로 있습니다.
경쟁 조건이 없는 예제
복합 연산을 사용하여 경쟁 상태를 피하고 항상 사용자에게 올바른 메시지를 제공합시다.
public void bookARoom(){ // Creates an update document to mark a room as reserved Bson update = Updates.combine(Updates.set("reserved", true), Updates.set("guest", guest)); // Creates a filter to match a document representing an available room Bson filter = Filters.eq("reserved", false);
// Updates the first document that matches the filter to mark it as reserved Document myRoom = this.collection.findOneAndUpdate(filter, update); // Prints a message when there are no available rooms if (myRoom == null){ System.out.println("Sorry, we are booked " + this.guest); return; }
// Prints the name of the guest that successfully booked the room String myRoomName = myRoom.getString("room"); System.out.println("You got the " + myRoomName + " " + this.guest);}별도의 두 게스트 잔과 펫이 동시에 이 방법으로 객실을 예약하려고 한다고 가정해 보겠습니다.
잔은 다음 출력을 확인합니다.
You got the Blue Room Jan그리고 패트릭은 다음 출력을 확인합니다.
Sorry, we are booked Pat데이터베이스를 살펴보면 다음과 같습니다.
{"_id":1, "guest":"Jan", "room":"Blue Room", "reserved":true}Pat이 올바른 메시지를 받았습니다. 그녀는 예약을 하지 못해 아쉬울 수도 있지만, 적어도 우리 호텔로 오지 않아도 된다는 것을 알고 있습니다.
다음은 MongoDB 인스턴스의 관점에서 발생한 이벤트의 일련입니다.
1월의 빈 자리를 찾아 예약합니다.
태선씨를 위한 빈 자리를 찾아 예약해 보세요. 남은 방이 없으므로
null을 반환합니다.
중요
쓰기 락
MongoDB 인스턴스는 복합 작업 기간 동안 수정하려는 문서에 쓰기 잠금(write lock)을 설정합니다.
Updates 클래스에 대한 자세한 내용 은 업데이트 빌더 가이드를 참조하세요.
Filters 클래스에 대한 자세한 내용은 필터 빌더 가이드를 참조하세요.
findOneAndUpdate() 메서드에 대한 자세한 내용은 MongoCollection 클래스에 대한 API 설명서를 참조하세요.