DB.withTransaction
est ce que vous voulez. Tout comme DB.withConnection
, il provisionnera une seule connexion à partir du pool de connexions pour toutes les fonctions SQL contenues. Puisque vous voulez utiliser une transaction par requête, il semble que cela aurait plus de sens de l'appeler dans la fonction de contrôleur, et d'exiger que toutes vos fonctions de modèle aient un paramètre de connexion implicite.
Modèle:
object Product {
def checkInventory(id: Long)(implicit c: Connection): Int = SQL(...)
def decrementInventory(id: Long, quantity: Int)(implicit c: Connection): Boolean = SQL(...)
}
object Cart {
def addItem(id: Long, quantity: Int)(implicit c: Connection): Boolean = SQL(...)
}
fonction contrôleur:
def addToCart(id: Long, quantity: Int) = Action {
DB.withTransaction{ implicit connection =>
if(Product.checkInventory(id) >= quantity && Product.decrementInventory(id, quantity)) {
Cart.addItem(id, quantity)
....
} else {
BadRequest
}
}
}
Avertissement: Ceci est clairement pas une transaction de panier logiquement son, et une simple illustration de l'utilisation des transactions de base de données.
Après Action
exemples de composition dans le documentation, vous pouvez faire une action Transaction
spéciale que les dispositions de la transaction pour chaque demande automatiquement:
object Transaction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
DB.withTransaction{implicit connection => block(request)}
}
}
et de l'utiliser comme Action
:
def addToCart(id: Long, quantity: Int) = Transaction {
Product.checkInventory(id)
...
}
Pièges: Fournir une transaction par requête de cette manière est pratique, en particulier lorsque la plupart de vos contro Les fonctions ller sont censées représenter les actions atomiques. Toutefois, cette méthode ne libère pas le Connection
de la transaction tant que le Result
n'a pas été renvoyé à l'utilisateur. Cela signifie que si vous renvoyez un grand ensemble de données qui prend beaucoup de temps à servir/restituer pour le client, vous conserverez la connexion pendant plus longtemps que vous n'en avez réellement besoin.
Vous devez spécifier au moins quelle approche DB utiliser et dans quelle langue (Java/Scala) – biesior
J'utilise Scala avec Anorm db library. – vbezhenar
Je m'attendais à une solution plus générale sans avoir besoin de modifier les contrôleurs, mais probablement il n'existe pas. Je vais vérifier votre réponse. – vbezhenar