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)

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️