Seata使用教程

news2024/12/23 16:27:09

文章目录

    • 一、Seata简介
    • 1.Seata 概念介绍
    • 2.分布式事务
    • 3.Seata核心组件
    • 4.Seata 工作流程
    • 5.Seata四大模式
    • 二、Seata实战教程
    • 1.下载资源
    • 2.配置Seata-Server
    • 3.增加相关表结构
    • 4.代码配置
    • 三、常见报错解决

一、Seata简介

1.Seata 概念介绍

Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。

官方文档地址 http://seata.io/zh-cn/docs/overview/what-is-seata.html

2.分布式事务

我们可以将分布式事务理解成一个包含了若干个分支事务的全局事务。全局事务的职责是协调其管辖的各个分支事务达成一致,要么一起成功提交,要么一起失败回滚。通常分支事务本身就是一个满足 ACID 特性的本地事务。
分布式事务主要涉及以下概念:
事务:由一组操作构成的可靠、独立的工作单元,事务具备 ACID 的特性,即原子性、一致性、隔离性和持久性。
本地事务:本地事务由本地资源管理器(例如 MySQL、Oracle 等)管理,严格地支持 ACID 特性,高效可靠。本地事务不具备分布式事务的处理能力,只能对自己数据库的操作进行控制,对于其他数据库的操作则无能为力。
全局事务:全局事务指的是一次性操作多个资源管理器完成的事务,由一组分支事务组成。
分支事务:在分布式事务中,就是一个个受全局事务管辖和协调的本地事务。

3.Seata核心组件

(1)TC(Transaction Coordinator):事务协调器,它是事务的协调者(这里指的是 Seata 服务器),主要负责维护全局事务和分支事务的状态,驱动全局事务提交或回滚。
(2)TM(Transaction Manager):事务管理器,它是事务的发起者,负责定义全局事务的范围,并根据 TC 维护的全局事务和分支事务状态,做出开始事务、提交事务、回滚事务的决议。
(3)RM(Resource Manager):资源管理器,它是资源的管理者(这里可以将其理解为各服务使用的数据库)。它负责管理分支事务上的资源,向 TC 注册分支事务,汇报分支事务状态,驱动分支事务的提交或回滚。

4.Seata 工作流程

Seata 对分布式事务的协调和控制,主要是通过 XID 和 3 个核心组件实现的。
XID:是全局事务的唯一标识,它可以在服务的调用链路中传递,绑定到服务的事务上下文中
工作流程:
(1)TM 向 TC 申请开启一个全局事务,全局事务创建成功后,TC 会针对这个全局事务生成一个全局唯一的 XID;
(2)XID 通过服务的调用链传递到其他服务;
(3)RM 向 TC 注册一个分支事务,并将其纳入 XID 对应全局事务的管辖;
(4)TM 根据 TC 收集的各个分支事务的执行结果,向 TC 发起全局事务提交或回滚决议;
(5)TC 调度 XID 下管辖的所有分支事务完成提交或回滚操作。

概况一下就是每个分支事务都会有一个XID,全局事务会通过TC调度将所有XID相同的分支事务提交或者回滚。

5.Seata四大模式

四大模式分别是AT、TCC、SAGA 和 XA

5.1 AT模式(最常用、无业务入侵)
(1)使用前提:
①必须使用支持本地 ACID 事务特性的关系型数据库,例如 MySQL、Oracle 等;
②应用程序必须是使用 JDBC 对数据库进行访问的 JAVA 应用。
③创建一个 UNDO_LOG(回滚日志)表。(不同数据库建表语句不同,这里以mysql为例)
CREATE TABLE undo_log (
id bigint(20) NOT NULL AUTO_INCREMENT,
branch_id bigint(20) NOT NULL,
xid varchar(100) NOT NULL,
context varchar(128) NOT NULL,
rollback_info longblob NOT NULL,
log_status int(11) NOT NULL,
log_created datetime NOT NULL,
log_modified datetime NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_undo_log (xid,branch_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在后面提到的回滚日志中可以知道各个字段的作用

(2)AT模式的实现流程:
①获取 SQL 的基本信息,生成回滚日志,插入到 UNDO_LOG 表中,示例回滚日志如下。

{"@class":"io.seata.rm.datasource.undo.BranchUndoLog",
"xid":"2.0.1.47:8091:5791972543984050625",
"branchId":5791972543984050628,
"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"INSERT","tableName":"t00_user",
"beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords","tableName":"t00_user","rows":["java.util.ArrayList",[]]},
"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"t00_user","rows":["java.util.ArrayList",
[{"@class":"io.seata.rm.datasource.sql.struct.Row",
"fields":["java.util.ArrayList"[{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"user_id","keyType":"PRIMARY_KEY","type":12,"value":"338"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"user_name","keyType":"NULL","type":12,"value":"灏忕帇"}]]}]]}}]]}

