【SpringBoot入門】 第4回 「サンプルプログラムを読み解こう!(その2)」

こんにちは。タグボート開発チームのワシヅカです。

 

最近冬に備えて少しずつ肥えてきました。越冬の準備です。

今日は、2回目から使っているサンプルプロジェクトのDBアクセス部分を中心に確認していきたいと思います。

 

 

1.ログ出力レベルの変更

…と作業の前に。ログレベルを設定しておきましょう。
下のように変更しておくと、データベースアクセスが発生した際にSQLログを出力してくれます。

application.propertiesに以下の1行を追加しておきましょう。

 

2.「UserRepository.java」を読み解く

それでは、DBアクセス部分を確認していきたいと思います。

まずは、「MainController」クラスの「getAllUsers」メソッドを覗いてみましょう。このメソッドは、たった1行です。

とだけコードが書いてあります。「UserRepository」インターフェースの「findAll」メソッドを呼び出してUSERテーブルからデータ抽出を行っています。また、「MainController」クラスの中で、「@Autowired」アノテーションとともに「UserRepository」インターフェースを宣言することで、「UserRepository」インターフェースは自動的に利用可能な状態になっています。

英語で書かれているコメント行にもそのようなことが書かれていますね。

 

続いて「UserRepository」インターフェースの中身を見てみましょう。

なんと、このインターフェースは中身がほとんど書かれていません。しかしよく見ると「CrudRepository」を継承していることがわかります。実はこの継承がポイントです。継承の階層構造を見てみましょう。

CrudRepositoryにポインタを合わせ、右クリック→[型階層を開く]とすると「型階層」タブにされます。

CrudRepositoryにはたくさんのメソッドがあることが分かります。
saveメソッドにctrlキー押しながらポインタをあわせ、[実装を開く]をクリックしてみましょう。

実際の実装を確認する事ができます。「SimpleJpaRepository」クラスで実装されているようです。細かい実装を追い続けると「AbstractEntityManagerImpl」あたりの深いところまで行ってしまいそうなので、今回はこの先は追いませんが、このような階層構造を引き継ぎながら動いていることが分かります。実はこのデータベース周りの処理はJPA(Java Persistence API)というAPIを利用して実現しています。

サンプルプロジェクトのpom.xmlにも「JPAを使っているよ」と書かれています。

 

 

 

3.条件を付けて検索可能にしてみる(WHERE句)

さて、この「UserRepository」クラスで名前(name)カラムを条件に検索可能なメソッドを定義してみましょう。

以下の1行を追加してください。

また「MainController」クラスには以下のような呼出メソッドを追加します。

 

 

追加し終わったら、アプリケーションを実行してブラウザで以下のURLにアクセスしてみましょう。

http://localhost:8080/demo/user-by-name?name=hogehoge

 

nameカラムに”hogehoge”を持つデータが取得できました。ログも確認してみましょう。

ログにもしっかりWHERE句がついて出力されていますね。なんて簡単で便利なんでしょう!

 

 

4.並び順をつけて検索可能にしてみる(ORDER BY句)

もう1つおまけに、並び順も付けてみましょう。

今度は、名前(nameカラム)を条件にし登録が新しい順(IDが大きい順)で取得できるメソッドを定義してみます。先ほどと同様にUserRepositoryクラスに以下のようにメソッドを定義してあげます。

 

コントロールクラスは、先ほどのメソッドを使ってしまいましょう。

呼出メソッドに「OrderByIdDesc」と追加してあげます。

データベースのデータの状態は以下のような感じです。

先ほどと同じURLを叩くことでデータが取得可能です。

http://localhost:8080/demo/user-by-name?name=hogehoge

 

見事にname=”hogehoge”を条件に、idを降順に並び替えたデータを取得することができました。このように、メソッド名の命名規則によって検索クエリを変更することが可能となっています。

 

5.データを更新(UPDATE)する

だいたい要領がつかめてきました。

さて、データの更新はどのメソッドを使えば良いのでしょうか。

これは、saveメソッドを使います。実は先ほど深追いしかけた際に「em.merge(entity);」というキーワードがありました。(このページの5枚目のスクリーンショットです。)saveメソッドは、テーブルキーに対してデータが無ければINSERT、データが有れば更新という動作をしてくれます。

 

試しに以下のようなデータを更新するメソッドをコントローラクラスに追加してみます。

サンプルのUserクラス(エンティティークラス)はidが@Idアノテーションによりキーとなっています。

 

「UserRepository」インターフェースの定義を少し修正します。

●変更前

public interface UserRepository extends CrudRepository<User, Long>

●変更後

public interface UserRepository extends CrudRepository<User, Integer>

書き終わったら実行してみます。実行前のDBの状態は以下のようになっています。

 

ブラウザから以下のURLにアクセスしてみましょう。

http://localhost:8080/demo/update-user?id=9&name=kyapikyapi&email=email99

 

ブレイクポイントを事前に張っておきました。パラメータが予定通りリクエストされています。F8キーを押して再開してみましょう。

  

 

データベースが更新されて、画面へ値が返却されました。

 

 

5.データ更新中にエラーが発生した場合のロールバック

更新中にエラーが発生した場合のロールバックについて確認してみましょう。

トランザクションの管理は@Transactionalアノテーションで実現できます。クラス(またはメソッド)の前に@Transactionalアノテーションを付けることで Exceptionが発生した場合、ロールバックしてくれるようになります。

