天天看點

seata1.4.0落地

1,簡介

        由于項目功能已經開發完成,但是某些功能牽扯到的分布式事務沒有處理,而在調研了一些分布式解決方案後,最終選擇了目前比較流行,且對現有業務代碼無侵入的seata。

        本項目情況:

        spring boot 2.0.9.RELEASE + sprong cloudFinchley.SR3 + nacos1.3.2作為注冊中心+ oracle12C

        本次內建seata 1.4.0 : 需要單獨部署TC(seata-server服務)

為防止部分資源無法下載下傳,文末會附上相關下載下傳資源

2,seata服務端安裝

        仔細官方文檔,很重要,能避免後期一些坑。

        2.1 seata官方文檔路徑:https://seata.io/zh-cn/index.html       

        2.2 seata下載下傳路徑:http://seata.io/zh-cn/blog/download.html

        2.3下載下傳好1.4.0壓縮

seata1.4.0落地

如果沒有logs檔案夾,則建立一個logs檔案夾,并在logs檔案夾裡建立一個seata_gc.log檔案

2.4打開目錄seata/cof在README-zh.md中有一些資源github下載下傳位址

seata1.4.0落地

2.5建立seata-server 資料庫

本項目隻有一個資料庫所有在該項目的資料庫裡建立一個使用者,作為seata的資料庫,使用者名叫seata

腳本:

CREATE TABLE global_table

(

    xid                       VARCHAR2(128) NOT NULL,

    transaction_id            NUMBER(19),

    status                    NUMBER(3)     NOT NULL,

    application_id            VARCHAR2(32),

    transaction_service_group VARCHAR2(32),

    transaction_name          VARCHAR2(128),

    timeout                   NUMBER(10),

    begin_time                NUMBER(19),

    application_data          VARCHAR2(2000),

    gmt_create                TIMESTAMP(0),

    gmt_modified              TIMESTAMP(0),

    PRIMARY KEY (xid)

);

CREATE INDEX idx_gmt_modified_status ON global_table (gmt_modified, status);

CREATE INDEX idx_transaction_id ON global_table (transaction_id);

-- the table to store BranchSession data

CREATE TABLE branch_table

(

    branch_id         NUMBER(19)    NOT NULL,

    xid               VARCHAR2(128) NOT NULL,

    transaction_id    NUMBER(19),

    resource_group_id VARCHAR2(32),

    resource_id       VARCHAR2(256),

    branch_type       VARCHAR2(8),

    status            NUMBER(3),

    client_id         VARCHAR2(64),

    application_data  VARCHAR2(2000),

    gmt_create        TIMESTAMP(6),

    gmt_modified      TIMESTAMP(6),

    PRIMARY KEY (branch_id)

);

CREATE INDEX idx_xid ON branch_table (xid);

-- the table to store lock data

CREATE TABLE lock_table

(

    row_key        VARCHAR2(128) NOT NULL,

    xid            VARCHAR2(128),

    transaction_id NUMBER(19),

    branch_id      NUMBER(19)    NOT NULL,

    resource_id    VARCHAR2(256),

    table_name     VARCHAR2(32),

    pk             VARCHAR2(36),

    gmt_create     TIMESTAMP(0),

    gmt_modified   TIMESTAMP(0),

    PRIMARY KEY (row_key)

);

CREATE INDEX idx_branch_id ON lock_table (branch_id);

2.6建立undo_log表

說明:該表在seata服務資料庫建立一張,在相關業務庫也都要建立,如果是多個業務庫,每個業務庫都要建立。

-- Create table

create table UNDO_LOG

(

  id            NUMBER(19) not null,

  branch_id     NUMBER(19) not null,

  xid           VARCHAR2(128) not null,

  context       VARCHAR2(128) not null,

  rollback_info BLOB not null,

  log_status    NUMBER(10) not null,

  log_created   TIMESTAMP(0) not null,

  log_modified  TIMESTAMP(0) not null

);

comment on table UNDO_LOG

  is 'AT transaction mode undo table';

2.7 更改seata服務相關配置檔案

        2.7.1在根目錄seata下建立config.txt檔案

service.vgroupMapping.mjkf-agility-sys-manage_tx_group=default

service.vgroup_mapping.sys_tx_group=default

service.vgroup_mapping.mjkf-agility-sys-manage-htf-group=default

service.vgroupMapping.mjkf-agility-sys-manage-htf-group=default

