 includes/database/mysql/query.inc |   14 ++++++++
 includes/database/query.inc       |   64 +++++++++++++++++++------------------
 modules/system/system.install     |    2 -
 3 files changed, 47 insertions(+), 33 deletions(-)

diff --git includes/database/mysql/query.inc includes/database/mysql/query.inc
index bf71ddc..0516876 100644
--- includes/database/mysql/query.inc
+++ includes/database/mysql/query.inc
@@ -89,6 +89,14 @@ class MergeQuery_mysql extends MergeQuery {
 
   public function execute() {
 
+    // ON DUPLICATE KEY UPDATE in MySQL doesn't behave the right way if there
+    // is more than one key field. If so, fall back to the slower generic
+    // version.  When there is only a single key field, it behaves the same
+    // as the generic version but is faster and more atomic.
+    //if (count($this->keyFields) > 1) {
+      return parent::execute();
+    //}
+
     // A merge query without any key field is invalid.
     if (count($this->keyFields) == 0) {
       throw new InvalidMergeQueryException("You need to specify key fields before executing a merge query");
@@ -144,6 +152,12 @@ class MergeQuery_mysql extends MergeQuery {
 
   public function __toString() {
 
+    // We need to fall back to the generic implementation for both execute()
+    // and __toString() separately.
+    //if (count($this->keyFields) > 1) {
+      return parent::__toString();
+    //}
+
     // Set defaults.
     if ($this->updateFields) {
       $update_fields = $this->updateFields;
diff --git includes/database/query.inc includes/database/query.inc
index e481cdf..50466b7 100644
--- includes/database/query.inc
+++ includes/database/query.inc
@@ -779,45 +779,47 @@ class MergeQuery extends Query {
       $select->condition($field, $value);
     }
 
-    $select = $select->countQuery();
-    $sql = (string) $select;
+    // Using SELECT FOR UPDATE syntax will lock the rows we want to attempt to update.
+    $sql = ((string) $select) . ' FOR UPDATE';
     $arguments = $select->getArguments();
-    $num_existing = $this->connection->query($sql, $arguments)->fetchField();
 
-
-    if ($num_existing) {
-      // If there is already an existing record, run an update query.
-
-      if ($this->updateFields) {
-        $update_fields = $this->updateFields;
-      }
-      else {
-        $update_fields = $this->insertFields;
-        // If there are no exclude fields, this is a no-op.
-        foreach ($this->excludeFields as $exclude_field) {
-          unset($update_fields[$exclude_field]);
+    try {
+      // If there are already existing records, run an update query.
+      if ($this->connection->query($sql, $arguments)->fetch()) {
+        if ($this->updateFields) {
+          $update_fields = $this->updateFields;
         }
-      }
-      if ($update_fields || $this->expressionFields) {
-        // Only run the update if there are no fields or expressions to update.
-        $update = $this->connection->update($this->table, $this->queryOptions)->fields($update_fields);
-        foreach ($this->keyFields as $field => $value) {
-          $update->condition($field, $value);
+        else {
+          $update_fields = $this->insertFields;
+          // If there are no exclude fields, this is a no-op.
+          foreach ($this->excludeFields as $exclude_field) {
+            unset($update_fields[$exclude_field]);
+          }
         }
-        foreach ($this->expressionFields as $field => $expression) {
-          $update->expression($field, $expression['expression'], $expression['arguments']);
+        if ($update_fields || $this->expressionFields) {
+          // Only run the update if there are no fields or expressions to update.
+          $update = $this->connection->update($this->table, $this->queryOptions)->fields($update_fields);
+          foreach ($this->keyFields as $field => $value) {
+            $update->condition($field, $value);
+          }
+          foreach ($this->expressionFields as $field => $expression) {
+            $update->expression($field, $expression['expression'], $expression['arguments']);
+          }
+          $update->execute();
+          return MergeQuery::STATUS_UPDATE;
         }
-        $update->execute();
-        return MergeQuery::STATUS_UPDATE;
+      }
+      else {
+        // If there is no existing record, run an insert query.
+        $insert_fields = $this->insertFields + $this->keyFields;
+        $this->connection->insert($this->table, $this->queryOptions)->fields($insert_fields)->execute();
+        return MergeQuery::STATUS_INSERT;
       }
     }
-    else {
-      // If there is no existing record, run an insert query.
-      $insert_fields = $this->insertFields + $this->keyFields;
-      $this->connection->insert($this->table, $this->queryOptions)->fields($insert_fields)->execute();
-      return MergeQuery::STATUS_INSERT;
+    catch (Exception $e) {
+      $transaction->rollback();
+      return FALSE;
     }
-
     // Transaction commits here where $transaction looses scope.
   }
 
diff --git modules/system/system.install modules/system/system.install
index 0d73c64..0693dd5 100644
--- modules/system/system.install
+++ modules/system/system.install
@@ -1393,8 +1393,6 @@ function system_schema() {
     'indexes' => array(
       'timestamp' => array('timestamp'),
       'uid' => array('uid'),
-    ),
-    'unique keys' => array(
       'ssid' => array('ssid'),
     ),
     'foreign keys' => array(
