복합 작업
개요
이 가이드에서는 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
필드를 제외합니다.쿼리와 일치하는 문서가 없는 경우 쿼리 필터에 지정된 문서를 삽입하는 업서트를 지정합니다.
MongoDB 인스턴스에서 이 작업의 최대 실행 시간을 5초로 설정합니다. 작업에 시간이 오래 걸리면
findOneAndUpdate()
메서드에서MongoExecutionTimeoutException
가 발생합니다.
// <MongoCollection set up code here> // Creates a projection to exclude the "_id" field from the retrieved documents Bson 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, permit an upsert and limit execution time FindOneAndUpdateOptions options = new FindOneAndUpdateOptions(). projection(projection). upsert(true). maxTime(5, TimeUnit.SECONDS); // Updates the first matching document with the content of the update document, applying the specified options Document result = collection.findOneAndUpdate(filter, update, options); // Prints the matched document in its state before the operation System.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 document Bson 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 state FindOneAndReplaceOptions options = new FindOneAndReplaceOptions(). returnDocument(ReturnDocument.AFTER); // Atomically finds and replaces the matching document and prints the replacement document Document 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 collection Bson filter = Filters.empty(); // Defines options that specify a descending sort on the "_id" field FindOneAndDeleteOptions options = new FindOneAndDeleteOptions(). sort(sort); // Deletes the document containing the highest "_id" value and prints the deleted document Document 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 설명서를 참조하세요.