service.vgroupMapping.sys_tx_group=default

service.vgroupMapping.sys_group=default

service.vgroupMapping.mjkf-agility-dbmodel_tx_group=default

service.vgroupMapping.mjkf-agility-code_tx_group=default

service.default.grouplist=10.1.5.98:8091

service.disableGlobalTransaction=false

store.mode=db

store.db.datasource=druid

store.db.dbType=oracle

store.db.driverClassName=oracle.jdbc.OracleDriver

store.db.url=jdbc:oracle:thin:@10.1.5.98:1521/bxpdb

store.db.user=seata

store.db.password=seata

store.db.minConn=5

store.db.maxConn=30

store.db.globalTable=global_table

store.db.branchTable=branch_table

store.db.queryLimit=100

store.db.lockTable=lock_table

store.db.maxWait=5000

以下是需要自行更改的内容,包含資料庫連接配接資訊,自行修改

seata1.4.0落地

2.7.2在seata/conf/檔案夾下增加nacos-config.sh 檔案 内容如下:

#!/usr/bin/env bash

# Copyright 1999-2019 Seata.io Group.

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at、

#

#      http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

while getopts ":h:p:g:t:u:w:" opt

do

  case $opt in

  h)

    host=$OPTARG

    ;;

  p)

    port=$OPTARG

    ;;

  g)

    group=$OPTARG

    ;;

  t)

    tenant=$OPTARG

    ;;

  u)

    username=$OPTARG

    ;;

  w)

    password=$OPTARG

    ;;

  ?)

    echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] "

    exit 1

    ;;

  esac

done

urlencode() {

  for ((i=0; i < ${#1}; i++))

  do

    char="${1:$i:1}"

    case $char in

    [a-zA-Z0-9.~_-]) printf $char ;;

    *) printf '%%%02X' "'$char" ;;

    esac

  done

}

if [[ -z ${host} ]]; then

    host=localhost

fi

if [[ -z ${port} ]]; then

    port=8848

fi

if [[ -z ${group} ]]; then

    group="SEATA_GROUP"

fi

if [[ -z ${tenant} ]]; then

    tenant=""

fi

if [[ -z ${username} ]]; then

    username=""

fi

if [[ -z ${password} ]]; then

    password=""

fi

nacosAddr=$host:$port

contentType="content-type:application/json;charset=UTF-8"

echo "set nacosAddr=$nacosAddr"

echo "set group=$group"

failCount=0

tempLog=$(mktemp -u)

function addConfig() {

  curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$(urlencode $1)&group=$group&content=$(urlencode $2)&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/null

  if [[ -z $(cat "${tempLog}") ]]; then

    echo " Please check the cluster status. "

    exit 1

  fi

  if [[ $(cat "${tempLog}") =~ "true" ]]; then

    echo "Set $1=$2 successfully "

  else

    echo "Set $1=$2 failure "

    (( failCount++ ))

  fi

}

count=0

for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do

  (( count++ ))

    key=${line%%=*}

    value=${line#*=}

    addConfig "${key}" "${value}"

done

echo "========================================================================="

echo " Complete initialization parameters,  total-count:$count ,  failure-count:$failCount "

echo "========================================================================="

if [[ ${failCount} -eq 0 ]]; then

    echo " Init nacos config finished, please start seata-server. "

else

    echo " init nacos config fail. "

fi

2.7.3更改seata/cong檔案夾下的registry.conf,修改兩處

    1注冊中心類型及注冊中西配置

seata1.4.0落地

2,配置中心類型及相關參數

seata1.4.0落地

2.7.4修改項目目錄下的file.conf檔案

更改資料庫資訊,如有redis更改redis相關配置

seata1.4.0落地

2.8将fonfig.txt上傳至nacos

在seata/conf檔案夾下執行如下上傳指令:

sh nacos-config.sh -h 10.1.5.88 -p 8848 -g SEATA_GROUP -t 60e39b35-0229-4733-addf-fa9eedcd8e33 -u admin -w 123456

seata1.4.0落地
seata1.4.0落地
seata1.4.0落地

2.9 啟動seata服務,在seataa/bin 檔案夾下執行,windows的話執行.bat  linux執行.sh檔案

seata1.4.0落地

如下表示啟動成功,可取nacos裡去檢視

seata1.4.0落地
seata1.4.0落地
seata1.4.0落地

至此TC(服務端)配置啟動完成

2.9用戶端配置(自己的服務)

2.9.1 引入依賴,

注意引入依賴這一步可能會有些模範,首先官網提供了依賴版本說明

https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html

可參考官網提供的版本配置方式。

可能我項目内spring boot cloud版本比較老所有幾番嘗試之後使用了如下配置:

主項目:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.0.4.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
           

子項目:

<dependency>
   <groupId>io.seata</groupId>
   <artifactId>seata-spring-boot-starter</artifactId>
   <version>1.4.0</version>
</dependency>
           
seata1.4.0落地

2.9.2yml配置,增加如下配置

seata:
  enabled: true
  application-id: mjkf-agility-sys-manage-htf
  tx-service-group: mjkf-agility-sys-manage-group
  data-source-proxy-mode: AT
  use-jdk-proxy: true
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 10.1.5.88:8848
      username: admin
      password: 123456
  config:
    type: nacos
    nacos:
      server-addr: 10.1.5.88:8848
      group: SEATA_GROUP
      username: admin
      password: 123456
      namespace: 60e39b35-0229-4733-addf-fa9eedcd8e33
      #data-id: seata.properties
      #namespace: 5342dc77-dbb7-4ac7-ad72-9f65b71b1e94
  service:
    vgroupMapping:
      mjkf-agility-sys-manage-group: default
  client:
    rm:
      report-success-enable: false
  grouplist:
    default: 10.1.5.98:8091
           
seata1.4.0落地
seata1.4.0落地

2.10,業務代碼增加配置

@GlobalTransactional(rollbackFor = Exception.class)
           
seata1.4.0落地

注意:完成上述工作後,因為fegin調用需要綁定XID的傳遞,以下附上綁定代碼

建立一個配置類

import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author htf
 * @description
 * @date 2021-7-12 10:56
 */

@Configuration
public class FeignSupportConfig implements RequestInterceptor {
    /**
     * 解決服務直接調用請求頭不傳遞的問題
     * @param template
     */
    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                Map<String, Collection<String>> resolvedHeaders = new CaseInsensitiveKeyMap<>();
                resolvedHeaders.putAll(template.headers());

                while (headerNames.hasMoreElements()) {
                    String name = headerNames.nextElement();
                    if (!resolvedHeaders.containsKey(name)) {
                        String values = request.getHeader(name);
                        List<String> headers = new ArrayList<String>();
                        headers.addAll(Arrays.asList(values));
                        resolvedHeaders.put(name, headers);
                    }
                }
                template.headers(null);
                template.headers(resolvedHeaders);
            }
        }
        String xid = RootContext.getXID();
        if (StringUtils.isNotBlank(xid)) {
            template.header(RootContext.KEY_XID, xid);
        }
    }
}

