Spring学習ノート③:JDBCと事務管理
文書ディレクトリ0.基本概念 1.JDBTtemplate使用例 1.1データソースおよび構成 1.2データベース構成 1.3クエリ文の例 2.Springトランザクション制御 2.1プロファイル 2.2トランザクションインタフェース 2.2.1取引管理:PlatformTransactionManager 2.2.2取引情報:TransactionDefinition 2.2.3取引ステータス:TransactionStatus 2.3 Springの宣言トランザクション管理 2.3.1例①: XMLベースの宣言トランザクション管理 2.3.2 tx:methodのプロパティ詳細 2.3.3例②:注釈ベースの宣言トランザクション管理 付録学習ノート①~③コード及び工程書類 この3つのノートをコレクションし、Springのよくある問題と使用方法を完全にレビューします. Spring学習ノート①: IoC容器、Beanと注入 Spring学習ノート②:ダイナミックエージェントおよびフェース向けプログラミング Spring学習ノート③: JDBCと事務管理(本編) 0.基本概念 Springフレームワークで提供されるJDBCサポートは、core(コアパッケージ)、object(オブジェクトパッケージ)、dataSource(データソースパッケージ)、support(サポートパッケージ)の4つのパッケージで構成されています.
1.JDBCTEmplate使用例
1.1データソースと構成
データ・ソースの基本クラスは
コアクラスは
プロファイルクラスを使用して、上記の構成を完了することもできます.
1.2データベース構成
データベースにテーブル
対応モデル:
1.3クエリ文の例
2.Springトランザクション制御トランザクション制御は一般的にサービス層にあり、「プログラミングトランザクション」と「宣言トランザクション」に分けられる.SringはAOPに基づいて実現される後者を提供する. Spring JDBCベースのトランザクションマネージャは
2.1プロファイル
Springのトランザクション制御はAOPに基づいて実現されるため,AOPのネーミングスペースも導入する必要がある.
2.2取引インタフェース
2.2.1取引管理:PlatformTransactionManager
2.2.2取引情報:TransactionDefinition
ここで、トランザクションの伝播動作は次のように定義されます.
属性名
説明
の値
PROPAGATION_REQUIRED
現在トランザクション環境がある場合は、現在実行中のトランザクション環境に追加します.そうでない場合は、新しいトランザクションを作成します.【デフォルト】
REQUIRED
PROPAGATION_SUPPORTS
現在のメソッドを現在のトランザクション環境に追加することを指定します.現在トランザクションがない場合は、非トランザクションで実行します.
SUPPORTS
PROPAGATION_MANDATORY
現在のメソッドが現在のトランザクション環境に追加される必要があることを指定します.現在トランザクションがない場合、例外が放出されます.
MANDATORY
PROPAGATION_REQUIRES_NEW
新しいトランザクションが作成され、現在のメソッドがトランザクションにすでに存在する場合は、現在新しいトランザクションが保留され、実行待ちになります.
REQUIRES_NEW
PROPAGATION_NOT_SUPPORTED
現在のトランザクションはサポートされず、非トランザクション状態で実行されます.トランザクション環境が現在存在する場合は、現在のメソッドが先に実行されるまで保留します.
NOT_SUPPORTED
PROPAGATION_NEVER
現在のトランザクションはサポートされていません.現在のメソッドがトランザクションにある場合は、例外が放出されます.
NEVER
PROPAGATION_NESTED
現在のメソッドの実行時に、すでにトランザクションが存在する場合は、ネストされたトランザクションで実行することを指定します.現在の環境で実行されていないトランザクションの場合は、ロールバック可能な複数のセーブポイントを持つ親トランザクションと独立した新規トランザクションが作成されます.内部トランザクションロールバックは外部トランザクションに影響を与えません(
NESTED
2.2.3取引状態:TransactionStatus
2.3 Springの宣言トランザクション管理
振替用のデータベース・トランザクション・シーンを構築するには、次のようにします.
対応するModelクラス:
永続レイヤーを発行する
ビジネスロジック:
テストクラス:
2.3.1例①:XMLベースの宣言トランザクション管理
2.3.2 tx:methodのプロパティの詳細
ツールバーの
を選択します.
デフォルト
説明
propagation
propagation列挙
REQUIRED
トランザクション伝播プロパティ(詳細は2.2.2を参照)
isolation
isolation列挙
DEFAULT(使用するデータベースのデフォルトレベル)
トランザクション独立性レベル
read-only
boolean
false
最適化された読み取り専用トランザクションを使用するかどうか
timeout
int
-1
タイムアウト(秒)
rollbackFor
Class[]
{}
ロールバックが必要な例外クラス
rollbackForClassName
String[]
{}
ロールバックが必要な例外クラス名
noRollbackFor
Class[]
{}
ロールバック不要の例外クラス
noRollbackForClassName
String[]
{}
ロールバック不要の例外クラス名 隔離等級は全部で5級:
2.3.3例②:注釈ベースの宣言トランザクション管理
コンフィギュレーション・ファイルでトランザクション・ノートのドライバと登録トランザクション・マネージャを開きます.
ビジネス・レベルの変更:
付録学習ノート①~③コード及び工程書類(ダウンロード後zipファイルに変更)——springtest.pdf もっと見たい?——SpringBoot、Restful、ファイルアップロード…
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.20version>
dependency>
1.JDBCTEmplate使用例
1.1データソースと構成
データ・ソースの基本クラスは
org.springframework.jdbc.dataSource.DriverManagerDataSource
で、主な機能はデータベース接続を取得することであり、バッファ・プール、分散トランザクションなどを導入することもでき、以下の構成が必要です.
<bean id="dataSource" class="org.springframework.jdbc.dataSource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="username" value="$root" />
<property name="password" value="$password" />
<property name="initialPoolSize" value="3">property>
<property name="maxPoolSize" value="10">property>
<property name="maxStatements" value="100">property>
<property name="acquireIncrement" value="2">property>
bean>
コアクラスは
org.springframework.jdbc.core.JDBCTemplate
で、データ・ソースをロードしてインスタンス化する必要があります.<bean id="jdbcTemplate" class="org.springframework.jdbc.core.jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
プロファイルクラスを使用して、上記の構成を完了することもできます.
@Bean
public DriverManagerDataSource dataSource(){
String url = "jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "$password";
DriverManagerDataSource d = new DriverManagerDataSource(url, username, password);
d.setDriverClassName("com.mysql.cj.jdbc.Driver");
return d;
}
@Bean
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource());
}
1.2データベース構成
データベースにテーブル
student
があるとします.CREATE TABLE student (
id BIGINT(20) NOT NULL COMMENT ' ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT ' ',
age INT(11) NULL DEFAULT NULL COMMENT ' ',
email VARCHAR(50) NULL DEFAULT NULL COMMENT ' ',
PRIMARY KEY (id)
);
INSERT INTO student (id, name, age, email) VALUES
(1, 'Jack', 28, '[email protected]'),
(2, 'Louis', 20, '[email protected]'),
(3, 'Tom', 24, '[email protected]'),
(4, 'Sandy', 12, '[email protected]'),
(5, 'Lily', 85, '[email protected]');
対応モデル:
@Data
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
private String email;
}
1.3クエリ文の例
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
jdbcTemplate.query(
"SELECT * FROM student;",
(resultSet, i) -> new Student(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getString(4))
).forEach(System.out::println);
2.Springトランザクション制御
DataSourceTransactionManager
です.2.1プロファイル
Springのトランザクション制御はAOPに基づいて実現されるため,AOPのネーミングスペースも導入する必要がある.
<beans xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
beans>
2.2取引インタフェース
Spring-tx
(Spring Transaction)の3つのコアインタフェースは、次のとおりです.PlatformTransactionManager
:トランザクションの管理に使用されます.TransactionDefinition
:トランザクションを定義するための関連情報.TransactionStatus
:トランザクションのステータスを記述します.2.2.1取引管理:PlatformTransactionManager
TransactionStatus getTransaction(TransactionDefinition definition)
:トランザクションステータス情報を取得します.void commit(TransactionStatus status)
:トランザクションをコミットします.void rollback(TransactionStatus status)
:トランザクションをロールバックします.2.2.2取引情報:TransactionDefinition
String getName()
:トランザクション・オブジェクト名を取得します.int getIsolationLevel()
:トランザクションの独立性レベルを取得します.int getPropagationBehavior()
:トランザクションの伝播動作を取得します.int getTimeout()
:トランザクションのタイムアウト時間を取得します.boolean isReadOnly()
:トランザクションが読み取り専用かどうかを取得します.ここで、トランザクションの伝播動作は次のように定義されます.
属性名
説明
の値
PROPAGATION_REQUIRED
現在トランザクション環境がある場合は、現在実行中のトランザクション環境に追加します.そうでない場合は、新しいトランザクションを作成します.【デフォルト】
REQUIRED
PROPAGATION_SUPPORTS
現在のメソッドを現在のトランザクション環境に追加することを指定します.現在トランザクションがない場合は、非トランザクションで実行します.
SUPPORTS
PROPAGATION_MANDATORY
現在のメソッドが現在のトランザクション環境に追加される必要があることを指定します.現在トランザクションがない場合、例外が放出されます.
MANDATORY
PROPAGATION_REQUIRES_NEW
新しいトランザクションが作成され、現在のメソッドがトランザクションにすでに存在する場合は、現在新しいトランザクションが保留され、実行待ちになります.
REQUIRES_NEW
PROPAGATION_NOT_SUPPORTED
現在のトランザクションはサポートされず、非トランザクション状態で実行されます.トランザクション環境が現在存在する場合は、現在のメソッドが先に実行されるまで保留します.
NOT_SUPPORTED
PROPAGATION_NEVER
現在のトランザクションはサポートされていません.現在のメソッドがトランザクションにある場合は、例外が放出されます.
NEVER
PROPAGATION_NESTED
現在のメソッドの実行時に、すでにトランザクションが存在する場合は、ネストされたトランザクションで実行することを指定します.現在の環境で実行されていないトランザクションの場合は、ロールバック可能な複数のセーブポイントを持つ親トランザクションと独立した新規トランザクションが作成されます.内部トランザクションロールバックは外部トランザクションに影響を与えません(
DataSourceTransactionManager
トランザクションマネージャのみ有効).NESTED
2.2.3取引状態:TransactionStatus
void flush()
:トランザクションをリフレッシュします.boolean hasSavepoint()
:セーブポイントが存在するかどうかを取得します.boolean isCompleted()
:トランザクションが完了したかどうかを取得します.boolean isNewTransaction()
:新しいトランザクションかどうかを取得します.boolean isRollbackOnly()
:ロールバックするかどうかを取得します.void setRollbackOnly()
:トランザクションロールバックを設定します.2.3 Springの宣言トランザクション管理
振替用のデータベース・トランザクション・シーンを構築するには、次のようにします.
CREATE TABLE account (
id INT (11) PRIMARY KEY AUTO_INCREMENT COMMENT ' ID',
username VARCHAR(20) NOT NULL COMMENT ' ',
money INT DEFAULT NULL COMMENT ' '
);
/* */
INSERT INTO account VALUES (1, ' ', 2000);
INSERT INTO account VALUES (2, ' ', 1000);
対応するModelクラス:
@Data
@AllArgsConstructor
public class Account {
private Integer id;
private String username;
private Integer money;
}
永続レイヤーを発行する
@Repository(value = "accountDao")
public class AccountDaoImpl implements AccountDaoInterface{
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void send(int money, Account sbPaid) {
val sql = "UPDATE account SET money=money-? WHERE username=?;";
this.jdbcTemplate.update(sql, money, sbPaid.getUsername());
}
@Override
public void receive(int money, Account sbReceived) {
val sql = "UPDATE account SET money=money+? WHERE username=?;";
this.jdbcTemplate.update(sql, money, sbReceived.getUsername());
}
@Override
public Account query(Account account){
val sql = "SELECT * FROM account WHERE username=?";
return this.jdbcTemplate.query(sql,
(res, index) -> new Account(res.getInt(1),
res.getString(2),
res.getInt(3)
),
account.getUsername()).get(0);
}
}
ビジネスロジック:
@Service(value = "accountService")
public class AccountServiceImpl implements AccountServiceInterface {
private AccountDaoInterface accountDao;
@Autowired
public void setAccountDao(AccountDaoInterface accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(Account from, Account to, int money) throws Throwable {
this.accountDao.send(money, from);
if(money >= 1000) throw new Exception(" ");
this.accountDao.receive(money, to);
}
@Override
public Account query(Account account){
return this.accountDao.query(account);
}
}
テストクラス:
AccountServiceInterface accountService = (AccountServiceInterface)context.getBean("accountService");
System.out.println(accountService.query(new Account(1, " ", -1)));
System.out.println(accountService.query(new Account(2, " ", -1)));
accountService.transfer(
new Account(1, " ", -1),
new Account(2, " ", -1), 500); // 1000
System.out.println(accountService.query(new Account(1, " ", -1)));
System.out.println(accountService.query(new Account(2, " ", -1)));
2.3.1例①:XMLベースの宣言トランザクション管理
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut expression="execution(* MVC.Service.AccountServiceImpl.transfer(..))" id="txPointCut" />
<aop:advisor pointcut-ref="txPointCut" advice-ref="txAdvice" />
aop:config>
2.3.2 tx:methodのプロパティの詳細
ツールバーの
を選択します.
デフォルト
説明
propagation
propagation列挙
REQUIRED
トランザクション伝播プロパティ(詳細は2.2.2を参照)
isolation
isolation列挙
DEFAULT(使用するデータベースのデフォルトレベル)
トランザクション独立性レベル
read-only
boolean
false
最適化された読み取り専用トランザクションを使用するかどうか
timeout
int
-1
タイムアウト(秒)
rollbackFor
Class[]
{}
ロールバックが必要な例外クラス
rollbackForClassName
String[]
{}
ロールバックが必要な例外クラス名
noRollbackFor
Class[]
{}
ロールバック不要の例外クラス
noRollbackForClassName
String[]
{}
ロールバック不要の例外クラス名
read-only
の値がtrue
であれば、読取り専用トランザクション、すなわち接続点内にINSERT
などの書き込み操作がない.DEFAULT
:【デフォルト】データベースのデフォルトの独立性レベルを使用します.SERIALIZABLE
:最も厳格なレベルで、トランザクションがシリアルに実行され、リソース消費が最大です.REPEATABLE_READ
:1つのトランザクションが、別のトランザクションによって読み込まれたがコミットされていないデータを変更しないことを保証します.汚れた読み取りと重複しない読み取りは回避されますが、パフォーマンスの損失は増加します.READ_COMMITTED
:ほとんどの主流データベースのデフォルトのトランザクション・レベルは、1つのトランザクションが別のパラレル・トランザクションが変更されたがコミットされていないデータを読み込まないことを保証し、「汚れた読み取り」を回避します.このレベルは、ほとんどのシステムに適用されます.READ_UNCOMMITTED
:読み込み中に不正なデータが読み込まれないことを保証します.独立性レベルは、複数のトランザクションを処理する同時問題です.2.3.3例②:注釈ベースの宣言トランザクション管理
コンフィギュレーション・ファイルでトランザクション・ノートのドライバと登録トランザクション・マネージャを開きます.
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<tx:annotation-driven transaction-manager="txManager"/>
ビジネス・レベルの変更:
@Service(value = "accountService")
// , 2.3.1 & 2.3.2
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = {Exception.class})
public class AccountServiceImpl implements AccountServiceInterface {
private AccountDaoInterface accountDao;
@Autowired
public void setAccountDao(AccountDaoInterface accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(Account from, Account to, int money) throws Throwable {
this.accountDao.send(money, from);
if(money >= 1000) throw new Exception(" ");
this.accountDao.receive(money, to);
}
@Override
public Account query(Account account){
return this.accountDao.query(account);
}
}
付録学習ノート①~③コード及び工程書類