Play frameworkでisucon2アプリを書く-6

このエントリはPlay frameworkひとりアドベントカレンダーの21日目です。

今日はいよいよ /buy を実装します。

今日も昨日までと同じ流れでいきましょう。

  1. 元コードを見てcontrollerのinput/outputとviewのinput/outputを確認
  2. modelを作る
  3. viewを作る
  4. controllerを作る(TODOでよい)
  5. 表示確認
  6. controllerを作りこむ

元コード

post '/buy' => sub {
    my ($self, $c) = @_;
    my $variation_id = $c->req->param('variation_id');
    my $member_id = $c->req->param('member_id');

    my $txn = $self->dbh->txn_scope();
    $self->dbh->query(
        'INSERT INTO order_request (member_id) VALUES (?)',
        $member_id,
    );
    my $order_id = $self->dbh->last_insert_id;
    my $rows = $self->dbh->query(
        'UPDATE stock SET order_id = ? WHERE variation_id = ? AND order_id IS NULL ORDER BY RAND() LIMIT 1',
        $order_id, $variation_id,
    );
    if ($rows > 0) {
        my $seat_id = $self->dbh->select_one(
            'SELECT seat_id FROM stock WHERE order_id = ? LIMIT 1',
            $order_id,
        );
        $txn->commit;
        $c->render('complete.tx', { seat_id => $seat_id, member_id => $member_id });
    } else {
        $txn->rollback;
        $c->render('soldout.tx');
    }
};

model, viewは淡々と作ればokです。

controllerのポイントは2点。

  • POSTでデータを受け取る
  • トランザクションを使った更新処理

POSTでデータを受け取る

request().body().asFormUrlEncoded() を使いましょう。

素朴でrawな感じですが、これでいいにしましょう。

トランザクションを使った更新処理

Ebean を使います。
Ebean.beginTransaction() , Ebean.commitTransaction() , Ebean.rollbackTransaction() , Ebean.endTransaction() でトランザクションしましょう。

	public static Result buy() {
		Map requestBody = request().body().asFormUrlEncoded();

		String variationId = requestBody.containsKey("variation_id") ? requestBody
				.get("variation_id")[0] : "";
		String memberId = requestBody.containsKey("member_id") ? requestBody
				.get("member_id")[0] : "";

		Ebean.beginTransaction();
		OrderRequest orderRequest = new OrderRequest();
		orderRequest.memberId = memberId;
		orderRequest.save();

		Stock stock = Stock.find.where().eq("variation_id", variationId)
				.isNull("order_id").orderBy("RAND()").findList().get(0);
		stock.orderId = orderRequest.id;
		stock.save();

		try {
			Ebean.commitTransaction();
			Ebean.endTransaction();
		} catch (Exception e) {
			Ebean.rollbackTransaction();
			Ebean.endTransaction();
			return ok(views.html.soldout.render());
		}
		String seatId = Stock.find.where()
				.eq("order_id", orderRequest.id.toString()).findList().get(0).seatId;
		return ok(views.html.buy.render(seatId, memberId));

	}

できました?これでひと通り動作できるようになりました。
明日は画面左側の recent_sold を実装しましょう。


See also