LoginSignup
1
0

More than 3 years have passed since last update.

【Java・SpringBoot】明示的トランザクション処理(SpringBootアプリケーション実践編21)

Posted at

ホーム画面からユーザー一覧画面に遷移し、ユーザーの詳細を表示するアプリケーションを作成して、Spring JDBCの使い方について学びます⭐️
前回は、トランザクションの基本的な処理である宣言的トランザクション実装したので、今回は明示的トランザクションを学びます^^
構成は前回/これまでの記事を参考にしてください

⭐️前回の記事
Java・SpringBoot】宣言的トランザクション処理(SpringBootアプリケーション実践編20)

明示的トランザクション

  • 実践では宣言的トランザクションを使う
  • Springが用意するトランザクションでは対応できない場合に、明示的トランザクションを使う

明示的トランザクションの使い方

  • PlatformTransactionManagerクラス
    • トランザクションを開始、コミットなどをするクラス
PlatformTransactionManager txManager;
//トランザクション開始
TransactionStatus status = txManager.getTransaction(def);
//コミット
txManager.commit(status);
  • DefaultTransactionDefinitionクラス
    • トランザクションの設定をするクラス
DefaultTransactionDefinition def = new DefaultTransactionDefinition();

//トランザクションの名前を設定
def.setName("UpdateUser");
//読取専用ではない設定
def.setReadOnly(false); 
//トランザクションの伝播レベルをREQUIREDに設定
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

明示的トランザクション実践

UserService.java
@Service
public class UserService {
//中略(全文は下記参考)
    @Autowired
    PlatformTransactionManager txManager;

//中略(全文は下記参考)
    /**
     * 1件更新用メソッド.
     */
    public boolean updateOne(User user) throws DataAccessException {
        //インスタンス生成
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();

        //設定
        def.setName("UpdateUser");
        def.setReadOnly(false);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        //トランザクション開始
        TransactionStatus status = txManager.getTransaction(def);

        // 判定用変数
        boolean result = false;
        try {
            // 1件更新
            int rowNumber = dao.updateOne(user);

            if (rowNumber > 0) {
                // update成功
                result = true;
            }
        }catch (Exception e){
            txManager.rollback(status);
            throw new DataAccessException("ERROR Update",e) {};
        }
        //コミット
        txManager.commit(status);

        return result;
    }
//中略(全文は下記参考)
}

SpringBootを起動してホーム画面確認!

  • http://localhost:8080/home
  • ユーザ一覧からユーザ詳細画面に移り、ユーザー名更新
  • "Update Oyakata Neko"に名前を更新しても、ユーザ名が変わっていない(更新失敗)、トランザクションがロールバックできていることがわかりました〜〜!^^
  • 明示的トランザクションは、AOP内でサービスクラスのメソッドを実行する前後で、トランザクションの開始/コミットをすればOK!

スクリーンショット 2020-12-05 12.12.07.png

スクリーンショット 2020-12-05 12.10.46.png

(参考)コード全文

UserService.java
package com.example.demo.login.domain.service;

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.repository.UserDao;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
public class UserService {
    @Autowired
    @Qualifier("UserDaoJdbcImpl")

    UserDao dao;
    @Autowired
    PlatformTransactionManager txManager;

    /**
     * insert用メソッド.
     */
    public boolean insert(User user) {
        // insert実行
        int rowNumber = dao.insertOne(user);
        // 判定用変数
        boolean result = false;

        if (rowNumber > 0) {
            // insert成功
            result = true;
        }
        return result;
    }

    /**
     * カウント用メソッド.
     */
    public int count() {
        return dao.count();
    }

    /**
     * 全件取得用メソッド.
     */
    public List<User> selectMany() {
        // 全件取得
        return dao.selectMany();
    }

    /**
     * 1件取得用メソッド.
     */
    public User selectOne(String userId) {
        // selectOne実行
        return dao.selectOne(userId);
    }

    /**
     * 1件更新用メソッド.
     */
    public boolean updateOne(User user) throws DataAccessException {
        //インスタンス生成
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();

        //設定
        def.setName("UpdateUser");
        def.setReadOnly(false);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        //トランザクション開始
        TransactionStatus status = txManager.getTransaction(def);

        // 判定用変数
        boolean result = false;
        try {
            // 1件更新
            int rowNumber = dao.updateOne(user);

            if (rowNumber > 0) {
                // update成功
                result = true;
            }
        }catch (Exception e){
            txManager.rollback(status);
            throw new DataAccessException("ERROR Update",e) {};
        }
        //コミット
        txManager.commit(status);

        return result;
    }

    /**
     * 1件削除用メソッド.
     */
    public boolean deleteOne(String userId) {

        // 1件削除
        int rowNumber = dao.deleteOne(userId);

        // 判定用変数
        boolean result = false;

        if (rowNumber > 0) {
            // delete成功
            result = true;
        }
        return result;
    }
    // ユーザー一覧をCSV出力する.
    /**
     * @throws DataAccessException
     */
    public void userCsvOut() throws DataAccessException {
        // CSV出力
        dao.userCsvOut();
    }

    /**
     * サーバーに保存されているファイルを取得して、byte配列に変換する.
     */
    public byte[] getFile(String fileName) throws IOException {

        // ファイルシステム(デフォルト)の取得
        FileSystem fs = FileSystems.getDefault();

        // ファイル取得
        Path p = fs.getPath(fileName);

        // ファイルをbyte配列に変換
        byte[] bytes = Files.readAllBytes(p);

        return bytes;
    }
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0