②注册所有分支事务,生成行锁
③提交或回滚
提交:若所有分支事务都执行成功,TM 向 TC 发起全局事务的提交,并批量删除各个 RM 保存的 UNDO_LOG 记录和行锁,否则全局事务回滚;
回滚:
a.通过 XID 和分支事务 ID(Branch ID) 查找所有的 UNDO_LOG 记录;
b.数据校验:将 UNDO_LOG 中的后镜像数据(afterImage)与当前数据进行比较,如果有不同,则说明数据被当前全局事务之外的动作所修改,需要人工对这些数据进行处理;
c.生成回滚语句:根据 UNDO_LOG 中的前镜像(beforeImage)和业务 SQL 的相关信息生成回滚语句;
d.还原数据:执行回滚语句,并将前镜像数据、后镜像数据以及行锁删除;
e.提交事务:提交本地事务,并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。

二、Seata实战教程

1.下载资源

下载seata-server-XXX.zip和Srouce code
https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip
https://github.com/seata/seata/archive/refs/tags/v1.4.2.zip

2.配置Seata-Server

(1)将seata-1.4.2\script\config-center\config.txt 复制到 seata-server-1.4.2\ 目录下
替换下面几行:
service.vgroupMapping.tx_service_default_group=default
store.mode=db
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root

transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
service.vgroupMapping.tx_service_default_group=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=db
store.publicKey=
store.file.dir=file_store/data
store.file.maxBranchSessionSize=16384
store.file.maxGlobalSessionSize=512
store.file.fileWriteBufferCacheSize=16384
store.file.flushDiskMode=async
store.file.sessionReloadReadSize=100
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
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
store.redis.mode=single
store.redis.single.host=127.0.0.1
store.redis.single.port=6379
store.redis.sentinel.masterName=
store.redis.sentinel.sentinelHosts=
store.redis.maxConn=10
store.redis.minConn=1
store.redis.maxTotal=100
store.redis.database=0
store.redis.password=
store.redis.queryLimit=100
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

(2)将seata-1.4.2\script\config-center\nacos下文件复制到 seata-server-1.4.2\bin目录下
(3)修改seata-server-1.4.2\conf\file.conf

## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"
  ## rsa decryption public key
  publicKey = ""
  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai"
    user = "root"
    password = "root"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
    ## redis mode: single、sentinel
    mode = "single"
    ## single mode property
    single {
      host = "127.0.0.1"
      port = "6379"
    }
    ## sentinel mode property
    sentinel {
      masterName = ""
      ## such as "10.28.235.65:26379,10.28.235.65:26380,10.28.235.65:26381"
      sentinelHosts = ""
    }
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    maxTotal = 100
    queryLimit = 100
  }
}

(4)修改seata-server-1.4.2\conf\register.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
 
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "file"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
    dataId = "seataServer.properties"
  }

  file {
    name = "file.conf"
  }
}

(5)启动nacos,运行seata-server.bat

3.增加相关表结构

其中t00_user是测试用的表结构

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
--全局事务表--
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 分支表
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
-- 锁定表
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8;
 
--seata新版本加的锁表
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    PRIMARY KEY (`lock_key`)
    ) ENGINE = INNODB
    DEFAULT CHARSET = utf8mb4;
 
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

