   when type in [:percentage_of_time, :percentage_of_actors] do
     name_string = to_string(flag_name)
 
-    find_one_q = from(
-      r in Record,
-      where: r.flag_name == ^name_string,
-      where: r.gate_type == "percentage"
-    )
-
-    out = case db_type() do
-      :postgres -> _put_percentage_postgres(flag_name, gate, find_one_q)
-      :mysql    -> _put_percentage_mysql(flag_name, gate, find_one_q)
-    end
-
-    case out do
-      {:ok, {:ok, result}} ->
-        publish_change(flag_name)
-        {:ok, result}
-      {:error, _} = error ->
-        error
-    end
-  end
-
-
-  def put(flag_name, gate = %Gate{}) do
-    changeset = Record.build(flag_name, gate)
-    options = upsert_options(gate)
-
-    case do_insert(flag_name, changeset, options) do
-      {:ok, flag} ->
-        publish_change(flag_name)
-        {:ok, flag}
-      other ->
-        other
-    end
-  end
-
-
-  defp _put_percentage_postgres(flag_name, gate, find_one_q) do
-    @repo.transaction fn() ->
-      postgres_table_lock!()
+    transaction_fn = case db_type() do
+      :postgres -> &_transaction_with_lock_postgres/1
+      :mysql -> &_transaction_with_lock_mysql/1
+    end
+
+    out = transaction_fn.(fn() ->
+      find_one_q = from(
+        r in Record,
+        where: r.flag_name == ^name_string,
+        where: r.gate_type == "percentage"
+      )
+
       case @repo.one(find_one_q) do
         record = %Record{} ->
           changeset = Record.update_target(record, gate)

          changeset = Record.build(flag_name, gate)
          do_insert(flag_name, changeset)
      end
    end
  end

  defp _put_percentage_mysql(flag_name, gate, find_one_q) do
    @repo.transaction fn() ->
      if mysql_lock!() do
        try do
          case @repo.one(find_one_q) do
            record = %Record{} ->
              changeset = Record.update_target(record, gate)
              do_update(flag_name, changeset)
            nil ->
              changeset = Record.build(flag_name, gate)
              do_insert(flag_name, changeset)
          end
        rescue
          e ->
            @repo.rollback("Exception: #{inspect(e)}")

          {:ok, value} ->
            {:ok, value}
        after
          # This is not guaranteed to run if the VM crashes, but at least the
          # lock gets released when the MySQL client session is terminated.
          mysql_unlock!()
        end
      else
