tamuraです。

今回はDropwizardでデータベースの更新を行っていきます。


DAOの修正

DAOにUPDATEメソッドを追加します。

package com.github.tamurashingo.dropwizard.helloworld.dao;

import org.skife.jdbi.v2.sqlobject.mixins.Transactional;

import com.github.tamurashingo.dropwizard.helloworld.Saying;  
import com.google.common.base.Optional;

public interface MessageDAO extends Transactional<MessageDAO> {

    public Optional<Saying> getMessage(String messageId);

    public void updateMessage(String messageId, String message);

}

続いてMySQL用の実装にSQLを追加します。

package com.github.tamurashingo.dropwizard.helloworld.dao.impl;

import org.skife.jdbi.v2.sqlobject.Bind;  
import org.skife.jdbi.v2.sqlobject.SqlQuery;  
import org.skife.jdbi.v2.sqlobject.SqlUpdate;  
import org.skife.jdbi.v2.sqlobject.customizers.Mapper;  
import org.skife.jdbi.v2.sqlobject.customizers.SingleValueResult;

import com.github.tamurashingo.dropwizard.helloworld.Saying;  
import com.github.tamurashingo.dropwizard.helloworld.dao.MessageDAO;  
import com.github.tamurashingo.dropwizard.helloworld.dao.impl.mapper.SayingMapper;  
import com.google.common.base.Optional;

public interface MessageDAOMySQLImpl extends MessageDAO {

    @Override
    @SingleValueResult(Saying.class)
    @SqlQuery(
              " select "
            + "   message "
            + " from "
            + "   m_message "
            + " where "
            + "   id = :messageId "
    )
    @Mapper(SayingMapper.class)
    public Optional<Saying> getMessage(@Bind("messageId") String messageId);

    @Override
    @SqlUpdate(
              " update "
            + "   m_message "
            + " set "
            + "   message = :message "
            + " where "
            + "   id = :messageId "
    )
    public void updateMessage(@Bind("messageId") String messageId, @Bind("message") String message);
}

Resourceの修正

POSTでデータベースを更新する処理を追加します。 今回は単純な更新なのであまりトランザクションの意味はないのですが、このようにして書くことができます。

messageというパラメータに新しいメッセージをセットします。
ID:00001のレコードを更新するようにしています。

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Saying updateHello(MultivaluedMap<String, String> formParams) {  
    final String message = formParams.getFirst("message");

    messageDAO.inTransaction(new Transaction<Void, MessageDAO>() {
        @Override
        public Void inTransaction(MessageDAO transactional, TransactionStatus status) throws Exception {
            messageDAO.begin();
            messageDAO.updateMessage("00001", message);
            messageDAO.commit();
            return null;
        }
    });

    return sayHello(Optional.of("00001"));
}

Configurationの修正

MySQLは初期モードが自動コミットになっているので、それを外しておきます。

database:  
  driverClass: com.mysql.jdbc.Driver
  user: root
  password: password
  (...省略...)
  autoCommitByDefault: false

実行

POSTを使うので、cUrlで実行します。

$ curl -d message=new\\ message -i -L http://localhost:8080/hello-world
HTTP/1.1 200 OK  
Date: Fri, 12 Jun 2015 14:50:18 GMT  
Content-Type: application/json  
Content-Length: 26  
Cache-Control: proxy-revalidate  
Proxy-Connection: Keep-Alive  
Connection: Keep-Alive

{"greeting":"new message"}

無事更新できました。

また、MySQLのコマンドラインツールからトランザクションを使って更新をしている最中に動かすと、Dropwizard側の処理がストップします。

mysql> start transaction;  
Query OK, 0 rows affected (0.00 sec)

mysql> update m_message set message = 'hello' where id = '00001';  
Query OK, 1 row affected (0.00 sec)  
Rows matched: 1  Changed: 1  Warnings: 0  

この状態でcUrlを使うとMySQLコマンドラインからcommitrollbackを行うまで返ってこなくなります。

$ curl -d message=new\\ new\\ message -i -L http://localhost:8080/hello-world

返ってきません。

mysql> commit;  
Query OK, 0 rows affected (0.00 sec)  

コミットすると返ってきます。

$ curl -d message=new\\ new\\ message -i -L http://localhost:8080/hello-world
HTTP/1.1 200 OK  
Date: Fri, 12 Jun 2015 14:59:16 GMT  
Content-Type: application/json  
Content-Length: 30  
Cache-Control: proxy-revalidate  
Proxy-Connection: Keep-Alive  
Connection: Keep-Alive

{"greeting":"new new message"}

次回予告

今回はひとつのDAOでトランザクションを制御しました。 次回は複数のDAOでトランザクション制御をやっていきます。