CREATE TABLE `t00_user`  (
  `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `user_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

4.代码配置

我这里没有使用多个服务,简单的使用了单个服务看回滚能不能成功。
项目结构如下:
在这里插入图片描述

(1)pom.xml

<dependencies>
        <!--  seata依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>2021.1</version>
        </dependency>

       <!-- <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>-->

        <!--mysql数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
            <scope>compile</scope>
        </dependency>


    </dependencies>

(2)bootstrap.yml

spring:
  #允许循环依赖
  main:
    allow-circular-references: true
  application:
    name: seata-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #不加allowPublicKeyRetrieval=true会报SQLNonTransientConnectionException
    url: jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
    username: root
    password: root
seata:
  application-id: seata-server
  tx-service-group: tx_service_default_group
  service:
    vgroup-mapping:
      tx_service_default_group: default



mybatis:
  #扫描mapper文件,Mapper文件一般放到resource下,如果放在java目录下,需要在pom文件的bulid标签下将.xml放到include下
  mapper-locations: classpath:mapping/*Mapper.xml

(3)测试的相关代码
SeataController .java

package com.example.seata.controller;

import com.example.seata.entity.User;
import com.example.seata.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
public class SeataController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/test")
    @ResponseBody
    public String test() {
        return "Sentinel server";
    }



    @RequestMapping(value="/getUser")
    @ResponseBody
    public List<User> getUser(){
        List<User> user = userService.getUser();
        return user;
    }

    @RequestMapping(value="/addUser")
    @ResponseBody
    public List<User> addUser(){
        userService.addUser();
        List<User> user = userService.getUser();
        return user;
    }



}





UserDAO.java

package com.example.seata.dao;

import com.example.seata.entity.User;

import java.util.List;

public interface UserDAO {

    List<User> getUser();

    void addUser(User user);
}


User.java

package com.example.seata.entity;

public class User {
    private String user_id;
    private String user_name;

    public String getUser_id() {
        return user_id;
    }

    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public User(String user_id, String user_name) {
        this.user_id = user_id;
        this.user_name = user_name;
    }
}


UserServiceImpl.java

package com.example.seata.service.impl;

import com.example.seata.dao.UserDAO;
import com.example.seata.entity.User;
import com.example.seata.service.UserService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDAO;

    @Override
    public List<User> getUser() {
        return userDAO.getUser();
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void addUser() {
        User user1 = new User("338","小王");
        User user2 = new User("339","大力");
        User user3 = new User("339","小毛");
        userDAO.addUser(user1);
        userDAO.addUser(user2);
        //加这一行是为了看undo_log,因为异常之后事务结束,undo_log会被删除
        try {
            new Thread().sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        userDAO.addUser(user3);

    }
}

UserService .java

package com.example.seata.service;

import com.example.seata.entity.User;

import java.util.List;

public interface UserService {

    public List<User> getUser();

    void addUser();
}


SeataApplication.java

package com.example.seata;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

import java.util.Arrays;

@SpringBootApplication
@MapperScan( "com.example.seata.dao")//使用MapperScan批量扫描所有的Mapper接口;
public class SeataApplication {

    public static void main(String[] args) {
        args = Arrays.copyOf(args,args.length + 1);
        args[args.length - 1] = "--spring.cloud.bootstrap.enabled=true";
        SpringApplication.run(SeataApplication.class, args);
    }

}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.seata.dao.UserDAO">
    <select id="getUser" resultType="com.example.seata.entity.User">
        SELECT * FROM t00_user
    </select>

    <select id="addUser" resultType="com.example.seata.entity.User">
        INSERT INTO t00_user (user_id, user_name)
                        VALUES (
                           #{user_id,jdbcType=VARCHAR}, #{user_name,jdbcType=VARCHAR}
                      )
    </select>
</mapper>

(4)启动项目
进入http://localhost:8080/addUser
发现报错,并且数据没有增加一条
如果将UserServiceImpl中的@GlobalTransactional(rollbackFor = Exception.class)去掉,会发现数据新增了两条。
说明注解使用成功,回归成功了
我这里为了看undo_log,在代码抛出异常前加上了Sleep5秒的操作,在这五秒内可以看到undo_log的情况
在这里插入图片描述

三、常见报错解决

1.Failed to get available servers: endpoint format should like ip:port
config.txt的service.vgroupMapping.tx_service_default_group=default中tx_service_default_group
与yml中的tx_service_default_group要一致
2.seata启动闪退/报错
修改seata-server.bat,这样就能看到报错信息了
if “%FORCE_EXIT_ON_ERROR%” == “on” (
if %ERROR_CODE% NEQ 0 exit %ERROR_CODE%
)
cmd
exit /B %ERROR_CODE%
3.数据库连接不上
mysql5.+使用 driverClassName = “com.mysql.jdbc.Driver”
mysql8使用 driverClassName = “com.mysql.cj.jdbc.Driver”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eNSP 设备启动失败,错误代码:40 解决方案

eNSP 路由器启动失败&#xff0c;错误代码&#xff1a;40 解决方案 eNSP 路由器启动失败&#xff0c;错误代码&#xff1a;40 解决方案 文章目录eNSP 路由器启动失败&#xff0c;错误代码&#xff1a;40 解决方案一、出现错误代码&#xff1a;40二、解决方法1.确定相关的软件安…

《设计模式》外观模式

《设计模式》外观模式《设计模式》设计模式的基本原则 《设计模式》单例模式 《设计模式》工厂模式 《设计模式》原型模式 《设计模式》建造者模式 《设计模式》适配器模式 《设计模式》桥接模式 《设计模式》装饰者模式 《设计模式》组合模式 《设计模式》外观模式 定义&#…

免费刷题!初级软件测试面试题目和答案这个小程序很全

有没有软件测试面试题库小程序&#xff1f;相信这是很多准备找工作的新手测试人都想要知道的吧&#xff01; 今天&#xff0c;我就根据大家的需求&#xff0c;为大家整理了一些有关初级软件测试的面试题目以及一个可以免费刷题的题库&#xff0c;希望能帮助你们早日拿下心仪的…

UDS-10 Diagnostic and communication management functional unit

10 诊断与通信管理功能单元 来自&#xff1a;ISO 14229-1-2020.pdf 10.1概述 表22指定了诊断和通信管理功能单元。 注&#xff1a; DiagnosticSessionControl&#xff1a;客户端请求控制服务器的诊断会话。ECUReset&#xff1a;客户端强制服务器执行重置。SecurityAccess&am…

知识蒸馏原理

文章目录0.知识蒸馏&#xff08;模型压缩的一种方法&#xff09;1.蒸馏2.为什么要蒸馏3.知识的表示与迁移4.蒸馏温度T5.知识蒸馏过程6.知识蒸馏的应用场景7.知识蒸馏背后的机理8.为什么用soft targets 而不用 label smoothing?9.知识蒸馏的研究方向10.知识蒸馏代码库11.扩展阅…

回顾2022,展望2023,笔耕不辍,钟情翰墨

目录 回顾2022 博客概览 博客成就 获得测试领域优质创作者认证 获得博客专家认证 获得额外收入 创建第一个属于自己的个人社区 获得第一个实体奖牌【博客专家】 首次登榜梦想照进现实CSDN实体奖牌榜 首次参与社区新锐和社区先锋评选 开启了6个知识体系系列教程 个人…

2023春招面试:消息中间件面试题整理

RabbitMQ如何确保消息发送 &#xff1f; 消息接收&#xff1f; 开启生产者确认机制&#xff0c;确保生产者的消息能到达队列&#xff08;config机制保证消息正确到达交换机、return机制保证消息正确到达队列&#xff09;开启持久化功能&#xff0c;确保消息未消费前在队列中不会…

如何通过WindowsIIS部署网站

1.winR输入control 打开【控制面板】 2.选择程序 3.选择【启用或关闭Windows功能】 4.在【Windows功能】对话框中勾选【Internet Information Services】下的【FTP服务器】、【Web管理工具】和【万维网服务】中的所有选项&#xff0c;并点击【确定】 5.Windows功能会开始下载并…

Lambda表达式的来龙去脉,全在这篇文章里了

一. 前言部分 大家都知道Lambda表达式作为JAVA 8中提供的新特性之一&#xff0c;在现在的企业开发中已经非常的流行了。今天壹哥就通过一个具体的案例&#xff0c;来带大家一起详细地探究一下Lambda表达式是如何被提出来的&#xff0c;以及它的出现主要是用来解决什么问题的。…

乌班图(Ubuntu)单系统或者乌班图+Win双系统安装教程

单ubuntu系统安装 1、将ubuntu系统U盘插入电脑USB接口&#xff0c;建议优先插USB3.0蓝色(彩色)接口&#xff0c;这样可以保证安装过程中文件的读取速度&#xff0c;加快安装进程。 2、然后电脑关机状态下&#xff0c;开机。开机后快速按主机的快捷启动键&#xff1a; 3、在出现…

Qt编写雷达模拟仿真工具1-背景布局

一、前言 雷达模拟仿真工具&#xff0c;整体结构采用的QGraphicsView框架&#xff0c;背景布局采用的分层绘制&#xff0c;这样可以控制该需要重新绘制的重新绘制&#xff0c;不需要重新的绘制的就没必要再多余的浪费&#xff0c;这里定义了一个GraphicsBackGroundItem类继承自…

Spring框架(容器)--简介(实现原理、核心模块、组成部分)

spring框架&#xff08;容器&#xff09; spring简介 1、Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言&#xff0c;任何Java应用都可以从Spring中受益。 2、Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。 3、轻量——从大小…

Creo9.0 Windows 3D建模工具

前言 creo9.0正式版是一款非常优秀的3D建模设计软件。该软件界面美观&#xff0c;提供了CAD 技术、模制造绘图、多实体建模、多体设计、实时仿真、框架和焊缝设计等一系列强大的辅助设计功能&#xff0c;通过这些功能&#xff0c;让用户轻松解决设计中带来的各种问题。 下载 …

律所管理系统的功能以及作用分别有哪些?

在全球进入信息化的时代&#xff0c;随着网络的普及与发展&#xff0c;网络所带来的信息交流与利用的优势愈发明显。尤其是随着法律制度的不断健全和人民法律意识的提高&#xff0c;涉及法律诉讼的案件也在不断地增加&#xff0c;律师事务所作为中介的法律机构&#xff0c;要处…

字符设备驱动(一)

1.Linux设备分类 linux的文件种类&#xff1a; -&#xff1a;普通文件 文件内容文件名元信息&#xff08;文件的相关属性—组织在inode的一个结构体内&#xff09; d&#xff1a;目录文件 p&#xff1a;管道文件 s&#xff1a;本地socket文件 l&#xff1a;链接文件 软链接&am…

4 内部类实例

内部类 内部类的分类&#xff1a; 成员内部类方法内部类局部内部类匿名类静态内部类 1 成员内部类 是在一个类中声明的类&#xff0c;包含内部类的是外围类 成员内部类的访问权限&#xff1a; public可以在外围类的外部使用内部类创建对象private只能在外围类的内部使用内…

提升Mac使用性能的5大方法,都非常的好用哦~

是不是发现你的 Mac 越用运行速度会越慢&#xff1f;没错&#xff0c;任何电子设备&#xff0c;随着使用时间的增加&#xff0c;都会出现不如刚买时那么流畅的问题。Mac当然也不能例外&#xff0c;它的运行速度会随着使用时长的递增而有所下降&#xff0c;所以为 Mac 提速也是十…

CSS总结(网页布局:标准流 浮动 定位)

CSS 主要的功能是布局页面&#xff0c;增加标签的样式和部分交互效果。 资料来源&#xff1a;黑马 目录 元素显示 块级元素 行内元素 行内块元素 显示模式的转换 CSS三个特点 盒子模型 传统三种布局 标准流 浮动 结合浮动和标准流可以搭建出常见的网页布局: 清除…

Java Integer.toBinaryString() 方法源码及原理解析(进制转换、位运算)

title: Java Integer.toBinaryString() 方法源码及原理解析&#xff08;进制转换、位运算&#xff09; date: 2022-12-27 17:31:38 tags: Java categories:Java cover: https://cover.png feature: false 1. 使用及源码概览 Integer.toBinaryString() 方法用于将十进制整数转…

【1 - 决策树 - 案例部分:泰坦尼克号幸存者预测】菜菜sklearn机器学习

课程地址&#xff1a;《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili 第一期&#xff1a;sklearn入门 & 决策树在sklearn中的实现第二期&#xff1a;随机森林在sklearn中的实现第三期&#xff1a;sklearn中的数据预处理和特征工程第四期&#xff1a;sklearn中的降维算法…