DEV Community

kaede
kaede

Posted on

Kotlin Springboot -- JPA, hibernate, h2 DB の初期設定に失敗

参考

https://spring.io/guides/tutorials/spring-boot-kotlin/

Spring 公式のチュートリアル


H2 DB を使うメリット

https://m12i.hatenablog.com/entry/2014/10/29/010801

永続的なストレージとしては機能しない。
つまりアプリの起動のたびに初期化される。
組み込みとして追加できる。
( なので psql サーバーを Docker で立てて )
URL ( と認証 ) 書いて接続する手間が省ける。

と書いてあった。

H2 はインメモリの DB らしい。
依存関係を書けばそのまま使えるらしいので導入してみる


Gradle で JPA を同居させて Spring を動かす

Maven の場合は POM に書く

build.gradle.kts の plugins に jpa を追加

  kotlin("plugin.jpa") version "1.6.21"
Enter fullscreen mode Exit fullscreen mode

プラグインとして jpa を使えるようにする


Null でバグる issue 対策

tasks.withType<KotlinCompile> {
  kotlinOptions {
    freeCompilerArgs = listOf("-Xjsr305=strict")
  }
}
Enter fullscreen mode Exit fullscreen mode

コンパイラに指定のオプションをつける


dependencies に h2 を追加

dependencies {
// ...
  runtimeOnly("com.h2database:h2")
}
Enter fullscreen mode Exit fullscreen mode

runtime だけ h2 を動かす
ランタイムっていうのが SpringBootApp が起動して落ちるまでの間と解釈する。


application.properties に H2 用の設定を追加

spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.properties.hibernate.globally_quoted_identifiers_skip_column_definitions = true
Enter fullscreen mode Exit fullscreen mode

application.properties に h2 の設定が必要。

https://m12i.hatenablog.com/entry/2014/10/29/010801

Spring の Hibernate のエンティティマネージャーにこの変数と値が渡されるらしい。

調べたけど全くわからないので、この
globally_quoted_identifiers
globally_quoted_identifiers_skip_column_definitions
2 つの値の true の設定はおまじないとしておく。


Controller とテストを書く

省略


H2 DB を(インメモリの範囲で)永続化させる

allopen をプラグインに追加

エンティティを全てオープンにしておかないと
lazy-fetch が使えないので永続化できないらしい。

  kotlin("plugin.allopen") version "1.6.21"
Enter fullscreen mode Exit fullscreen mode

allopen を plugins に追加して

allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.Embeddable")
    annotation("javax.persistence.MappedSuperclass")
}
Enter fullscreen mode Exit fullscreen mode

Entity, Embeddable, MappedSuperclass,
これらの永続化用のアノテーションも import できるように読み込んでおく


Entity を作成

これを元に DB のテーブルが作成されると予想する。

Controller と並列に Entities.kt というファイルを作り

import javax.persistence.GeneratedValue
import javax.persistence.Id

class Article (
    var title: String,
    var slug: String = title.toSlug(),
    @Id
    @GeneratedValue
    var id: Long? = null)
Enter fullscreen mode Exit fullscreen mode

自動生成の ID と String の Title だけを作る

Javax の Persisitence ( 耐久? ) のライブラリを使う


Repositiry を作成

JPA を使った Driver だと解釈する。

import org.springframework.data.repository.CrudRepository

interface ArticleRepository : CrudRepository<Article, Long> {
  fun findByTitle(title: String): Article?
}
Enter fullscreen mode Exit fullscreen mode

同じく Controller 並列に Repository を作成
findBy{ColumnName}(ColumnName: type) とすることで
JPA を使って値が取れると解釈する


Repository のテストを作成できない

テストでデータをいれるようだ
しかし読み込みが全くうまく行かなかった

DataJpaTest
Class RepositoryTests @Autowired constructor (
    val entityManager: TestEntityManager,
    val articleRepository: ArticleRepository) {
        @Test
        fun `When findByIdOrNull then return Article`() {
            val article = Article("Spring Framework 5.0 goes GA", "2")
            entityManager.persist(article)
            entityManager.flush()
            val found = articleRepository.findByTitle(article.title)
            assertThat(found).isEqualTo(article)
        }
    }
)
Enter fullscreen mode Exit fullscreen mode

まず、import たちのちょくごにこのアノテーションを書いても
Expecting a top level defintion と
トップに宣言しろとエラーがでるし

@Test もエラーがでる関数の書き方が違うと。
関数名がないと言われる。

https://stackoverflow.com/a/51894673

@SpringbootApplication
main で呼ばれているからトップでないと言われているかもしれない?
要検証

Top comments (0)