今回はすべてのエラーと例外のスーパークラスであるThrowable.classが発生したのをトリガーにロールバックするように書いています。

 

では、実際にSQL実行エラーを発生させてみましょう。varchar(255)で定義されているnameカラムにそれ以上の文字列のデータを入力してみましょう。下は実行してブレークを張った状態です。nameプロパティーに長い文字列が代入されていることが分かります。そのままF8キーで再開します。

 

エラーが発生しました。nameカラムに長過ぎるデータが発生しているとログ出力されています。

 

画面を見てみると「Exceptionが発生して実行できません」と表示されています。

肝心のデータベースを確認してみましょう。データは更新されずに、実行前のままとなっています。

 

こんな風に書いて、意図的にRuntimeExceptionをスローしても良かったかもしれません。

 

余談ですが、継承元をJpaRepositoryに変更するとページャーのような一部データ取得のようなこともできそうです。これについては別の機会に検証してみたいと思います。

 

6.まとめ

  1. DBアクセスは、Entityクラス、Repositoryインターフェースを使ってアクセスする
  2. 今回のサンプルの場合、Entityクラス=Userクラス、Repositoryクラス=UserRepositoryインターフェースである
  3. RepositoryインターフェースはCrudRepository、(またはJpaRepository)を継承する
  4. CrudRepositoryは、エンティティークラスとキーとなるプロパティーの型を書く
  5. 命名規則に従ってRepositoryインターフェースにメソッドを追加することでWHERE句やORDER BY句の着いたSQLを実行することができる
  6. ロールバックは@Transactionalアノテーションを付与しトランザクション管理を行うことで実現できる

 

今回もだいぶ長くなってしまいました。

いかかでしたでしょうか?ここまでサンプルプロジェクトを少し拡張しながら見てきました。ここまでの話は、実はGetting Startedのサンプル解説ページ(英語)で紹介されていますが、少し機能追加しながら見てきました。

次回は、ThymeLeafを使ったHTML出力を紹介したいと思います。

 

【SpringBoot入門】 第5回 「Thymeleafを使ってみよう!(その1)」



3 thoughts on “【SpringBoot入門】 第4回 「サンプルプログラムを読み解こう!(その2)」

  • webシステム開発、spring、javaの初心者の私でも
    わかりやすいため参考にさせていただいております。

    1点、ご教示ください。
    「MainController」クラスの@Transactional(rollbackOn = Throwable.class)という記述ですが、
    rollbackOnだとエラーになってしまいます。rollbackForにするとエラーが消えましたが
    rollbackForが正しいのでしょうか?

    またこのような基本的な知識を習得するには何(本、サイト)を参考にするとよいかご教示頂けると幸甚です。

  • ここに書いてある通りに実装し、実行したところ、タイプUserのfindOneプロパティが見つかりません!といったエラーが出力されてしまいました。何をどう調べればよいか、またはどう対処すればよいか、ご教示頂けると幸甚です。
    ↓詳細
    org.springframework.beans.factory.UnsatisfiedDependencyException: ‘mainController’という名前のBeanの作成中にエラーが発生しました:フィールド ‘userRepository’で表現されている満足度の低い依存関係。 ネストされた例外はorg.springframework.beans.factory.BeanCreationExceptionです: ‘userRepository’という名前のBeanの作成中にエラーが発生しました:initメソッドの呼び出しに失敗しました。 ネストされた例外はjava.lang.IllegalArgumentExceptionです:メソッドのクエリーを作成できませんでしたpublic abstract hello.User hello.UserRepository.findOne(java.lang.Integer)! タイプUserのfindOneプロパティが見つかりません!

  • web開発初心者さん、こんにちは♪コメントありがとうございます。

    @Transactional(rollbackOn = Throwable.class)
    とコーディングするとエラーになってしまう…。ということですね。

    SpringToolSuite(eclipse)をご使用でしたら、コントロールキーを押しながら
    @Transactionalと書いた文字の上にマウスのポインタをあてて、クリックしてみてください。
    Transactional.classが開けると思いますが、JTAを使用していれば、その中に
    public Class[] rollbackOn() default {};
    という記載があると思います。

    ない場合は、おそらく
    Controllerクラスのimportに
    import javax.transaction.Transactional;
    という記述がないのではないかな?(もしくは、べつのパッケージを利用しているのかな?)
    と思います。
    import org.springframework.transaction.annotation.Transactional;と記述されていませんでしょうか?

    Exceptionの件ですが、
    UserRepositoryインターフェースの定義はどのようになっていますでしょうか?
    public interface UserRepository extends CrudRepository
    と記述されていますでしょうか?先ほどのコントロール+クリックで調べてみてください♪

    >基本的な知識を習得するためのおすすめの方法
    個人的に新しい技術を勉強するときは、まず書籍を探して勉強するようにしています。
    Webですと断片的に情報が入ってきてしまうので、最初は本でさっと体系的に勉強するのがよいかなと思っています。

    そのあとでWebでより詳しい情報を調べるようにしています。
    SpringBootの場合はWebで検索するとSpringも検索に引っかかってしまうので、
    なかなか良い情報にたどり着けないんですけれども…。

    おすすめの書籍ですが、私はこちらを購入して読んでいました。
    https://amzn.to/2yoSPZn

    有名な「掌田津耶乃」さんが執筆された
    より新しい書籍もあるようですので探してみてくださいね!
    https://amzn.to/2ytpkpl

web開発初心者 にコメントする コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください