[[356529]] シータ公式サイト: http://seata.io/zh-cn/ 序文 マイクロサービス アーキテクチャが非常に普及しているため、新世代のマイクロサービス ソリューションである Spring Cloud Alibaba が提供するオープン ソースの分散トランザクション ソリューション フレームワークである Seata が、分散トランザクションを解決するための第一の選択肢となっていることは間違いありません。前回の 2 つの記事では、一般的な分散ソリューションと成熟したフレームワークを紹介し、Seata の概念についても紹介しました。分散トランザクション処理を経験したことのない方は、まず概要をご覧ください。 - SpringCloud Alibaba マイクロサービス アーキテクチャ (XI) - 共通分散トランザクション ソリューションと理論的基礎
- SpringCloud Alibaba マイクロサービス アーキテクチャ (XII) - 分散トランザクション ソリューション フレームワークの Seata コンセプトの紹介
したがって、この記事で Seata を Spring Cloud と統合する前に、Spring Cloud Alibaba と Spring Boot と Spring Cloud 間のバージョン対応を理解しておく必要があります。 バージョン選択: Spring Cloud Alibaba と Spring Boot および Spring Cloud のバージョン間の対応 1. バージョン要件 落とし穴 1: プロジェクトで druid データベース接続プールが使用され、SpringBoot Starter 依存関係 druid-spring-boot-starter が導入されている場合、seata ソース コードで導入された druid 依存関係が druid-spring-boot-starter の自動アセンブリ クラスと競合するため、druid-spring-boot-starter 依存関係を druid1.1.23 に置き換える必要があります。競合が発生した場合、プロジェクトの起動時に次のような例外が発生します。 2. Seata環境設定を統合する 1. seata-server-1.2.0とseata-1.2.0のソースコードをダウンロードする seate-server ダウンロード: https://seata.io/zh-cn/blog/download.html、使用する必要がある seata1.2 圧縮パッケージをダウンロードします。 seata-1.2.0 ソースコードのダウンロード: https://github.com/seata/seata/releases ここに画像の説明を挿入 2. undo_logログテーブルを作成する seata1.2 ソース コードの seata-1.2.0\script\client\at\db ディレクトリには、mysql、oracle、postgresql の 3 つのデータベースの undo-log リバース ログ ロールバック テーブルを生成するためのテーブル作成スクリプトがあります。 - プロジェクトのグローバル トランザクションに参加しているデータベースに undo_log テーブルを追加します。 undo_log テーブル スクリプトは、データベースの種類に応じて選択されます。
-
- 作成する テーブルが存在しない場合`undo_log`
- (
- `branch_id` BIGINT (20) NOT NULL COMMENT 'ブランチトランザクションID' 、
- `xid` VARCHAR (100)ではない NULL COMMENT 'グローバルトランザクションID' 、
- `context` VARCHAR (128) NOT NULL COMMENT 'undo_logコンテキスト(シリアル化など)' 、
- `rollback_info` LONGBLOB NOT NULLコメント「ロールバック情報」 、
- `log_status` INT (11) NOT NULL COMMENT '0:通常状態、1:防御状態' 、
- `log_created` DATETIME(6) NOT NULLコメント'create datetime' 、
- `log_modified` DATETIME(6) NOT NULLコメント'datetimeの変更' 、
- 個性的 キー`ux_undo_log` (`xid`, `branch_id`)
- ) エンジン = InnoDB
- AUTO_INCREMENT = 1
- デフォルト文字セット = utf8 コメント = 'AT トランザクション モード undo テーブル' ;
3. seataトランザクション関連テーブルを作成する Seata1.2 のソースコードをダウンロードし、上記のように解凍します。現在、mysql、oracle、postgresql の 3 つのデータベースをサポートしています。上記の 3 つのスクリプトは、Seata のサーバー側で分散トランザクションを調整および処理するために必要な 3 つのテーブル用です。さまざまなデータベース用の global_table、branch_table、および lock_table 作成スクリプトを提供します。独自のデータベースに応じて、対応する SQL スクリプトを実行できます。 ここでは MySQL を例に挙げます。 MySQL データベースに seata という名前のライブラリを作成し、次の SQL を実行して 3 つのテーブルを生成します。 -
-
- 作成する テーブルが存在しない場合`global_table`
- (
- `xid` VARCHAR (128)ではない NULL 、
- `transaction_id` BIGINT 、
- `status` TINYINT NOT NULL 、
- `application_id` VARCHAR (32)、
- `transaction_service_group` VARCHAR (32)、
- `トランザクション名` VARCHAR (128)、
- `タイムアウト` INT ,
- `begin_time` BIGINT 、
- `application_data` VARCHAR (2000)、
- `gmt_create` 日付時刻、
- `gmt_modified` 日付時刻、
- 主要な キー(`xid`)、
- キー`idx_gmt_modified_status` (`gmt_modified`, `status`),
- キー`idx_transaction_id` (`transaction_id`)
- ) エンジン = InnoDB
- デフォルト文字セット = utf8;
-
-
- 作成する テーブルが存在しない場合`branch_table`
- (
- `branch_id` BIGINT ない NULL 、
- `xid` VARCHAR (128)ではない NULL 、
- `transaction_id` BIGINT 、
- `resource_group_id` VARCHAR (32)、
- `resource_id` VARCHAR (256)、
- `branch_type` VARCHAR (8)、
- `ステータス` TINYINT、
- `client_id` VARCHAR (64)、
- `application_data` VARCHAR (2000)、
- `gmt_create` 日付時刻(6)、
- `gmt_modified` 日付時刻(6)、
- 主要な キー(`branch_id`)、
- キー`idx_xid` (`xid`)
- ) エンジン = InnoDB
- デフォルト文字セット = utf8;
-
-
- 作成する テーブルが存在しない場合`lock_table`
- (
- `row_key` VARCHAR (128) NOT NULL 、
- `xid` VARCHAR (96)、
- `transaction_id` BIGINT 、
- `branch_id` BIGINT ない NULL 、
- `resource_id` VARCHAR (256)、
- `テーブル名` VARCHAR (32)、
- `pk` VARCHAR (36)、
- `gmt_create` 日付時刻、
- `gmt_modified` 日付時刻、
- 主要な キー(`行キー`)、
- キー`idx_branch_id` (`branch_id`)
- ) エンジン = InnoDB
- デフォルト文字セット = utf8;
4. プロジェクトに seata 依存関係を導入する 4.1 マイクロサービスがSpringCloudの場合
- <!
- <!
- <依存関係>
- <グループ ID>com.alibaba.cloud</グループ ID>
- <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
- <バージョン>2.1.3.RELEASE</バージョン>
- <除外事項>
- <除外>
- <groupId>io.seata</groupId>
- <artifactId>seata-spring-boot-starter</artifactId>
- </除外>
- </除外>
- </依存関係>
- <依存関係>
- <groupId>io.seata</groupId>
- <artifactId>seata-spring-boot-starter</artifactId>
- <バージョン>1.2.0</バージョン>
- </依存関係>
- <!
4.2 マイクロサービスがDubboの場合
- <依存関係>
- <groupId>io.seata</groupId>
- <artifactId>seata-spring-boot-starter</artifactId>
- <バージョン>1.2.0</バージョン>
- </依存関係>
5. seata-serverのregistry.confを変更する registry.conf 登録センターを nacos として設定し、nacos 関連の属性パラメータを設定します。 - ## seata-server、サポートファイル、nacos、eureka、redis、zk、consul、etcd3、sofa の登録センターを設定します。
- レジストリ {
- # ファイル、nacos、eureka、redis、zk、consul、etcd3、sofa
- タイプ = "ナコス"
-
- ナコス
- アプリケーション = "seata-server"
- サーバーアドレス = "127.0.0.1:8848"
- グループ= "SEATA_GROUP"
- 名前空間 = "public"
- ユーザー名 = "nacos"
- クラスター = "デフォルト"
- パスワード= "nacos"
- }
-
- ファイル {
- 名前= "file.conf"
- }
- }
-
- ## seata-server、サポートファイル、nacos、apollo、zk、consul、etcd3 の設定センターを設定します
- 設定{
- # ファイル、nacos、apollo、zk、consul、etcd3
- タイプ = "ナコス"
-
- ナコス
- サーバーアドレス = "127.0.0.1:8848"
- 名前空間 = "public"
- グループ= "SEATA_GROUP"
- ユーザー名 = "nacos"
- パスワード= "nacos"
- }
-
- ファイル {
- 名前= "file.conf"
- }
- }
6. seata-serverのfile.configを変更する file.config の DB モード関連のパラメータを設定します。 - ## ローカル ドキュメントとデータベースをサポートするように seata-server のデータ保存方法を構成します。
- ##トランザクションログ ストア。seata -serverでのみ使用されます。
- 店 {
- ## 保存モード: ファイル、DB、Redis
- モード = "db"
-
- ## ファイルストアプロパティ
- ファイル {
- ##保存場所のディレクトリ
- dir = "セッションストア"
- # セッションサイズを分岐します。超過した場合はまずロックキーの圧縮を試みます。それでも超過した場合は例外がスローされます。
- 最大ブランチセッションサイズ = 16384
- # globe セッションサイズ。超過すると例外がスローされます
- 最大グローバルセッションサイズ = 512
- # ファイルバッファサイズ、超過した場合は新しいバッファを割り当てます
- ファイル書き込みバッファキャッシュサイズ = 16384
- #バッチ読み取りを回復するとき サイズ
- セッションリロード読み取りサイズ = 100
- # 非同期、同期
- フラッシュディスクモード = 非同期
- }
-
- ##データベースストアプロパティ
- デシベル{
- ## DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari)などのjavax.sql.DataSourceの実装。
- データソース = "ドルイド"
- ## mysql/oracle/postgresql/h2/oceanbase など
- dbType = "mysql"
- ドライバークラス名 = "com.mysql.jdbc.Driver"
- url = "jdbc:mysql://127.0.0.1:3306/seata"
- ユーザー= "root"
- パスワード= "root"
- 最小接続数 = 5
- 最大接続数 = 30
- グローバルテーブル = "グローバルテーブル"
- branchTable = "ブランチテーブル"
- lockTable = "ロックテーブル"
- クエリ制限 = 100
- 最大待機時間 = 5000
- }
-
- ## redis ストアプロパティ
- レディス{
- ホスト = "127.0.0.1"
- ポート = "6379"
- パスワード= ""
- データベース= "0"
- 最小接続 = 1
- 最大接続数 = 10
- クエリ制限 = 100
- }
- }
7. nacosスクリプトを修正してnacosコンソールに送信する ダウンロードした nacos を実行し、https://github.com/seata/seata/tree/develop/script/config-center の config.txt ファイルを参照して変更します。 - service.vgroupMapping.my_test_tx_group=デフォルト
- ストアモード=db
- store.db.datasource=ドルイド
- ストア.db.dbType=mysql
- store.db.driverClassName=com.mysql.jdbc.Driver
- store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode= true
- store.db.user = ユーザー名
- store.db.password =パスワード
- ストア.db.minConn=5
- ストア.db.maxConn=30
- store.db.globalTable=グローバルテーブル
- store.db.branchTable=ブランチテーブル
- ストア.db.クエリ制限=100
- store.db.lockTable=ロックテーブル
- ストア.db.maxWait=5000
リポジトリ https://github.com/seata/seata/tree/develop/script/config-center/nacos で提供されている nacos スクリプト nacos-config.sh を実行し、上記の情報を nacos コンソールに送信します。パラメータを変更する必要がある場合は、nacos コンソールにログインして直接変更できます。 操作は以下のとおりです。
8. application.yml の設定 公式 github リポジトリ (https://github.com/seata/seata/tree/develop/script/client) から参照構成を取得し、変更して、プロジェクトの application.yml ファイルに追加します。 - #Seata 分散トランザクション構成 ( ATモード)
- シータ:
- 有効: true
- アプリケーションID : ${spring.application.name }
- #クライアントとサーバーは同じトランザクショングループに属しています
- tx-サービス-グループ: my_test_tx_group
- 自動データソースプロキシを有効にする: true
- サービス:
- vgroup マッピング:
- my_test_tx_group:デフォルト
- 設定:
- タイプ: ナコス
- ナコス:
- 名前空間: "public"
- サーバーアドレス: 127.0.0.1:8848
- グループ: SEATA_GROUP
- ユーザー名: "nacos"
- パスワード: 「nacos」
- #nacosへのサービス登録
- レジストリ:
- タイプ: ナコス
- ナコス:
- アプリケーション: seata-server
- サーバーアドレス: 127.0.0.1:8848
- グループ: SEATA_GROUP
- 名前空間: "public"
- ユーザー名: "nacos"
- パスワード: 「nacos」
- クラスター:デフォルト
9. seata-serverを実行する seata-server を起動して実行します。成功したら、独自のサービスプロバイダーとサービス参加者を実行します。グローバル トランザクション呼び出し元 (グローバル トランザクションを開始するサービス) のインターフェースに @GlobalTransactional アノテーションを追加します。 これまでに、SpringCloud 統合、seata1.2 統合、nacos の seata1.2 統合の構成と登録センターが完全に統合されました。 3. プロジェクトの準備 前の手順で Seata 環境を完了している場合は、プロジェクトを開始することができます。コンソールに異常がなければ構築は成功です。 次に、タイトルとして Seata の公式ドキュメントの典型的な例を使用し、ユーザーが注文を出し、注文を作成し、同時に在庫数量を減算することによって発生する分散トランザクションの問題をシミュレートし、Seata の次の機能を使用してそれを解決します。 1. 注文サービス - /**
- * @desc : 注文サービス
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:27
- */
- @レストコントローラ
- 翻訳者
- @RequestMapping( "/order" )
- パブリッククラスOrderController{
-
- オートワイヤード
- プライベート OrderServiceImpl orderService;
-
- /**
- * ユーザーが購入して注文し、グローバルトランザクションの送信をシミュレートします
- * @param pid
- * @戻る
- */
- @RequestMapping( "/purchase/commit/{pid}" )
- 公共 注文orderCommit(@PathVariable( "pid" ) Integer pid) {
- orderService.createOrderCommit(pid)を返します。
- }
-
- /**
- * ユーザーが購入して注文し、グローバルトランザクションのロールバックをシミュレートします。
- * @param pid
- * @戻る
- */
- @RequestMapping( "/purchase/rollback/{pid}" )
- 公共 オーダーorderRollback(@PathVariable( "pid" ) Integer pid) {
- orderService.createOrderRollback(pid)を返します。
- }
-
- }
- /**
- * @説明:
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:30
- */
- @サービス
- 翻訳者
- パブリッククラス OrderServiceImpl {
- オートワイヤード
- プライベート OrderDao orderDao;
-
- オートワイヤード
- プライベートProductService productService;
-
- // ユーザーは注文を出し、グローバルトランザクションの送信をシミュレートします
- 公共 注文createOrderCommit(整数pid) {
- log.info( "製品番号 {} の注文リクエストを受け取り、製品マイクロサービスを呼び出して製品情報を照会しました" 、 pid);
-
- //1 製品マイクロサービスを呼び出して製品情報を照会する
- 製品 product = productService.findByPid(pid);
- log.info( "製品番号 {} の情報が見つかりました。内容は次のとおりです: {}" , pid, JSON.toJSONString(product));
-
- //2 注文する(注文を作成する)
- 注文 order = 新しい注文();
- オーダー.setUid(1);
- .setUsername ( "テストユーザー" );
- 命令.setPid(pid);
- 注文.setPname(product.getPname());
- 注文.setPprice(product.getPprice());
- 順序.setNumber (1);
- orderDao.save(注文);
- log.info( "注文が正常に作成されました。注文情報は {} です" , JSON.toJSONString( order ));
-
- //3 在庫を減算するm
- productService.reduceInventoryCommit(pid、 order.getNumber ());
-
- 戻る 注文;
- }
-
- // ユーザーは注文を出し、グローバルトランザクションのロールバックをシミュレートします
- @GlobalTransactional //グローバルトランザクション制御
- 公共 注文createOrderRollback(整数pid) {
- log.info( "製品番号 {} の注文リクエストを受け取り、製品マイクロサービスを呼び出して製品情報を照会しました" 、 pid);
-
- //1 製品マイクロサービスを呼び出して製品情報を照会する
- 製品 product = productService.findByPid(pid);
- log.info( "製品番号 {} の情報が見つかりました。内容は次のとおりです: {}" , pid, JSON.toJSONString(product));
-
- //2 注文する(注文を作成する)
- 注文 order = 新しいOrder ();
- オーダー.setUid(1);
- .setUsername ( "テストユーザー" );
- 命令.setPid(pid);
- 注文.setPname(product.getPname());
- 注文.setPprice(product.getPprice());
- 順序.setNumber (1);
- orderDao.save(注文);
- log.info( "注文が正常に作成されました。注文情報は {} です" , JSON.toJSONString( order ));
-
- //3 在庫を減算するm
- productService.reduceInventoryRollback(pid、 order.getNumber ());
-
- 戻る 注文;
- }
-
- }
- 製品サービス用のFeignクラスProductService
- /**
- * @説明:
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:43
- */
- @FeignClient(値 = "product-service" 、構成 = FeignRequestInterceptor.class)
- パブリックインターフェースProductService {
- //@FeignClient 値 + @RequestMapping 値は、実際には完了したリクエスト アドレス"http://product-service/product/" + pid です
- //リクエストのURI部分を指定する
- @RequestMapping( "/product/product/{pid}" )
- Product findByPid(@PathVariable Integer pid);
-
- //在庫を減算し、グローバルトランザクションの送信をシミュレートする
- //パラメータ 1: 製品 ID
- //パラメータ2: 控除量
- @RequestMapping( "/product/reduceInventory/commit" )
- void ReduceInventoryCommit(@RequestParam( "pid" )整数pid、
- @RequestParam( "number" )整数値);
-
- //在庫を減算し、グローバルトランザクションのロールバックをシミュレートします
- //パラメータ 1: 製品 ID
- //パラメータ2: 控除量
- @RequestMapping( "/product/reduceInventory/rollback" )
- void ReduceInventoryRollback(@RequestParam( "pid" )整数pid,
- @RequestParam( "number" )整数値);
-
- }
2. 製品サービス - /**
- * @説明:
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:16
- */
- @レストコントローラ
- 翻訳者
- @RequestMapping( "/product" )
- パブリッククラスProductController {
-
- オートワイヤード
- プライベートProductService productService;
-
- /**
- * 在庫を減算、通常->グローバルトランザクション送信をシミュレート
- * @param pid
- * @パラメータ番号
- */
- @RequestMapping( "/reduceInventory/commit" )
- パブリックvoid ReduceInventoryCommit(整数pid,整数数) {
- 文字列トークン = ServletUtils.getRequest().getHeader( "token" );
- log.info( "ヘッドリクエストヘッダーから渡された値はトークンです: " + トークン);
- productService.reduceInventoryCommit(pid、数値);
- }
-
- /**
- * 在庫を減算、例外 -> グローバルトランザクションのロールバックをシミュレート
- * @param pid
- * @パラメータ番号
- */
- @RequestMapping( "/reduceInventory/rollback" )
- パブリックvoid ReduceInventoryRollback(整数pid,整数数) {
- productService.reduceInventoryRollback(pid、数値);
- }
-
- //製品情報のクエリ
- @RequestMapping( "/product/{pid}" )
- public Product product(@PathVariable( "pid" ) Integer pid) {
- log.info( "次に、製品番号 {} の情報を照会します" , pid);
- 製品 product = productService.findByPid(pid);
- log.info( "製品情報のクエリが成功しました。コンテンツは {} です" 、 JSON.toJSONString(product));
- 商品を返品する。
- }
- }
- ProductService インターフェース クラス
- /**
- * @desc : 製品インターフェース
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:18
- */
- パブリックインターフェースProductService {
- //PIDに基づいて製品情報を照会する
- 製品 findByPid(整数pid);
-
- //在庫を減算、通常->グローバルトランザクションの送信をシミュレート
- void ReduceInventoryCommit(整数pid、整数数);
-
- //在庫を減算、例外->グローバルトランザクションのロールバックをシミュレート
- void ReduceInventoryRollback(整数pid、整数数);
- }
- ProductServiceImpl インターフェース実装クラス
- /**
- * @desc : 製品サービス実装クラス
- * @著者: cao_wencao
- * @日付: 2020-09-22 23:20
- */
- @サービス
- パブリッククラス ProductServiceImpl は ProductService を実装します {
-
- オートワイヤード
- プライベート ProductDao productDao;
-
- @オーバーライド
- パブリック製品findByPid(整数pid) {
- productDao.findById(pid).get()を返します。
- }
-
- /**
- * 在庫を減算、通常->グローバルトランザクション送信をシミュレート
- * @param pid
- * @パラメータ番号
- */
- @オーバーライド
- パブリックvoid ReduceInventoryCommit(整数pid,整数数) {
- //クエリ
- 製品 product = productDao.findById(pid).get();
- //検証を省略
-
- //メモリ内の推論
- product.setStock(product.getStock() - 数値);
-
- //控除インベントリを保存する
- productDao.save(製品);
- }
-
- /**
- * 在庫を減算、例外 -> グローバルトランザクションのロールバックをシミュレート
- * @param pid
- * @パラメータ番号
- */
- @Transactional(rollbackFor = Exception.class) //サービスプロバイダーのローカルトランザクション注釈
- @オーバーライド
- パブリックvoid ReduceInventoryRollback(整数pid,整数数) {
- //クエリ
- 製品 product = productDao.findById(pid).get();
- //検証を省略
-
- //メモリ内の推論
- product.setStock(product.getStock() - 数値);
-
- //例外をシミュレートする
- 整数i = 1 / 0;
-
- //控除インベントリを保存する
- productDao.save(製品);
- }
- }
IV.参考資料 シータ公式サイト: Seata FAQ: - http://seata.io/zh-cn/docs/overview/faq.html
Seata 統合 1.2 チュートリアル: - https://www.bilibili.com/video/BV12Q4y1A7Nt
アップグレード 1.3 チュートリアル: - https://www.bilibili.com/video/BV1Cf4y1X7vR
- https://mp.weixin.qq.com/s/2KSidJ72YsovpJ94P1aK1g
Springcloud 統合デモ: - https://gitee.com/itCjb/spring-cloud-alibaba-seata-demo
5. 完全なソースコード - https://github.com/Thinkingcao/SpringCloudLearning/tree/master/springcloud-seata
|