Cain (6-6) went five innings, allowing two runs on four hits over five innings to record his first triumph since June 13, a span of six starts. The right-hander walked four and struck out four.
George Kontos, Jeremy Affeldt, Jose Mijares, Santiago Casilla, Sandy Rosario and Javier Lopez teamed up for three scoreless relief innings. Sergio Romo notched his 23rd save despite allowing a run in the ninth for the Giants.
The Diamondbacks' Wade Miley (6-8) was saddled with the loss after surrendering two runs on four hits in four innings.
Martin Prado provided two RBI for Arizona, which saw its divisional lead over second-place Los Angeles shrink to one-half game with a third straight loss overall.