tamuraです。
 

今回はDropwizardで複数のDAOを使った場合のトランザクション制御をやって行きます。



構成の変更

AbstractDAOの作成

DAOの中で別のDAOを生成できるように、基底クラスを作ります。 またトランザクション制御を行えるようにしてあります。

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

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

public abstract class AbstractDAO implements Transactional<AbstractDAO> {

    @CreateSqlObject
    public abstract MessageDAO createMessageDAO();
}

MessageDAOの変更

今まであったMessageDAOinterfaceからabstract classに変更します。 あと、今まで実装(?)はMessageDAOMySQLImplで行っていたのですが、ちょっとうまくできなかったのでこのクラスでSQLを実装しています。

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

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.mapper.SayingMapper;
import com.google.common.base.Optional;

public abstract class MessageDAO extends AbstractDAO {

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

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

HelloWorldResourceの変更

まずはコンストラクタでAbstractDAOを受け取ります。

@Path("/hello-world")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {

    private AbstractDAO dao;
    private Saying defaultValue = new Saying("hello world");

    public HelloWorldResource(AbstractDAO dao) {
        this.dao = dao;
    }

つぎにsayHelloメソッドを変更します。 今までMessageDAOをそのまま使っていましたが、AbstractDAO#createMessageDAOMessageDAOを生成するようにします。

    @GET
    public Saying sayHello(@QueryParam("messageid") Optional<String> messageId) {
        if (messageId.isPresent()) {
            MessageDAO messageDAO = dao.createMessageDAO();
            return messageDAO.getMessage(messageId.get()).or(defaultValue);
        }
        else {
            return defaultValue;
        }
    }

updateHelloも同じように変更します。

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

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

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

HelloWorldApplicationの変更

HelloWorldResourceの呼び出し方を変更します。 具体的にはAbstractDAOを渡すように変更しています。

    @Override
    public void run(HelloWorldConfiguration configuration, Environment environment) throws Exception {
        final DBIFactory factory = new DBIFactory();
        final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "helloworlddb");
        final AbstractDAO dao = jdbi.onDemand(AbstractDAO.class);

        environment.jersey().register(new HelloWorldResource(dao));
    }

これで実行すると、前回と同じ結果が得られます。

テーブルの追加

migrations.xmlを使ってテーブルを追加します。 M_MESSAGEを更新した際にバックアップを格納するテーブルです。

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

  <changeSet id="1" author="tamura.shingo">
    <createTable tableName="m_message">
      <column name="id" type="char(5)">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="message" type="varchar(255)" />
    </createTable>
  </changeSet>

  <changeSet id="2" author="tamura.shingo">
    <insert tableName="m_message">
      <column name="id" value="00001" />
      <column name="message" value="hello" />
    </insert>
    <insert tableName="m_message">
      <column name="id" value="00002" />
      <column name="message" value="こんにちは" />
    </insert>
    <insert tableName="m_message">
      <column name="id" value="00003" />
      <column name="message" value="bonjour" />
    </insert>
  </changeSet>

  <changeSet id="3" author="tamura.shingo">
    <createTable tableName="h_message">
      <column name="history_id" type="BIGINT" autoIncrement="true">
        <constraints primaryKey="true" nullable="false" />
      </column>
      <column name="id" type="char(5)" />
      <column name="message" type="varchar(255)" />
      <column name="updateDate" type="datetime" />
    </createTable>
  </changeSet>
</databaseChangeLog>

これをマイグレーションします。

$ java -jar target/helloworld-0.0.1-SNAPSHOT.jar db migrate hello-world.yml
INFO  [2015-06-12 15:16:17,876] liquibase: Successfully acquired change log lock
INFO  [2015-06-12 15:16:18,351] liquibase: Reading from helloworld.DATABASECHANGELOG
INFO  [2015-06-12 15:16:18,384] liquibase: migrations.xml: 3::tamura.shingo: Table h_message created
INFO  [2015-06-12 15:16:18,385] liquibase: migrations.xml: 3::tamura.shingo: ChangeSet migrations.xml::3::tamura.shingo ran successfully in 9ms
INFO  [2015-06-12 15:16:18,395] liquibase: Successfully released change log lock

DAOの追加

このH_MESSAGEを処理するDAOを作っていきます。 こんな感じです。

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

import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;

public abstract class HistoryDAO extends AbstractDAO {