然後再feigin調用server處添加此配置類就可以      
seata1.4.0落地

至此用戶端也配置完成。  一定要自己檢視官方文檔,避免踩空

過程中可能出現問題:

因為本人已經踩過很多坑,給出的配置檔案基本上已經是更改過的,此前出現過的一些報錯資訊及解決記錄:

1,用戶端服務一緻起不起來 一緻報錯

   Could not generate CGLIB subclass of class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper: 

   Common causes of this problem include using a final class or a non-visible class; 

   nested exception is org.springframework.cglib.core.CodeGenerationException: 

   java.lang.reflect.InvocationTargetException-->null

解決:yml配置檔案增加use-jdk-proxy: true  解決

2,seata服務端已啟動,用戶端還是一直報錯:

no available service found in cluster ‘default’, please make sure registry config correct and keep your seata server running

或者

can not get cluster name in registry config 'service.vgroupMapping.my_test_tx_group', please make sure registry config correct

解決:注意在nacos的seata-server服務與 nacos的配置中心分組保持一緻,都使用SEATA_GROUP

這個分組是在配置檔案裡 registry.conf配置檔案裡

seata1.4.0落地
seata1.4.0落地

關于這個報錯  還需要注意:config.txt裡的service.vgroupMapping.mjkf-agility-sys-manage-group=default(注:mjkf-agility-sys-manage-group 為自定義)這個配置即為nacos裡的配置

seata1.4.0落地

與yml檔案裡的這兩處一定要保持一緻,否在會此錯誤。

seata1.4.0落地

-----------------------------------------------------------------------------------------

相關資源:

https://download.csdn.net/download/u010185947/20065800