かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Gradle で Multi-project を作成する ( その11 )( doma2lib+cmdapp+webapp編、log4jdbc-log4j2 を導入してトランザクションが有効なことを確認する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その10 )( doma2lib+cmdapp+webapp編、sample-cmdapp プロジェクトを作成する2 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Doma 2 の Entity、Dao を提供するライブラリ+Spring Boot ベースのコマンドラインアプリケーション+Spring Boot ベースの Web アプリケーションの Multi-project を作成します。
    • ksbysample.app.samplecmdapp.EmployeeDataCsvToDbLoader#run メソッドに @Transactional アノテーションを付与してトランザクションが有効になるように設定したつもりでいましたが、log4jdbc-log4j2 を導入して本当に有効になっているのかを確認します。

参照したサイト・書籍

目次

  1. gradle-multiprj-doma2lib-cmdwebapp の build.gradle を変更する
  2. doma2-lib の src/main/resources の下に application-develop.properties、application-product.properties を作成する
  3. doma2-lib の db-product.properties と同じ内容を db-develop.properties に記述する
  4. EmployeeDataCsvToDbLoaderTest クラスでトランザクションが有効か確認する
  5. java.sql.SQLSyntaxErrorException: SELECT command denied to user 'sampledb_user'@'172.18.0.1' for table 'user_variables_by_thread' を解消する
  6. sample-cmdapp をコマンドラインから実行した時にトランザクションが有効か確認する

手順

gradle-multiprj-doma2lib-cmdwebapp の build.gradle を変更する

gradle-multiprj-doma2lib-cmdwebapp の build.gradle の configure に log4jdbc-log4j2 を利用するための com.integralblue:log4jdbc-spring-boot-starter を依存関係に追加します。

..........

configure(subprojects.findAll { it.name ==~ /^(doma2-lib|sample-cmdapp)$/ }) {
    apply plugin: "org.springframework.boot"

    dependencyManagement {
        imports {
            mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
        }
    }

    ext {
        jdbcDriver = "mysql:mysql-connector-java:8.0.15"
        domaVersion = "2.24.0"
    }
    
    dependencies {
        def lombokVersion = "1.18.6"

        testImplementation("org.springframework.boot:spring-boot-starter-test")

        runtimeOnly(jdbcDriver)
        implementation("org.seasar.doma.boot:doma-spring-boot-starter:1.1.1")
        implementation("org.seasar.doma:doma:${domaVersion}")
        implementation("org.flywaydb:flyway-core:5.2.4")
        implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2")

        // for lombok
        // testAnnotationProcessor、testCompileOnly を併記しなくてよいよう configurations で設定している
        annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
        compileOnly("org.projectlombok:lombok:${lombokVersion}")
    }

}
  • implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2") を追加します。

doma2-lib の src/main/resources の下に application-develop.properties、application-product.properties を作成する

develop profile の時には log4jdbc-log4j2 でログが出力されるようにし、product profile の時にはログが出力されないようにします。設定ファイルは doma2-lib プロジェクトの下に作成します(ここに作成しても sample-cmdapp に適用されます)。

doma2-lib/src/main/resources の下に application-develop.properties、application-product.properties を新規作成し、以下の内容を記述します。

■application-develop.properties

# log4jdbc-log4j2
logging.level.jdbc.sqlonly=DEBUG
logging.level.jdbc.sqltiming=INFO
logging.level.jdbc.audit=INFO
logging.level.jdbc.resultset=ERROR
logging.level.jdbc.resultsettable=ERROR
logging.level.jdbc.connection=DEBUG

■application-product.properties

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration

doma2-lib の db-product.properties と同じ内容を db-develop.properties に記述する

develop profile ではログが出力され product profile ではログが出力されないことを確認できるようにするために doma2-lib/src/main/resources/db-product.properties の内容を db-develop.properties と同じにします。

■db-product.properties

doma.dialect=mysql

spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost/sampledb?sslMode=DISABLED&characterEncoding=utf8
spring.datasource.hikari.username=sampledb_user
spring.datasource.hikari.password=xxxxxxxx
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.leak-detection-threshold=60000
spring.datasource.hikari.register-mbeans=true

EmployeeDataCsvToDbLoaderTest クラスでトランザクションが有効か確認する

sample-cmdapp/src/test/java/ksbysample/app/samplecmdapp/EmployeeDataCsvToDbLoaderTest.groovy のテストを実行して、employeeDataCsvToDbLoader = (EmployeeDataCsvToDbLoader) context.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(employeeDataCsvToDbLoader, "employeeDataCsvToDbLoader") で手動で Bean に登録した場合にトランザクションが有効か確認します。

テストを実行すると insert 前に Connection.setAutoCommit(false) が呼び出されて、employeeDataCsvToDbLoader.run(...) で2件 insert した後に Connection.commit() が呼び出されていることが確認できました。

f:id:ksby:20190501082847p:plain

わざと RuntimeException を throw して rollback されるかも確認します。 sample-cmdapp/src/main/java/ksbysample/app/samplecmdapp/EmployeeDataCsvToDbLoader.java を以下のように変更します。

@Component
@ConditionalOnProperty(value = {"batch.execute"}, havingValue = "EmployeeDataCsvToDbLoader")
public class EmployeeDataCsvToDbLoader implements CommandLineRunner {

    ..........

    @Override
    @Transactional
    public void run(String... args) throws Exception {
        ..........

        // CSV ファイルを1行ずつ読み込み employee テーブルに insert する
        try (BufferedReader br = Files.newBufferedReader(Paths.get(this.csvfile), StandardCharsets.UTF_8)) {
            Employee employee = new Employee();
            for (EmployeeCsvRecord employeeCsvRecord : routines.iterate(EmployeeCsvRecord.class, br)) {
                modelMapper.map(employeeCsvRecord, employee);
                employeeDao.insert(employee);
                throw new RuntimeException("error");
            }
        }
    }

}
  • throw new RuntimeException("error"); を追加します。

テストを実行すると1件目の insert 文が実行された後に RuntimeException が throw された結果 Connection.rollback() が呼び出されていました。

f:id:ksby:20190501112522p:plain

トランザクションが有効になっていることが確認できました。

また spring.profiles.active=product に変更すると、

@SpringBootTest(properties = ["spring.profiles.active=product"])
class EmployeeDataCsvToDbLoaderTest extends Specification {

log4jdbc-log4j2 のログは出力されなくなりました。

f:id:ksby:20190501115518p:plain

java.sql.SQLSyntaxErrorException: SELECT command denied to user 'sampledb_user'@'172.18.0.1' for table 'user_variables_by_thread' を解消する

上でテストを実行した時に java.sql.SQLSyntaxErrorException: SELECT command denied to user 'sampledb_user'@'172.18.0.1' for table 'user_variables_by_thread' というエラーメッセージが出ていることに気づきました。flyway が performance_schema.user_variables_by_thread テーブルにアクセスしようとして出来なかったために出力されていました。

f:id:ksby:20190501113132p:plain

doma2-lib/src/main/resources/db/init/create_database.sql を以下のように変更します。

create database if not exists sampledb character set utf8mb4 collate utf8mb4_ja_0900_as_cs_ks;

create user 'sampledb_user'@'%' identified by 'xxxxxxxx';
grant all privileges ON sampledb.* to 'sampledb_user'@'%' with grant option;
grant select ON performance_schema.user_variables_by_thread to 'sampledb_user'@'%';
flush privileges;
  • grant select ON performance_schema.user_variables_by_thread to 'sampledb_user'@'%'; を追加します。

コンテナを再起動しても create_database.sql に追加した grant select ON ... 文が実行されなかったので、adminer に root ユーザでログインして直接 SQL 文を実行します。

f:id:ksby:20190501114610p:plain

テストを実行すると今度はエラーメッセージが出力されなくなりました。

f:id:ksby:20190501114827p:plain

sample-cmdapp をコマンドラインから実行した時にトランザクションが有効か確認する

コマンドラインから実行した時もトランザクションが有効になっているか確認します。まずは clean タスク実行 → Rebuild Project 実行 → build タスク実行を行い、sample-cmdapp-1.0.0-RELEASE.jar を build し直します。

f:id:ksby:20190501120220p:plain f:id:ksby:20190501120330p:plain

java -Dspring.profiles.active=develop -Dbatch.execute=EmployeeDataCsvToDbLoader -jar sample-cmdapp-1.0.0-RELEASE.jar -csvfile=D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-doma2lib-cmdwebapp\sample-cmdapp\src\test\resources\employee.csv コマンドを実行すると Connection.commit() が呼び出されています。

f:id:ksby:20190501120835p:plain (.....途中省略.....) f:id:ksby:20190501121125p:plain

sample-cmdapp/src/main/java/ksbysample/app/samplecmdapp/EmployeeDataCsvToDbLoader.javathrow new RuntimeException("error"); を追加してから build し直した後、再度コマンドを実行すると1件目を insert した後 Connection.rollback() が呼び出されていました。

f:id:ksby:20190501121804p:plain

コマンドラインから実行した時もトランザクションが有効になっていることが確認できました。

また -Dspring.profiles.active=product に変更した java -Dspring.profiles.active=product -Dbatch.execute=EmployeeDataCsvToDbLoader -jar sample-cmdapp-1.0.0-RELEASE.jar -csvfile=D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-doma2lib-cmdwebapp\sample-cmdapp\src\test\resources\employee.csv コマンドを実行すると log4jdbc-log4j2 のログは出力されませんでした。

f:id:ksby:20190501122312p:plain f:id:ksby:20190501122422p:plain

履歴

2019/05/01
初版発行。