    @SqlUpdate(
            " insert into "
          + "   h_message "
          + " ( "
          + "   id, "
          + "   message, "
          + "   updateDate "
          + " ) "
          + " values ( "
          + "   :messageId, "
          + "   :message, "
          + "   now() "
          + " ) "
    )
    public abstract void backupMessage(@Bind("messageId") String messageId, @Bind("message") String message);

}

また、AbstractDAOにこのHistoryDAOを生成する処理を追加しておきます。

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

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

public abstract class AbstractDAO implements Transactional<AbstractDAO> {

    @CreateSqlObject
    public abstract MessageDAO createMessageDAO();

    @CreateSqlObject
    public abstract HistoryDAO createHistoryDAO();
}

メインロジック

以下の要領で作っていきます。

  • 00001messageを更新
  • m_messageに既存の値があった場合は、h_messageに入れる
  • exceptionという更新値がきた場合は例外を発生させる(rollbackの確認用)
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Saying updateHello(MultivaluedMap<String, String> formParams) {
        final String message = formParams.getFirst("message");

        dao.inTransaction(new Transaction<Void, AbstractDAO>() {

            @Override
            public Void inTransaction(AbstractDAO transactional, TransactionStatus status) throws Exception {
                transactional.begin();
                MessageDAO messageDAO = transactional.createMessageDAO();
                Optional<Saying> oldMessage = messageDAO.getMessage("00001");
                if (oldMessage.isPresent()) {
                    Saying oldMessageContent = oldMessage.get();
                    HistoryDAO historyDAO = transactional.createHistoryDAO();
                    historyDAO.backupMessage("00001", oldMessageContent.getGreeting());
                }

                messageDAO.updateMessage("00001", message);

                if (Objects.equal(message, "exception")) {
                    throw new Exception("このタイミングで例外かよ。。。。");
                }

                transactional.commit();
                return null;
            }
        });

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

これで完成です。

実行

起動します。

$ java -jar target/helloworld-0.0.1-SNAPSHOT.jar server hello-world.yml
INFO  [2016-07-13 17:48:58,904] org.eclipse.jetty.util.log: Logging initialized @798ms
INFO  [2016-07-13 17:48:59,032] io.dropwizard.server.ServerFactory: Starting HelloWorldApplication
INFO  [2016-07-13 17:48:59,073] org.eclipse.jetty.setuid.SetUIDListener: Opened application@ab7a938{HTTP/1.1}{0.0.0.0:8080}
INFO  [2016-07-13 17:48:59,074] org.eclipse.jetty.setuid.SetUIDListener: Opened admin@3faf2e7d{HTTP/1.1}{0.0.0.0:8081}
INFO  [2016-07-13 17:48:59,076] org.eclipse.jetty.server.Server: jetty-9.2.z-SNAPSHOT
INFO  [2016-07-13 17:48:59,674] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:

    GET     /hello-world (com.github.tamurashingo.dropwizard.helloworld.HelloWorldResource)
    POST    /hello-world (com.github.tamurashingo.dropwizard.helloworld.HelloWorldResource)

INFO  [2016-07-13 17:48:59,678] org.eclipse.jetty.server.handler.ContextHandler: Started i.d.j.MutableServletContextHandler@359b650b{/,null,AVAILABLE}
INFO  [2016-07-13 17:48:59,683] io.dropwizard.setup.AdminEnvironment: tasks =

    POST    /tasks/log-level (io.dropwizard.servlets.tasks.LogConfigurationTask)
    POST    /tasks/gc (io.dropwizard.servlets.tasks.GarbageCollectionTask)

INFO  [2016-07-13 17:48:59,687] org.eclipse.jetty.server.handler.ContextHandler: Started i.d.j.MutableServletContextHandler@46d9aec8{/,null,AVAILABLE}
INFO  [2016-07-13 17:48:59,739] org.eclipse.jetty.server.ServerConnector: Started application@ab7a938{HTTP/1.1}{0.0.0.0:8080}
INFO  [2016-07-13 17:48:59,752] org.eclipse.jetty.server.ServerConnector: Started admin@3faf2e7d{HTTP/1.1}{0.0.0.0:8081}
INFO  [2016-07-13 17:48:59,752] org.eclipse.jetty.server.Server: Started @1647ms

更新

$ curl -d message=GoodAfternoon -i -L http://localhost:8080/hello-world
HTTP/1.1 200 OK
Date: Wed, 13 Jul 2016 17:51:48 GMT
Content-Type: application/json
Content-Length: 28

{"greeting":"GoodAfternoon"}

ログ

0:0:0:0:0:0:0:1 - - [13/7/2016:17:51:48 +0000] "POST /hello-world HTTP/1.1" 200 28 "-" "curl/7.30.0" 10

MySQL

mysql> select * from m_message;
+-------+---------------+
| id    | message       |
+-------+---------------+
| 00001 | GoodAfternoon |
| 00002 | こんにちは    |
| 00003 | bonjour       |
+-------+---------------+
3 rows in set (0.00 sec)

mysql> select * from h_message;
+------------+-------+---------+---------------------+
| history_id | id    | message | updateDate          |
+------------+-------+---------+---------------------+
|          1 | 00001 | hello   | 2016-07-14 02:51:48 |
+------------+-------+---------+---------------------+
1 row in set (0.00 sec)

例外発生

exceptionというキーワードを与えて、内部で例外を発生させてみます。

$ curl -d message=exception -i -L http://localhost:8080/hello-world
HTTP/1.1 500 Internal Server Error
Date: Wed, 13 Jul 2016 17:53:12 GMT
Content-Type: application/json
Content-Length: 110

{"code":500,"message":"There was an error processing your request. It has been logged (ID 1cf9824636cfbf6c)."}

ログ

0:0:0:0:0:0:0:1 - - [13/7/2016:17:53:12 +0000] "POST /hello-world HTTP/1.1" 500 110 "-" "curl/7.30.0" 11
ERROR [2016-07-13 17:53:12,657] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: 1cf9824636cfbf6c
! java.lang.Exception: このタイミングで例外かよ。。。。
! at com.github.tamurashingo.dropwizard.helloworld.HelloWorldResource$1.inTransaction(HelloWorldResource.java:66) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at com.github.tamurashingo.dropwizard.helloworld.HelloWorldResource$1.inTransaction(HelloWorldResource.java:50) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.sqlobject.InTransactionHandler$1.inTransaction(InTransactionHandler.java:37) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.tweak.transactions.LocalTransactionHandler.inTransaction(LocalTransactionHandler.java:184) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! ... 62 common frames omitted
! Causing: org.skife.jdbi.v2.exceptions.TransactionFailedException: Transaction failed do to exception being thrown from within the callback. See cause for the original exception.
! at org.skife.jdbi.v2.tweak.transactions.LocalTransactionHandler.inTransaction(LocalTransactionHandler.java:195) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.BasicHandle.inTransaction(BasicHandle.java:327) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.sqlobject.InTransactionHandler.invoke(InTransactionHandler.java:32) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.sqlobject.SqlObject.invoke(SqlObject.java:175) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.skife.jdbi.v2.sqlobject.SqlObject$1.intercept(SqlObject.java:75) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at com.github.tamurashingo.dropwizard.helloworld.dao.AbstractDAO$$EnhancerByCGLIB$$631a84fe.inTransaction(<generated>) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at com.github.tamurashingo.dropwizard.helloworld.HelloWorldResource.updateHello(HelloWorldResource.java:50) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_31]
! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_31]
! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_31]
! at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_31]
! at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:164) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:181) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:203) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:101) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:305) ~[helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.internal.Errors.process(Errors.java:267) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:288) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1110) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:401) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:386) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:222) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:49) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:300) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.jetty.BiDiGzipFilter.doFilter(BiDiGzipFilter.java:134) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:29) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:44) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:39) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:240) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:51) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:95) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:159) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.Server.handle(Server.java:497) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) [helloworld-0.0.1-SNAPSHOT.jar:na]
! at java.lang.Thread.run(Thread.java:745) [na:1.8.0_31]

MySQL

ちゃんとrollbackされていました。

mysql> select * from m_message;
+-------+---------------+
| id    | message       |
+-------+---------------+
| 00001 | GoodAfternoon |
| 00002 | こんにちは    |
| 00003 | bonjour       |
+-------+---------------+
3 rows in set (0.00 sec)

mysql> select * from h_message;
+------------+-------+---------+---------------------+
| history_id | id    | message | updateDate          |
+------------+-------+---------+---------------------+
|          1 | 00001 | hello   | 2016-07-14 02:51:48 |
+------------+-------+---------+---------------------+
1 row in set (0.00 sec)

まとめ

以下の方法でDropwizard JDBIで複数のDAOを扱うことができました。

  • AbstractDAOで各DAOを生成するメソッドを宣言する
  • 各DAOはAbstractDAOを基底クラスにする