精华内容
下载资源
问答
  • dubbo与spring4集成maven pom文件 此pom为我生产项目中的配置,开始想省事使用spring boot,结果与springmvc不兼容,导致tomcat启动失败,后来找了maven shade来打包,解决了xsd兼容问题 另外注意,dubbo阿里的分支...
  • 必要的jar依赖都已配置好,基本都采用较新版本,花了好几天时间去测试兼容性,oracle驱动Maven中心库没有的jar也放置在lib目录 因此,此Demo在基础和细微的地方都处理得相当周到,10分钱所谓是物有所值
  • 1.标题所提及技术的整合,...必要的jar依赖都已配置好,基本都采用较新版本,花了好几天时间去测试兼容性,oracle驱动Maven中心库没有的jar也放置在lib目录 因此,此Demo在基础和细微的地方都处理得相当周到
  • Maven安装及配置

    2020-08-09 17:25:44
    Maven 官网:http://maven.apache.org/ 一、为什么要用Maven 在开发中经常需要依赖第三方的之间存在依赖...1.你要使用dom4j就要去dom4j官网下载,要使用spring也要去对应的网站下载。 2当某些jar有依赖

    Maven

    官网:http://maven.apache.org/
    一、为什么要用Maven
    在开发中经常需要依赖第三方的包,包与包之间存在依赖关系,版本间还有兼容性的问题,有时候还要将旧的包升级或者降级,当项目复杂到一定程度是包管理就变得非常重要。
    Maven提供了开发人员构建完整额生命周期框架,Maven主要做了两件事:
    1.统一开发规范与工具
    2.统一管理jar包
    如果没有Maven:
    1.你要使用dom4j就要去dom4j官网下载包,要使用spring也要去对应的网站下载包。
    2当某些jar包有依赖的时候,还要去下载对应的依赖jar包。
    有了Maven后:
    1.依赖的管理:仅仅通过jar包的几个属性,就能确定唯一的jar包,在指定的文件pom.xml中,只要写入这些依赖属性,就会自动下载和管理这些jar包。
    2.项目的构架:内置很多的插件与生命周期,支持多种任务。
    3.项目的知识管理:管理项目相关的其他内容。
    二、安装与配置
    2.1
    在这里插入图片描述
    2.2配置环境变量
    注意:配置之前必须确保电脑中有JDK。
    1.解压压缩包
    在这里插入图片描述
    2. 添加环境变量Maven_home.
    在这里插入图片描述
    3.在path环境变量的变量值末尾添加%Maven_Home%\bin;
    在这里插入图片描述
    4.在cmd输入mvn --version,如果出现maven信息,说明配置成功了

    在这里插入图片描述
    3.本地仓储配置
    如果不配置,默认会在C盘User、Administrator下存放从远程下载到的包;
    配置:
    1.打开maven文件夹,打开conf目录下的setting.xml文件。
    在这里插入图片描述
    在这里插入图片描述
    4.阿里仓库配置
    也是在setting.xml里面操作。
    在这里插入图片描述
    5.配置到Eclipse中

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    新建之后把J2SE-1.5版本的删掉,换成1.8的
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • springcloud H版+alibaba cloud419,sleuth链路追踪20,spring...#springcloud F版本起就不需要自己maven构建zipkin了。只需要调用jar即可 把jar下载下来放到一个盘 运行java -jar jar名 修改服务提供者cloud-p

    19,sleuth链路追踪

    sleuth提供了一套完整的服务追踪解决方案
    在分布式系统中提供追踪解决方案并且兼容支持zipkin

    #springcloud F版本起就不需要自己maven构建zipkin了。只需要调用jar包即可

    把jar包下载下来放到一个盘
    运行java -jar jar包名

    修改服务提供者cloud-provider-payment8001
    修改服务消费者cloud-consumer-order80

    8001:
    pom新增

    <!--包含了sleuth+zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    

    yml

    zipkin:
      base-url: http://localhost:9411
    sleuth:
      sampler:
        probability: 1
    

    controller

    @GetMapping("/payment/zipkin")
    public String paymentZipkin(){
        return "hi, i'am paymentzipkin server fall back,welcome to atguigu, O(∩_∩)O哈哈~";
    }
    

    80
    pom和yml一样

    controller

    //============> zipkin + sleuth
    @GetMapping("/consumer/payment/zipkin")
    public String paymentZipkin(){
        String result = restTemplate.getForObject("http://localhost:8001" + "/payment/zipkin", String.class);
        return result;
    }
    

    启动7001,8001,80,调用80的controller接口形成链路。。。。然后刷新9411的web界面。。。可以看到链路追踪详细信息

    在这里插入图片描述

    20,springcloud alibaba

    springcloud alibaba做了一件包饺子的事情

    dubbo被springcloud包饺子
    cloud又被alibaba cloud包饺子

    springcloud alibaba官网
    https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

    springalibaba 支持的功能
    服务限流降级
    服务注册与发现
    分布式配置管理
    消息驱动能力:rocketMq
    阿里云对象存储
    分布式任务调度

    如果需要使用springcloud alibaba,则在父工程的root的pom里引入

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

    springcloud alibaba的各大组件:

    sentinel ,nacos,Rocket,Dubbo,seata,oss,schedulerX

    21,nacos

    nacos:Naming configuration service

    服务注册发现与配置中心服务组件

    下载地址:
    https://github.com/alibaba/Nacos

    官方学习文档也从这进
    https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

    nacos和eureka都是保证AP,高可用和分区容错性。Nacos还保证了cp

    1,nacos下载后直接找到bin下的startup.cmd,启动即可

    2,访问http://localhost:8848/nacos
    用户名,密码都是nacos

                        nacos服务注册与发现
    

    #编码
    1,新建项目cloudalibaba-provider-payment9001
    2,pom新增

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

    3,yml

    server:
      port: 9001
    
    spring:
      application:
        name: nacos-payment-provider
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #配置Nacos地址
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'  #监控
    

    4,主启动类

    package com.atguigu.springcloud.alibaba;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    /**
     * @author wsk
     * @date 2020/3/23 10:21
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentMain9001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain9001.class,args);
        }
    }
    

    5,主业务类

    package com.atguigu.springcloud.alibaba.controller;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    /**
     * @author wsk
     * @date 2020/3/23 10:27
     */
    @RestController
    public class PaymentController {
        @Value("${server.port}")
        private String serverPort;
    
        @GetMapping("/payment/nacos/{id}")
        public String getPayment(@PathVariable("id") Integer id){
            return "nacos registry,serverPort: "+ serverPort+"\t id"+id;
        }
    }
    

    测试启动9001,访问localhost:9001/payment/nacos/1
    在这里插入图片描述

                                              nacos负载均衡
    

    1,参照9001新建9002
    2,新建微服务消费者83
    cloudalibaba-consumer-nacos-order83
    pom跟提供者一样

    yml

    server:
      port: 83
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
    

    #消费者将要去访问的微服务名称(成功注册进nacos的微服务提供者),在这配置了访问的服务,业务类就不用在定义常量了

    service-url:
      nacos-user-service: http://nacos-payment-provider
    

    主启动类一样
    配置类

    package com.atguigu.springcloud.alibaba.config;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    /**
     * @author wsk
     * @date 2020/3/23 11:07
     */
    @Configuration
    public class ApplicationContextConfig {
        @Bean
        @LoadBalanced   //RestTemplate结合Ribbon做负载均衡一定要加@LoadBalanced
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    

    业务类

    package com.atguigu.springcloud.alibaba.controller;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    import javax.annotation.Resource;
    /**
     * @author wsk
     * @date 2020/3/23 11:09
     */
    @RestController
    public class OrderNacosController {
        /*
        因为在yml中配置了service-url.nacos-user-service,
        这里不需要再定义要访问微服务名常量,而是通过boot直接读出来
         */
        @Value("${service-url.nacos-user-service}")
        private String serverURL;
    
        @Resource
        private RestTemplate restTemplate;
    
        @GetMapping("/consumer/payment/nacos/{id}")
        public String paymentInfo(@PathVariable("id") Long id){
            return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
        }
    }
    

    启动9002
    启动83
    然后看nacos
    在这里插入图片描述

    再访问80的接口localhost:83/consumer/
    在这里插入图片描述

    在这里插入图片描述

    nacos是cp+ap的支持HTTP/DNS/UDP协议的各种支持的强大的组件

    #nacos ap和cp的切换
    AP模式支持是springcloud,保证了高可用和分区容错性。只支持注册临时实例
    CP模式是k8s,保证强一致性和分区容错性

    AP和cp可以互相切换
    切换命令

    curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
    
                       nacos配置中心
    

    #编码
    1,新建cloudalibaba-config-nacos-client3377
    2,pom新增

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

    3,yml 两个
    bootstrap.yml

    server:
      port: 3377
    
    spring:
      application:
        name: nacos-config-client
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #Nacos服务注册中心地址
          config:
            server-addr: localhost:8848 #Nacos作为配置中心地址
            file-extension: yml
    

    application.yml

    spring:
      profiles:
        active: dev #
    

    4,主启动类

    package com.atguigu.springcloud.alibaba;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    /**
     * @author wsk
     * @date 2020/3/23 12:28
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class NacosConfigClientMain3377 {
        public static void main(String[] args) {
            SpringApplication.run(NacosConfigClientMain3377.class,args);
        }
    }
    

    5,业务类

    package com.atguigu.springcloud.alibaba.controller;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    /**
     * @author wsk
     * @date 2020/3/23 12:30
     */
    @RestController
    @RefreshScope   //SpringCloud原生注解 支持Nacos的动态刷新功能
    public class ConfigClientController {
    
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping("/config/info")
        public String getConfigInfo(){
            return configInfo;
        }
    }
    

    6,在nacos里添加规则
    规则是

    ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
    

    所以根据以上配置

    Data Id   :nacos-config-client-dev.yml
    

    在这里插入图片描述
    在这里插入图片描述

    启动3377,访问localhost:3377/config/info
    在这里插入图片描述

                                            动态刷新
    

    直接修改nacos配置中心的yaml文件,version改成20,在访问接口
    在这里插入图片描述

                                            nacos高级篇
    

    nacos对于多环境多项目的管理十分强大,不仅对生产,开发,测试环境都能管理,而且对其他的公司的外包项目的环境也能管理

    由nacos的namespace+Group+DataID三者构成
    namespace:用于区分部署环境的
    Group和DataID用于逻辑上区分两个目标对象

    默认情况下:namespace:public
    Group:DEFAULT_GROUP
    默认的集群cluster也是DEFAULT

    Group可以把不同的微服务划分到同一个分组里面去

    #######三种配置方式
    1,DataId级别的配置
    在原基础上再新建一个nacos-config-client-test.yaml
    配置内容

    config:
        info: from nacos config center,nacos-config-client-test.yaml ,version=2
    

    application.yml里改active改成test就可以访问后面这个新加的配置了
    在这里插入图片描述

    2,group级别的配置
    (1)新建配置

    DataId: nacos-config-client-info.yaml
    

    Group:DEV_GROUP
    配置内容:

    config:
        info: nacos-config-client-info.yaml,DEV_GROUP
    

    (2)新建配置

    DataId: nacos-config-client-info.yaml
    Group:TEST_GROUP
    

    配置内容:

    config:
        info: nacos-config-client-info.yaml,TEST_GROUP
    

    (3)修改bootstrap.yml和application.yml
    1,bootstrap
    config下增加

    group: TEST_GROUP
    

    2,application

    active: info
    在这里插入图片描述

    重启后访问controller
    在这里插入图片描述

    3,namespace命名空间方案
    (1)新建dev/test的namespace
    点击命名空间,新建命名空间
    dev和test

    (2)选择dev 点+号

    Dataid :nacos-config-client-dev.yaml
    

    配置内容:

     config:
        info: xxxxxxxxx  DEFAULT_GROUP
    

    回到bootstrap
    group下面配置一行

    namespace:  命名空间id
    

    (3)dev下再新建配置

    nacos-config-client-dev.yaml
    Group: DEV_GROUP
    

    配置内容:

     config:
         info: xxxxxxxxx,DEV-GROUP
    

    (4)dev下再新建配置

    nacos-config-client-dev.yaml
    Group:TEST_GROUP
    

    配置内容:

    config:
           info: xxxxxxxxx,TEST_GROUP
    

    到此为止dev下有三个配置文件。相同命名空间不同组配置
    重启服务,访问成功。test命名空间下道理一样不在赘述

                              nocas集群和持久化
    

    8848挂掉了,所有的玩完?
    至少得有3台nacos

    nocas为什么关闭服务以后。数据还存在。关闭电脑再启动还存在。因为它本身有一个嵌入式数据库,那么有了数据库为什么还要持久化集群mysql?因为多个nacos嵌入式数据库造成数据一致性问题得不到解决

    nacos底层源码:
    https://github.com/alibaba/nacos/blob/develop/config/pom.xml

    在这里插入图片描述

    默认自带derby嵌入式数据库坐标

    derby----mysql的配置
    1,nacos-server-1.1.4\nacos\conf目录下找到nacos-mysql.sql
    2,到sqlyog执行sql脚本
    3,nacos-server-1.1.4\nacos\conf目录下找到application.properties
    4,mysql版本在5.6.5以上
    application下粘贴

    spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?
    characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
    
    db.user=root
    db.password=ljs
    

    5,重启nacos会发现有一个空的页面

    6,新建配置
    在这里插入图片描述

    7,发现数据库

    在这里插入图片描述

                                   linux下搭建生产环境下的nacos集群+mysql+nginx
    

    1,下载linux版本的nacos
    https://github.com/alibaba/nacos/releases/tag/1.1.4
    跟之前windows的一样也是找到sql文件。然后复制到linux的数据库下。然后修改配置文件。。

    直接参考这篇文章。。。https://www.cnblogs.com/larscheng/p/11427733.html

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    代码实例

    修改9002 nacos的服务提供者yml文件

    在这里插入图片描述
    在这里插入图片描述

    注册成功。nacos

    22,sentinel

    alibaba sentinel 实现熔断和限流

    #官方文档
    github.com/alibaba/sentinel

    之前的hystrix
    1,需要自己手工搭建监控平台
    2,没有web界面可给我们进行更加细粒化的配置
    以及流控,速率控制。服务熔断,服务降级

    sentinel:
    1,单独一个组件,可独立出来
    2,直接姐棉花细粒度统一配置

    下载地址:https://github.com/alibaba/sentinel/releases
    下载1.7的sentinel-dashboard.jar

    sentinal分为两个部分:
    核心库:(java客户端)不依赖任何框架/库。能够运行于所有java运行时环境。对dubbo/springcloud框架也有很好的支持

    控制台:基于springboot开发。打包后可直接运行不需要额外的tomcat等应用容器

    运行jar包以后访问localhost:8080

    用户名密码都是sentinel
    在这里插入图片描述

                         sentinel的初始化监控
    

    #编码
    1,启动nacos8848

    2,新建cloud-alibaba-sentinel-service 8401

    3,pom

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--springcloud alibaba sentinel-datasource-nacos 后续做持久化用到-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <!--springcloud alibaba sentinel-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    4,yml

    server:
      port: 8401
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            # Nacos服务注册中心地址
            server-addr: localhost:8848
        sentinel:
          transport:
            # sentinel dashboard 地址
            dashboard: localhost:8080
            # 默认为8719,如果被占用会自动+1,直到找到为止
            port: 8719
    management:
      endpoints:
        web:
          exposure:
            include: "*"      
    

    5,主启动类

    package com.atguigu.springcloud.alibaba;
            import org.springframework.boot.SpringApplication;
            import org.springframework.boot.autoconfigure.SpringBootApplication;
            import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    /**
     * @author wsk
     * @date 2020/3/24 13:59
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class MainApp8401 {
        public static void main(String[] args) {
            SpringApplication.run(MainApp8401.class,args);
        }
    }
    

    6,controller

    package com.atguigu.springcloud.alibaba.controller;
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    /**
     * @author wsk
     * @date 2020/3/24 14:00
     */
    @RestController
    @Slf4j
    public class FlowLimitController {
    
        @GetMapping("/testA")
        public String testA(){
            return "--------testA";
        }
    
        @GetMapping("/testB")
        public String testB(){
            return "--------testB";
        }
    }
    

    7,启动8401
    访问接口http://localhost:8401/testA
    在这里插入图片描述

                                        sentinel 流控规则
    

    流量控制:
    资源名就是我们的application -name
    唯一的。或者默认请求路径

    针对来源就是:sentinel可以针对调用者进行限流。填写微服务名。默认default

    阈值类型/单机阈值
    qps:当调用该api的qps达到阈值的时候,进行限流
    线程数:当调用该api的线程数达到阈值的时候进行限流
    是否集群:sentinel不需要

    流控模式
    直接:api达到限流条件时,直接限流
    关联:当关联资源达到阈值,限流自己
    链路:只记录指定链路上的流量

    流控效果:
    快速失败:直接失败,抛异常
    warm up:根据codeFactor(冷加载因子。默认3)的值,从阈值codeFactor,经过预热时长,才达到设置的qps值
    排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须为qps,否则无效

                          流控模式
    

    1,qps:
    设置单机阈值 1
    流控模式:直接
    流控效果:快速失败
    在这里插入图片描述

    快速点击

    在这里插入图片描述

    2,线程数
    在sentinel设置
    在这里插入图片描述

    然后回到testA修改testA方法

    @GetMapping("/testA")
    public String testA(){
        try{
            TimeUnit.MILLISECONDS.sleep(800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "--------testA";
    }
    

    然后开两个浏览器模拟多线程

    在这里插入图片描述

    流控模式:1,关联
    相当于我生病,你吃药?这有什么用?
    #通常用于支付模块达到阈值,限流订单模块。

    配置规则
    testA
    阈值类型qps 单机阈值1
    流控模式:关联
    关联资源:/testB
    流控效果:快速失败
    打开postman 模拟多线程访问testB
    在这里插入图片描述
    在这里插入图片描述

    找到collections
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    模拟20个线程,每延迟300毫秒访问testB

    这期间访问testA
    在这里插入图片描述

    这之后访问

    在这里插入图片描述
    流控效果:default
    直接失败:抛出异常

    Blocked by sentinel(flow limiting)

                         流控效果:预热:warm up
    

    设置 资源名:/testB
    针对来源:default
    阈值类型:qps 单机阈值10
    预热时长 5 流程模式:直接

    在5秒钟阈值慢慢从3-10
    访问浏览器很快刷新页面。刚开始不行。慢慢过了5秒的样子能抗住了

    如秒杀系统在开启的瞬间,会有很多流量上来。很有可能把系统打死。预热方式就是为了保护系统,慢慢将流量放进来。慢慢把阈值增长到设置的阈值

    冷加载因子=单机阈值/3
    根据warm up 设置时间慢慢qps由单机阈值/3-----单机阈值

                          流程效果:排队等待
    

    让请求以均匀的速度通过,阈值类型必须设置成qps否则无效
    设置:资源名:/testA
    阈值类型:qps 单机阈值:1
    流控模式:直接
    流控效果:排队等待
    超时时间:20000

    意思是:/testA每秒1次请求。超过就排队等待,等待的超时时间为20000毫秒

    相当于在某一秒有大量请求。接下来空闲。一会又有大量请求。我们可以在空闲时间处理剩下的请求。而不是在第一秒就直接拒绝了

    回到idea在testB方法里加

    log.info(Thread.currentThread().getName()+"\t"+"...testB");
    

    在这里插入图片描述

                                       sentinel降级
    

    点击降级规则,右上角–+新增降级规则
    有三种策略:RT,异常比例,异常数

    RT:平均响应时间:秒级
    平均响应时间超出阈值,且时间窗口内通过的请求>=5两个条件同时满足触发降级。窗口期过后关闭断路器。RT最大为4900

    异常比例:秒级
    qps>=5且异常比例(秒级)超过阈值。触发降级。时间窗口结束后。关闭降级

    异常数(分钟级)
    异常数(分钟统计)超过阈值时。触发降级,时间窗口结束后,关闭降级

    sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时候(例如调用超时或异常比例升高),对这个资源的调用进行限制。让请求快速失败。避免影响到其他资源导致级联错误

    当资源被降级后,在接下来降级时间窗口内。对该资源的调用都自动熔断。默认抛出DegradeException

    Hystrix有open closed halfopen状态
    sentinel没有半开状态

    1,RT
    平均响应时间:1秒持续5个请求。且平均响应时间大于阈值,触发降级。时间窗口期结束。关闭降级

    回到controller

    @GetMapping("/testD")
    public String testD(){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 测试 RT");
        return "--------testD";
    }
    

    回到sentinel dashboard —簇点链路–选择降级–选RT–RT200–时间窗口1

    使用jmeter压测
    在这里插入图片描述

    线程数设置10
    在这里插入图片描述
    Ramp-up perviod(in seconds):1
    循环次数:永远

    启动项目,再启动jmeter

    再访问接口localhost:8401/testD
    会出现降级
    在这里插入图片描述

    #为什么会这样呢?
    根据jmeter的设置。永远一秒打进10个线程。大于5个。调用testD。我们希望200ms处理完本次任务。如果超过200ms没有处理完。在未来一秒钟内的时间窗口内。断路器打开。微服务不可用

    2,异常比例
    异常比例:当资源的每次请求量>=5,并且每秒异常总数占通过量比值超过阈值之后。资源进入降级状态,即在接下的时间窗口内,对这个方法调用都会自动地返回。异常比例的阈值范围在[0.0,1.0]。0%-100%

    qps>=5&&异常比例超过阈值,触发降级,时间窗口期结束,关闭降级

    将/testD代码改为。。

    @GetMapping("/testD")
    public String testD(){
        log.info("testD 测试 RT");
        int age=10/0;
        return "--------testD";
    }
    

    sentinel的设置
    异常比例-0.2–时间窗口1

    jmeter依旧和刚才一样设置跑起来
    在这里插入图片描述

    停掉jmeter
    在这里插入图片描述
    3,异常数
    异常数:当资源近一分钟的异常数目超过阈值之后会进行熔断:时间窗口一定大于60秒。因为它是分钟级的

    异常数超过阈值—降级—时间窗口结束----关闭降级

    controller

    @GetMapping("/testE")
    public String testE(){
        log.info("testE测试异常数");
        int age = 10/0;
        return "--------testE 测试异常数";
    }
    

    sentinel设置—异常数–5--时间窗口61

    访问localhost:8401/testE
    访问5次以后才触发降级

    在这里插入图片描述

                      sentinel热点key限流
    

    官网:github.com/alibaba/sentinel/wiki/热点参数限流

    像hystrix某个方法出问题了,去找对应兜底方法降级。这是我们自定义的

    像sentinel不配置的话。默认提示Blocked by sentinel(flow limiting)

    可以配置Sentinel的@SentinelResource

    热点限流key的原理
    官网源码:com.alibaba.csp.sentinel.slots.block.BlockException

    #编码
    controller

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2){
        return "testHotKey";
    }
    public String deal_testHotKey(String p1, String p2, BlockException exception){
        return "---------------deal_testHotKey,o(╥﹏╥)o";
    }
    

    sentinel设置热点限流规则
    资源名:testHotKey
    参数索引:0
    单机阈值:1
    窗口时长:1

    正常访问
    在这里插入图片描述
    点击速度加快
    在这里插入图片描述

    #如果用了@SentinelResource一定要指定value的同时,指定blockhandler否则会有异常页面。用户看到不太好

                       热点key参数例外项
    

    在编辑热点规则下面有个高级选项

    当我们设定了p1这个参数为0的索引。一旦qps>1则熔断限流。可不可以p1的值如果等于一个特定的值。则让他不熔断限流呢

    设置参数例外项。记得不要忘记添加按钮

    参数类型只能支持String加8种基本数据类型
    参数值:5
    限流阈值:200
    添加

    然后访问接口

    在这里插入图片描述
    在这里插入图片描述

    如果在testHotKey方法添加一行代码:
    int age=10/0;
    在这里插入图片描述
    所以直接的@SentinelResource不管运行时异常

                         系统自适应限流
    

    sentinel
    点击系统规则—新增系统规则
    load自适应
    只支持linux,unix系统。

    如果设置了入口qps则掌握全局qps阈值设置1

      #####           SentinelResource配置
    

    1,按资源名称限流+后续处理
    #编码
    (1)修改pom
    增加一个

    <dependency>
        <groupId>com.atguigu.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    

    (2)新建controller
    @RestController

    public class RateLimitController {
    
        @GetMapping("/byResource")
        @SentinelResource(value = "byResource",blockHandler = "handlerException")
        public CommonResult byResource(){
            return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
        }
        public CommonResult handlerException(BlockException exception){
            return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
        }
        }
    

    (3)sentinel–流控规则–新建资源名byResource-阈值类型qps-单机阈值1

    启动nacos,sentinel,8401项目
    访问localhost:8401/byResource狂点会进入兜底
    在这里插入图片描述

    正常点。正常访问

    在这里插入图片描述
    平时关闭8401微服务。流控规则会消失。所以它是临时节点

    2,按照url地址限流

    在controller增加一个方法
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value=“byUrl”)
    public CommonResult byurl(){
    return new CommonResult(200,“按url限流ok”,new Payment(2020L,“Serial002”));
    }

    这个sentinel设置直接加一个左斜杠

    在这里插入图片描述
    不好用就去掉斜杠,好用了
    ,但是没有指定blockHandler肯定刷快了会爆异常页面

    3,兜底方法存在问题
    每个业务都有一个兜底方法,像hystrix一样,可以解耦。写一个fallback类?可以!

    客户自定义限流
    (1)创建CustomerBlockHandler类

    package com.atguigu.springcloud.alibaba.handler;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    /**
     * @author wsk
     * @date 2020/3/24 22:04
     */
    public class CustomerBlockHandler {
    
        public static CommonResult handlerException(BlockException exception){
            return new CommonResult(4444,"按客户自定义,global handlerException-----1");
        }
        public static CommonResult handlerException2(BlockException exception){
            return new CommonResult(4444,"按客户自定义,global handlerException-----2");
        }
    }
    

    (2)RatelimitController添加方法

    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler(){
        return new CommonResult(200,"按客户自定义",new Payment(2020L,"serial002"));
    }
    

    启动8401

    访问这个接口

    然后设置sentinel
    在这里插入图片描述

    平时访问
    在这里插入图片描述
    兜底访问
    在这里插入图片描述
    sentinel熔断
    sentinel注解不支持private只支持public

    服务熔断采取整合ribbon或openFeign+fallback

    1,修改cloudalibaba-provider-payment9003/9004

    package com.atguigu.springcloud.controller;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.HashMap;
    /**
     * @author wsk
     * @date 2020/3/24 22:36
     */
    @RestController
    public class PaymentController {
    
        @Value("${server.port}")
        private String serverPort;
    
        public static HashMap<Long, Payment> hashMap = new HashMap<>();
        static {
            hashMap.put(1L,new Payment(1L,"28adsasadsafas5d1as5fad5as31d3as0"));
            hashMap.put(2L,new Payment(2L,"4das5d5asda4dad5asda5s3dasd53das0"));
            hashMap.put(3L,new Payment(3L,"6ads65d351as3d1as53d1a53d3as13as0"));
        }
    
        @GetMapping("/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
            Payment payment = hashMap.get(id);
            CommonResult<Payment> result = new CommonResult(200, "from mysql ,serverPort: " + serverPort);
            return result;
        }
    }
    

    2,84作为消费者端调9003/9004实现负载均衡
    修改84
    第一种情况。没有任何配置的

    package com.atguigu.springcloud.controller;
    
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    import com.atguigu.springcloud.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.Resource;
    
    /**
     * @author wsk
     * @date 2020/3/24 23:06
     */
    @RestController
    @Slf4j
    public class CircleBreakerController {
        private static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
       @SentinelResource(value = "fallback") //没有配置
    //    @SentinelResource(value = "fallback",fallback = "handlerFallback") //配置了fallback的,fallback只负责业务异常
    //    @SentinelResource(value = "fallback",blockHandler = "blockHandler") // 配置了blockHandler,只负责sentinel控制台配置违规
        //@SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler",
             //   exceptionsToIgnore = {IllegalArgumentException.class}) // 配置了blockHandler和fallback
        public CommonResult<Payment> fallback(@PathVariable("id") Long id){
            CommonResult<Payment> commonResult = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class);
            if(id == 4){
                throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
            }else if(commonResult.getData() == null){
                throw new NullPointerException("NullPointerException,该ID没有记录,空指针异常");
            }
            return commonResult;
        }
        // 本例是fallback
        public CommonResult handlerFallback(Long id, Throwable e){
            Payment payment = new Payment(id, null);
            return new CommonResult(444, "兜底异常handler,exception内容"+e.getMessage(), payment);
        }
    
        public CommonResult blockHandler(Long id, BlockException exception){
            Payment payment = new Payment(id, null);
            return new CommonResult<>(445, "blockHandler-sentinel 限流,无此流水号:blockException" + exception.getMessage(), payment);
        }
    
        // --------------- open feign---------
    
        @Resource
        private PaymentService paymentService;
    
        @GetMapping("/consumer/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
            return paymentService.paymentSQL(id);
        }
    }
    

    3,启动nacos,sentinel,9003,9004,84
    测试http://localhost:84/consumer/fallback

    如果是4,报页面的非法参数异常。。。。
    在这里插入图片描述
    4以外的报空指针异常
    在这里插入图片描述

    第二种情况
    @SentinelResource(value = “fallback”,fallback = “handlerFallback”)

    加代码。方法

    // 本例是fallback
    public CommonResult handlerFallback(Long id, Throwable e){
        Payment payment = new Payment(id, null);
        return new CommonResult(444, "兜底异常handler,exception内容"+e.getMessage(), payment);
    }
    

    在这里插入图片描述

    在这里插入图片描述

    第三种情况

    @SentinelResource(value = "fallback",blockHandler = "blockHandler")
    

    加代码

    public CommonResult blockHandler(Long id, BlockException exception){
          Payment payment = new Payment(id, null);
          return new CommonResult<>(445, "blockHandler-sentinel 限流,无此流水号:blockException" + exception.getMessage(), payment);
      }
    

    设置sentinel
    在这里插入图片描述

    然后访问接口方法
    在这里插入图片描述

    多访问几次进入兜底
    在这里插入图片描述

    第四种情况

    @SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler")
    

    放开刚才两个方法
    sentinel设置流控规则
    qps:1
    访问接口。

    快速点击进入限流

    在这里插入图片描述

    普通点击走兜底

    在这里插入图片描述

    快速点击fallback4,是走兜底还是限流。是走限流的

    异常忽略属性

    @SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler",
           exceptionsToIgnore = {IllegalArgumentException.class})
    

    然后访问localhost:84/consumer/fallback/4

    走的是error page
    在这里插入图片描述

    localhost:84/consumer/fallback/5

    在这里插入图片描述

    走的兜底

                          sentinel服务熔断+openfeign
    

    修改84.
    1,pom
    新增

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    2,yml
    #激活sentinel对feign的支持

    feign:
      sentinel:
        enabled: true
    

    3,主启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    

    4,service

    package com.atguigu.springcloud.service;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    /**
     * @author wsk
     * @date 2020/3/25 9:02
     */
    @FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
    public interface PaymentService {
    
        @GetMapping("/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
    }
    
    package com.atguigu.springcloud.service;
    import com.atguigu.springcloud.entities.CommonResult;
    import com.atguigu.springcloud.entities.Payment;
    import org.springframework.stereotype.Component;
    
    /**
     * @author wsk
     * @date 2020/3/25 9:06
     */
    @Component
    public class PaymentFallbackService implements PaymentService{
        @Override
        public CommonResult<Payment> paymentSQL(Long id) {
            return new CommonResult<>(444,"服务降级返回,------------PaymentFallbackService",new Payment(id,"errorSerial"));
        }
    }
    

    5,controller

    // --------------- open feign---------
    
      @Resource
      private PaymentService paymentService;
    
      @GetMapping("/consumer/paymentSQL/{id}")
      public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
          return paymentService.paymentSQL(id);
      }
    

    在这里插入图片描述

    故意关闭9003

    触发降级
    在这里插入图片描述

                    sentinel持久化
    

    当我们配置规则以后,关闭服务。配置规则自动消失。
    将限流,熔断这些配置规则持久化进nacos。只要刷新8401某个rest地址。sentinel控制台的流控规则就可以看到。只要nacos里面配置不删除。针对8401上sentinel上的流控规则持续有效

    1,修改cloudalibaba-sentinel-service8401
    pom新增

    <!--springcloud alibaba sentinel-datasource-nacos 后续做持久化用到-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    

    2,yml

    server:
      port: 8401
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            # Nacos服务注册中心地址
            server-addr: localhost:8848
        sentinel:
          transport:
            # sentinel dashboard 地址
            dashboard: localhost:8080
            # 默认为8719,如果被占用会自动+1,直到找到为止
            port: 8719
          # 流控规则持久化到nacos
          datasource:
            dsl:
              nacos:
                server-addr: localhost:8848
                data-id: ${spring.application.name}
                group-id: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    feign:
      sentinel:
        enabled: true        
    

    3,添加nacos业务规则配置(必须是做了持久化的nacos)
    可以用本地的8848 nacos配置

    新建配置
    DataID:cloudalibaba-sentinel-service
    配置格式:json
    配置内容:

    [
        {
            "resource":"/rateLimit/byUrl",
            "limitApp":"default",
            "grade":1,
            "count":1,
            "strategy":0,
            "controllBehavior":0,
            "clusterMode":false
        }
    ]
    

    其中各项含义:
    resource:资源名称
    limitApp:来源应用
    grade:阈值类型 0,线程数 1,qps
    count:单机阈值
    strategy:流控模式,0直接 1关联 2链路
    controlBehavior:流程效果 0快速失败 1warm up 2排队等待
    clusterMode 是否集群

    4,启动8401,访问接口。刷新sentinel发现流控规则有了
    在这里插入图片描述
    停止8401发现
    没了
    在这里插入图片描述

    不怕,再重启8401

    快速访问刚才那个localhost:8401/rateLimit/byUrl
    在这里插入图片描述

    我并没有重新配置流控。他快速访问就已经生效。说明。sentinel持久化成功

    23,seata

    seata处理分布式事务

    以前的单体应用被拆分成多个应用,分别使用多个独立的数据源(数据库),每个服务内部数据的一致性由本地事务来保证,但全局无法保证,所以出现了分布式事务

    一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题

    seata是alibaba开源的分布式事务解决方案。致力于在微服务架构下提供高性能和简单易用的分布式事务服务

    官网http://seata.io/zh-cn/

    全局唯一事务id+三组件(TC,TM,RM)

    TC:事务协调器,维护全局事务运行状态,负责协调并驱动全局事务提交或回滚
    TM:控制全局事务的边界。负责开启一个全局事务,并最终发起全局提交式全局回滚的决议
    RM:控制分支事务,负责分支注册,状态汇报,并接受事务协调器指令,驱动本地事务提交和回滚

    seata分布式事务执行原理
    1,TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
    2,XID在微服务调用链路的上下文中传播
    3,RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
    4,TM向TC发起针对XID的全局提交或回滚决议
    5,TC调度XID下管辖的全部后支事务完成提交或回滚请求

                          seata安装配置
    

    1,地址:https://github.com/seata/seata/releases

    在这里插入图片描述
    2,解压到固定的路径
    3,修改:自定义事务组名称+事务日志存储模式db+数据库连接信息
    4,修改conf下的file.conf
    (1)修改service里的

     vgroup_mapping.my_test_tx_group = "fsp_tx_group"
    

    (2)修改store模块的

    mode="db"
    

    然后下面改db的配置

    url="jdbc:mysql://127.0.0.1:3306/seata"
    user="root"
    password="ljs"
    

    5,在数据库新建库seata
    6,在seata库里建表
    建表sql在\seata-server-1.0.0\seata\conf里
    db_store.sql

    drop table if exists `global_table`;
    create table `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`)
    );
    
    
    drop table if exists `branch_table`;
    create table `branch_table` (
      `branch_id` bigint not null,
      `xid` varchar(128) not null,
      `transaction_id` bigint ,
      `resource_group_id` varchar(32),
      `resource_id` varchar(256) ,
      `lock_key` varchar(128) ,
      `branch_type` varchar(8) ,
      `status` tinyint,
      `client_id` varchar(64),
      `application_data` varchar(2000),
      `gmt_create` datetime,
      `gmt_modified` datetime,
      primary key (`branch_id`),
      key `idx_xid` (`xid`)
    );
    
    
    drop table if exists `lock_table`;
    create table `lock_table` (
      `row_key` varchar(128) not null,
      `xid` varchar(96),
      `transaction_id` long ,
      `branch_id` long,
      `resource_id` varchar(256) ,
      `table_name` varchar(32) ,
      `pk` varchar(36) ,
      `gmt_create` datetime ,
      `gmt_modified` datetime,
      primary key(`row_key`)
    );
    

    分支,全局,锁表生成成功

    7,修改seata-server-1.0.0\seata\conf目录下的registry.conf配置文件
    第三行

    type="nacos"
    然后找到nacos{
    serverAddr="localhost:8848"
    

    8,启动nacos,再启动seata-server.bat。如果dos下出现
    在这里插入图片描述

    表示内存不足。要找到
    seata-server.bat里修改
    在这里插入图片描述

    改成这样,改小
    在这里插入图片描述

    -load Registry Provider表示执行成功

    在这里插入图片描述

                订单/库存/账户数据库准备
    

    都需要先启动nacos,再启动seata
    业务:当用户下单时,会在订单服务中创建一个订单。然后通过远程调用库存服务扣减下单商品的库存,再通过远程调用账户服务来扣减用户账户里面的余额。最后订单服务中修改订单状态为已完成

    创建业务数据库
    seata-order:存储订单的数据库
    seata-storage:存储库存的数据库
    seata-account:存储账户信息的数据库
    库对应表:
    order库对应t_order表
    storage库对应t_storage表
    account库对应t_account表
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    订单,库存,账户3个库下都需要建各自的回滚日志表
    在\seata-server-1.0.0\seata\conf目录下有
    db_undo_log.sql

    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,
      `ext` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    

    在三个库下分别粘贴执行

    最终的数据库准备结果
    在这里插入图片描述

    订单。库存。账户微服务编码
    下订单–减库存—减余额–改订单状态

    订单模块。创建seata-order-service2001
    1,pom

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>cloud2020</artifactId>
            <groupId>com.atguigu.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>seata-order-service2001</artifactId>
    
        <dependencies>
            <!--nacos-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--seata-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>io.seata</groupId>
                        <artifactId>seata-all</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-all</artifactId>
                <version>1.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!--hutool 测试雪花算法-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-captcha</artifactId>
                <version>5.2.0</version>
            </dependency>
        </dependencies>
    </project>
    

    2,yml

    server:
      port: 2001
    
    spring:
      application:
        name: seata-order-service
      cloud:
        alibaba:
          seata:
            # 自定义事务组名称需要与seata-server中的对应
            tx-service-group: fsp_tx_group
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
      datasource:
        # 当前数据源操作类型
        type: com.alibaba.druid.pool.DruidDataSource
        # mysql驱动类
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://47.115.93.213:3306/seata_order?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: ljs
    feign:
      hystrix:
        enabled: false
    logging:
      level:
        io:
          seata: info
    #ribbon的超时时间,这里测试用
    ribbon:
       ReadTimeout: 60000
       ConnectTimeout: 60000
    
    mybatis:
      mapper-locations: classpath*:mapper/*.xml
    

    3,file.conf

    transport {
      # tcp udt unix-domain-socket
      type = "TCP"
      #NIO NATIVE
      server = "NIO"
      #enable heartbeat
      heartbeat = true
      #thread factory for netty
      thread-factory {
        boss-thread-prefix = "NettyBoss"
        worker-thread-prefix = "NettyServerNIOWorker"
        server-executor-thread-prefix = "NettyServerBizHandler"
        share-boss-worker = false
        client-selector-thread-prefix = "NettyClientSelector"
        client-selector-thread-size = 1
        client-worker-thread-prefix = "NettyClientWorkerThread"
        # netty boss thread size,will not be used for UDT
        boss-thread-size = 1
        #auto default pin or 8
        worker-thread-size = 8
      }
      shutdown {
        # when destroy server, wait seconds
        wait = 3
      }
      serialization = "seata"
      compressor = "none"
    }
    service {
      #vgroup->rgroup
      # 事务组名称
      vgroup_mapping.fsp_tx_group = "default"
      #only support single node
      default.grouplist = "127.0.0.1:8091"
      #degrade current not support
      enableDegrade = false
      #disable
      disable = false
      #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
      max.commit.retry.timeout = "-1"
      max.rollback.retry.timeout = "-1"
    }
    
    client {
      async.commit.buffer.limit = 10000
      lock {
        retry.internal = 10
        retry.times = 30
      }
      report.retry.count = 5
      tm.commit.retry.count = 1
      tm.rollback.retry.count = 1
    }
    
    ## transaction log store
    store {
      ## store mode: file、db
      #mode = "file"
      mode = "db"
    
      ## file store
      file {
        dir = "sessionStore"
    
        # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
        max-branch-session-size = 16384
        # globe session size , if exceeded throws exceptions
        max-global-session-size = 512
        # file buffer size , if exceeded allocate new buffer
        file-write-buffer-cache-size = 16384
        # when recover batch read size
        session.reload.read_size = 100
        # async, sync
        flush-disk-mode = async
      }
    
      ## database store
      db {
        ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
        datasource = "dbcp"
        ## mysql/oracle/h2/oceanbase etc.
        db-type = "mysql"
        driver-class-name = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://47.115.93.213:3306/seata"
        user = "root"
        password = "ljs"
        min-conn = 1
        max-conn = 3
        global.table = "global_table"
        branch.table = "branch_table"
        lock-table = "lock_table"
        query-limit = 100
      }
    }
    lock {
      ## the lock store mode: local、remote
      mode = "remote"
    
      local {
        ## store locks in user's database
      }
    
      remote {
        ## store locks in the seata's server
      }
    }
    recovery {
      #schedule committing retry period in milliseconds
      committing-retry-period = 1000
      #schedule asyn committing retry period in milliseconds
      asyn-committing-retry-period = 1000
      #schedule rollbacking retry period in milliseconds
      rollbacking-retry-period = 1000
      #schedule timeout retry period in milliseconds
      timeout-retry-period = 1000
    }
    
    transaction {
      undo.data.validation = true
      undo.log.serialization = "jackson"
      undo.log.save.days = 7
      #schedule delete expired undo_log in milliseconds
      undo.log.delete.period = 86400000
      undo.log.table = "undo_log"
    }
    
    ## metrics settings
    metrics {
      enabled = false
      registry-type = "compact"
      # multi exporters use comma divided
      exporter-list = "prometheus"
      exporter-prometheus-port = 9898
    }
    
    support {
      ## spring
      spring {
        # auto proxy the DataSource bean
        datasource.autoproxy = false
      }
    }
    

    4,regustry.conf

    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "nacos"
    
      nacos {
        #serverAddr = "localhost"
        serverAddr = "localhost:8848"
        namespace = ""
        cluster = "default"
      }
      eureka {
        serviceUrl = "http://localhost:8761/eureka"
        application = "default"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = "0"
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      consul {
        cluster = "default"
        serverAddr = "127.0.0.1:8500"
      }
      etcd3 {
        cluster = "default"
        serverAddr = "http://localhost:2379"
      }
      sofa {
        serverAddr = "127.0.0.1:9603"
        application = "default"
        region = "DEFAULT_ZONE"
        datacenter = "DefaultDataCenter"
        cluster = "default"
        group = "SEATA_GROUP"
        addressWaitTime = "3000"
      }
      file {
        name = "file.conf"
      }
    }
    
    config {
      # file、nacos 、apollo、zk、consul、etcd3
      type = "file"
    
      nacos {
        serverAddr = "localhost"
        namespace = ""
      }
      consul {
        serverAddr = "127.0.0.1:8500"
      }
      apollo {
        app.id = "seata-server"
        apollo.meta = "http://192.168.1.204:8801"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    

    5,domain
    CommonResult

    package com.atguigu.springcloud.alibaba.domain;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    /**
     * @author wsk
     * @date 2020/3/25 20:37
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CommonResult<T> {
    
        private Integer code;
        private String message;
        private T       data;
    
        public CommonResult(Integer code, String message){
            this(code,message,null);
        }
    }
    

    Order

    package com.atguigu.springcloud.alibaba.domain;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import java.math.BigDecimal;
    /**
     * @author wsk
     * @date 2020/3/25 20:25
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Order {
        private Long id;
        private Long userId;
        private Long productId;
        private Integer count;
        private BigDecimal money;
        private Integer status;
    }
    

    6,dao

    package com.atguigu.springcloud.alibaba.dao;
    import com.atguigu.springcloud.alibaba.domain.Order;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    /**
     * @author wsk
     * @date 2020/3/25 20:41
     */
    @Mapper
    public interface OrderDao {
        //1 新建订单
        void createOrder(Order order);
    
        //2 修改订单状态 从0改为1
        void update(@Param("userId") Long userId,@Param("status") Integer status);
    }
    

    7,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.atguigu.springcloud.alibaba.dao.OrderDao">
    
        <resultMap id="BaseResultMap" type="com.atguigu.springcloud.alibaba.domain.Order">
            <id column="id" property="id" jdbcType="BIGINT"></id>
            <result column="user_id" property="userId" jdbcType="BIGINT"></result>
            <result column="product_id" property="productId" jdbcType="BIGINT"></result>
            <result column="count" property="count" jdbcType="INTEGER"></result>
            <result column="money" property="money" jdbcType="DECIMAL"></result>
            <result column="status" property="status" jdbcType="INTEGER"></result>
        </resultMap>
    
        <insert id="createOrder" parameterType="com.atguigu.springcloud.alibaba.domain.Order" useGeneratedKeys="true"
                keyProperty="id">
            insert into t_order(user_id,product_id,count,money,status) values (#{userId},#{productId},#{count},#{money},0);
        </insert>
    
        <update id="update">
            update t_order set status =1 where user_id =#{userId} and status=#{status};
        </update>
    </mapper>
    

    8,service
    orderService

    package com.atguigu.springcloud.alibaba.service;
    
    import com.atguigu.springcloud.alibaba.domain.Order;
    
    /**
     * @author wsk
     * @date 2020/3/25 20:58
     */
    public interface OrderService {
        void create(Order order);
    
    
    }
    

    StorageService

    package com.atguigu.springcloud.alibaba.service;
    
    import com.atguigu.springcloud.alibaba.domain.CommonResult;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    /**
     * @author wsk
     * @date 2020/3/25 21:00
     */
    @FeignClient(value = "seata-storage-service")
    public interface StorageService {
    
        @PostMapping(value = "/storage/decrease")
        CommonResult decrease(@RequestParam("productId") Long productId,@RequestParam("count") Integer count);
    }
    

    AccountService

    package com.atguigu.springcloud.alibaba.service;
    import com.atguigu.springcloud.alibaba.domain.CommonResult;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import java.math.BigDecimal;
    
    /**
     * @author wsk
     * @date 2020/3/25 21:00
     */
    @FeignClient(value = "seata-account-service")
    public interface AccountService {
    
        @PostMapping(value = "/account/decrease")
        CommonResult decrease(@RequestParam("userId") Long userId,@RequestParam("money") BigDecimal money);
    }
    

    9,serviceImpl

    package com.atguigu.springcloud.alibaba.service.impl;
    import com.atguigu.springcloud.alibaba.dao.OrderDao;
    import com.atguigu.springcloud.alibaba.domain.Order;
    import com.atguigu.springcloud.alibaba.service.AccountService;
    import com.atguigu.springcloud.alibaba.service.OrderService;
    import com.atguigu.springcloud.alibaba.service.StorageService;
    import io.seata.spring.annotation.GlobalTransactional;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
    
    /**
     * @author wsk
     * @date 2020/3/25 20:59
     */
    @Service
    @Slf4j
    public class OrderServiceImpl implements OrderService {
    
        @Resource
        private OrderDao orderDao;
        @Resource
        private AccountService accountService;
        @Resource
        private StorageService storageService;
    
        /**
         * 创建订单->调用库存服务扣减库存->调用账户服务扣减账户余额->修改订单状态
         * 简单说:
         * 下订单->减库存->减余额->改状态
         * GlobalTransactional seata开启分布式事务,异常时回滚,name保证唯一即可
         */
        @Override
        @GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
        public void create(Order order) {
            log.info("----->开始创建新订单");
            //1 新建订单
            orderDao.createOrder(order);
    
            log.info("----->订单微服务开始调用库存,做扣减Count");
            //2 扣减库存
            storageService.decrease(order.getProductId(),order.getCount());
            log.info("----->订单微服务开始调用库存,做扣减end");
    
            log.info("----->订单微服务开始调用账户,做扣减Money");
            //3 扣减账户
            accountService.decrease(order.getUserId(),order.getMoney());
            log.info("----->订单微服务开始调用库存,做扣减end");
    
            //修改订单状态,从0到1,1代表以及完成
            log.info("----->修改订单状态开始");
            orderDao.update(order.getUserId(),0);
            log.info("----->修改订单状态结束");
    
            log.info("----->下订单结束了,O(∩_∩)O哈哈~");
        }
    }
    

    10.OrderController

    package com.atguigu.springcloud.alibaba.controller;
    
    import com.atguigu.springcloud.alibaba.domain.CommonResult;
    import com.atguigu.springcloud.alibaba.domain.Order;
    import com.atguigu.springcloud.alibaba.service.OrderService;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * @author wsk
     * @date 2020/3/25 21:24
     */
    @RestController
    public class OrderController {
    
        @Resource
        private OrderService orderService;
        @GetMapping("/order/create")
        public CommonResult create(Order order){
            orderService.create(order);
            return new CommonResult(200,"订单创建成功");
        }
    }
    

    11,config

    package com.atguigu.springcloud.alibaba.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import io.seata.rm.datasource.DataSourceProxy;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    
    import javax.sql.DataSource;
    
    /**
     * @author wsk
     * @date 2020/3/25 21:26
     */
    @Configuration
    @MapperScan({"com.atguigu.springcloud.alibaba.dao"})
    public class MyBatisConfig {
        @Value("${mybatis.mapper-locations}")
        private String mapperLocations;
    
        /**
         * @param sqlSessionFactory SqlSessionFactory
         * @return SqlSessionTemplate
         */
        @Bean
        public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
        /**
         * 从配置文件获取属性构造datasource,注意前缀,这里用的是druid,根据自己情况配置,
         * 原生datasource前缀取"spring.datasource"
         *
         * @return
         */
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource druidDataSource() {
            return new DruidDataSource();
        }
    
        /**
         * 构造datasource代理对象,替换原来的datasource
         *
         * @param druidDataSource
         * @return
         */
        @Primary
        @Bean("dataSource")
        public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
            return new DataSourceProxy(druidDataSource);
        }
    
        @Bean(name = "sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSourceProxy);
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            bean.setMapperLocations(resolver.getResources(mapperLocations));
    
            SqlSessionFactory factory;
            try {
                factory = bean.getObject();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return factory;
        }
    }
    

    12.主启动类

    package com.atguigu.springcloud.alibaba;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    /**
     * @author wsk
     * @date 2020/3/25 20:40
     */
    @EnableFeignClients
    @EnableDiscoveryClient
    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源的自带创建
    public class SeataOrderMainApp2001 {
        public static void main(String[] args) {
            SpringApplication.run(SeataOrderMainApp2001.class,args);
        }
    }
    

    库存模块 seataStorageService2002
    1,pom跟之前一样
    2,xml

    server:
      port: 2002
    
    
    spring:
      application:
        name: seata-storage-service
      cloud:
        alibaba:
          seata:
            # 自定义事务组名称需要与seata-server中的对应
            tx-service-group: fsp_tx_group
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
      datasource:
        # 当前数据源操作类型
        type: com.alibaba.druid.pool.DruidDataSource
        # mysql驱动类
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://47.115.93.213:3306/seata_storage?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: ljs
    feign:
      hystrix:
        enabled: false
    logging:
      level:
        io:
          seata: info
    #ribbon的超时时间
    ribbon:
      ReadTimeout: 60000
      ConnectTimeout: 60000
    
    mybatis:
      mapper-locations: classpath*:mapper/*.xml
    

    3,file.conf
    跟上一个一样

    4,registry.conf
    跟上一个一样

    5,domain
    CommonResult跟之前一样
    storage

    package com.atguigu.springcloud.alibaba.domain;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    /**
     * @author wsk
     * @date 2020/3/25 21:45
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Storage {
        private Long id;
    
        /**
         * 产品id
         */
        private Long productId;
    
        /**
         * 总库存
         */
        private Integer total;
    
        /**
         * 已用库存
         */
        private Integer used;
    
        /**
         * 剩余库存
         */
        private Integer residue;
    }
    

    6,dao

    package com.atguigu.springcloud.alibaba.dao;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    /**
     * @author wsk
     * @date 2020/3/25 21:47
     */
    @Mapper
    public interface StorageDao {
        /**
         * 减库存
         * @param productId
         * @param count
         * @return
         */
        int decrease(@Param("productId") Long productId, @Param("count") Integer count);
    }
    

    7,dao.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.atguigu.springcloud.alibaba.dao.StorageDao">
    
        <resultMap id="BaseResultMap" type="com.atguigu.springcloud.alibaba.domain.Storage">
            <id column="id" property="id" jdbcType="BIGINT"></id>
            <result column="product_id" property="productId" jdbcType="BIGINT"></result>
            <result column="total" property="total" jdbcType="INTEGER"></result>
            <result column="used" property="used" jdbcType="INTEGER"></result>
            <result column="residue" property="residue" jdbcType="INTEGER"></result>
        </resultMap>
    
        <!--减库存-->
        <update id="decrease">
            update t_storage
            set used =used + #{count},residue= residue - #{count}
            where product_id=#{productId};
        </update>
    </mapper>
    

    8,service

    package com.atguigu.springcloud.alibaba.service;
    /**
     * @author wsk
     * @date 2020/3/25 21:51
     */
    public interface StorageService {
        /**
         * 扣减库存
         * @param productId
         * @param count
         */
        void decrease(Long productId,Integer count);
    }
    

    9,serviceImpl

    package com.atguigu.springcloud.alibaba.service;
    
    import com.atguigu.springcloud.alibaba.dao.StorageDao;
    import com.atguigu.springcloud.alibaba.service.StorageService;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class StorageServiceImpl implements StorageService {
    
        @Resource
        private StorageDao storageDao;
    
        /**
         * 减库存
         *
         * @param productId
         * @param count
         * @return
         */
        @Override
        public void decrease(Long productId, Integer count) {
            storageDao.decrease(productId, count);
        }
    }
    
    
    
    10,controller
    package com.atguigu.springcloud.alibaba.controller;
    import com.atguigu.springcloud.alibaba.domain.CommonResult;
    import com.atguigu.springcloud.alibaba.service.StorageService;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.annotation.Resource;
    /**
     * @author wsk
     * @date 2020/3/25 21:55
     */
    @RestController
    public class StorageController {
    
        @Resource
        private StorageService storageService;
    
        @RequestMapping("/storage/decrease")
        public CommonResult decrease(Long productId, Integer count){
            storageService.decrease(productId,count);
            return new CommonResult(200,"扣减库存成功");
        }
    }
    

    11,config
    和之前一样

    12,主启动类和之前一样

    seata-account-service2003
    1,pom一样
    2。xml

    server:
      port: 2003
    spring:
      application:
        name: seata-account-service
      cloud:
        alibaba:
          seata:
            # 自定义事务组名称需要与seata-server中的对应
            tx-service-group: fsp_tx_group
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
      datasource:
        # 当前数据源操作类型
        type: com.alibaba.druid.pool.DruidDataSource
        # mysql驱动类
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://47.115.93.213:3306/seata_account?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: ljs
    feign:
      hystrix:
        enabled: false
    logging:
      level:
        io:
          seata: info
    #ribbon的超时时间
    ribbon:
      ReadTimeout: 60000
      ConnectTimeout: 60000
    
    mybatis:
      mapper-locations: classpath*:mapper/*.xml
    

    3,file.conf
    一样
    4,registry.conf
    一样
    5,domain
    CommonResult一样
    Account

    package com.atguigu.springcloud.alibaba.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * 账户实体类
     *
     * @author zzyy
     * @date 2020/3/8 12:28
     **/
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Account {
        private Long id;
    
        /**
         * 用户id
         */
        private Long userId;
    
        /**
         * 总额度
         */
        private Integer total;
    
        /**
         * 已用额度
         */
        private Integer used;
    
        /**
         * 剩余额度
         */
        private Integer residue;
    }
    

    6,dao

    package com.atguigu.springcloud.alibaba.dao;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    import java.math.BigDecimal;
    /**
     * @author wsk
     * @date 2020/3/25 22:05
     */
    @Mapper
    public interface AccountDao {
    
        /**
         * 扣减账户余额
         * @param userId
         * @param money
         */
        void decrease(@Param("userId") Long userId, @Param("money")BigDecimal money);
    }
    

    7,dao.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.atguigu.springcloud.alibaba.dao.AccountDao">
    
        <update id="decrease">
            update t_account set residue = residue- #{money},used = used + #{money}
            where user_id =#{userId};
        </update>
    </mapper>
    

    8,service

    package com.atguigu.springcloud.alibaba.service;
    import org.springframework.web.bind.annotation.RequestParam;
    import java.math.BigDecimal;
    /**
     * @author wsk
     * @date 2020/3/25 22:09
     */
    public interface AccountService {
        /**
         * 扣减账户余额
         */
        void decrease(@RequestParam("userId") Long userId, @RequestParam("money")BigDecimal money);
    }
    

    9,serviceImpl

    package com.atguigu.springcloud.alibaba.service.impl;
    import com.atguigu.springcloud.alibaba.dao.AccountDao;
    import com.atguigu.springcloud.alibaba.service.AccountService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.math.BigDecimal;
    /**
     * @author wsk
     * @date 2020/3/25 22:10
     */
    @Service
    public class AccountServiceImpl implements AccountService {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);
    
        @Resource
        AccountDao accountDao;
    
        @Override
        public void decrease(Long userId, BigDecimal money) {
            LOGGER.info("------>account-service中扣减账户余额开始");
            //模拟异常,全局事务回滚
           // int age=10/0;
            accountDao.decrease(userId,money);
            LOGGER.info("------>account-service中扣减账户余额结束");
        }
    }
    

    10,controller

    package com.atguigu.springcloud.alibaba.controller;
    import com.atguigu.springcloud.alibaba.domain.CommonResult;
    import com.atguigu.springcloud.alibaba.service.AccountService;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import javax.annotation.Resource;
    import java.math.BigDecimal;
    /**
     * @author wsk
     * @date 2020/3/25 22:14
     */
    @RestController
    public class AccountController {
    
        @Resource
        AccountService accountService;
    
        @RequestMapping("/account/decrease")
        public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money")BigDecimal money){
            accountService.decrease(userId,money);
            return new CommonResult(200,"扣减账户余额成功");
        }
    }
    

    11,config
    一样

    12,主启动类
    一样

    然后访问localhost:2001/order/create?userId=1&productId=1&count=10&money=100

    将会完成数据库操作

    这时候在AccountServiceImpl里模拟异常
    int age=10/0;

    将会导致数据库。。。。。数据不一致的问题。。。

    如何让全局事务回滚?

    在事务发起者OrderServiceImpl方法前上写
    @GlobalTransactional(name = “fsp-create-order”,rollbackFor = Exception.class)

                                  seata原理
    

    尽量使用1.0版本,支持集群,1.0版本支持大规模商用
    TC:seata服务器
    TM:事务的发起方
    RM:数据库

    AT模式:两阶段提交
    一阶段:加载。seata拦截业务SQL在我们执行sql前seata保存到 before image
    执行业务sql后保存成 after image。再加一个行锁。保证了一个阶段的原子性

    二阶段:业务sql在一阶段已经提交至数据库。seata框架只需将一阶段保存的快照数据(after和before和行锁)删掉。完成数据的清除即可

    二阶段回滚:
    利用反向补偿机制。seata回滚。阶段已经执行的业务sql,还原业务数据。回滚则用before image还原业务数据。还原前校验脏写。对比数据库当前业务数据库和
    after image的数据完全一致,则没有脏写。出现脏写。则转人工处理

    展开全文
  • 1、spring5框架新功能 整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除 ...Step1 引入jar(交给Maven) Step2 根目录下创建log4j2.xml配置文件 <?xml version="1.0

    1、spring5框架新功能

    整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

    2、Spring 5.0框架自带了通用的日志封装

    (1)Spring5已经移除Log4jConfigListener,官方建议使用Log4j2

    (2)Spring5框架整合Log4j2

    演示:使用日志框架Log4j2

    Step1 引入jar包(交给Maven)

    Step2 根目录下创建log4j2.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?> 
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出--> 
    <configuration status="INFO"> 
      <!--先定义所有的appender--> 
      <appenders> 
        <!--输出日志信息到控制台--> 
        <console name="Console" target="SYSTEM_OUT"> 
          <!--控制日志输出的格式--> 
          <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> 
        </console> 
      </appenders> 
      <!--然后定义logger,只有定义logger并引入的appender,appender才会生效--> 
      <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出--> 
      <loggers> 
        <root level="info"> 
          <appender-ref ref="Console"/> 
        </root>
      </loggers> 
    </configuration>

    在com.atguigu.spring5测试文件夹test下新创建一个UserLog类(包com.atguigu.spring5)

    java开发过程中经常需要打印日志信息,往往会在每个类的第一行加上形如以下代码:

    protected static final Logger logger = LoggerFactory.getLogger(XXX.class);

    目的:使用指定的类XXX初始化日志对象,方便在日志输出的时候,可以打印出日志信息所属的类

    示例:protected static final Logger logger = LoggerFactory.getLogger(XYZ.class);

              logger.debug("hello world");

              输出:XYZ:hello world

    package com.atguigu.spring5.test;
    
    public class UserLog{
      public class UserLog{
        private static final Logger log = LoggerFactory.getLogger(UserLog.class);
      }
    
      public static void main(String[] args){
        log.info("hello log4j2");
        log.warn("hello log4j2");
      }
    }

    3、Spring5框架核心容器支持@Nullable注解

    (1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空

    (2)注解用在方法上面,方法返回值可以为空

    说明:可以为空,指不会报空指针异常

    Spring源码中随处可见

    (3)注解使用在方法参数里面,方法参数值可以为空

    (4)注解使用在属性上面,属性值可以为空

    4、Spring5核心容器支持函数式风格GenericApplicationContext

    简单地说:函数式风格创建对象,交给spring进行管理,通过GenericApplicationContext 类对象的registerBean方法注册对象,方法的形参支持Lambda表达式

    在com.atguigu.spring5测试文件夹test下新创建一个User类(包com.atguigu.spring5)

    此时,自己new的对象,spring5并不知道,需要将其注册进spring容器中,spring才会进行管理。现在就是不自己new对象,通过函数式风格GenericApplicationContext 将该User类的对象创建并注册进spring容器

    package com.atguigu.spring5.test;
    
    public class User{
      
    }

    在com.atguigu.spring5/test文件夹下的TestBook类中,写GenericApplicationContext()方法

    package com.atguigu.spring5.test
    
    public class TestBook{
      @Test
      public void testGennericApplicationContext(){
        //1 创建GenericApplicationContext对象 
        GenericApplicationContext context = new GenericApplicationContext(); 
        //2 调用context的方法对象注册 
        context.refresh(); 
        context.registerBean("user1",User.class,() -> new User()); 
        //3 获取在spring注册的对象 
        // User user = (User)context.getBean("com.atguigu.spring5.test.User"); 
        User user = (User)context.getBean("user1"); 
        System.out.println(user);
      }
    }
    

    5、Spring5支持整合JUnit5

    在test文件夹下创建JTest类 

    @ContextConfiguration("classpath:bean1.xml") 

    @ContextConfiguration这个注解通常与@RunWith(SpringJUnit4ClassRunner.class)联合使用用来测试

    当一个类添加了注解@Component,那么他就自动变成了一个bean,就不需要再Spring配置文件中显示的配置了。把这些bean收集起来通常有两种方式,Java的方式和XML的方式。当这些bean收集起来之后,当我们想要在某个测试类使用@Autowired注解来引入这些收集起来的bean时,只需要给这个测试类添加@ContextConfiguration注解来标注我们想要导入这个测试类的某些bean。

    @ExtendWith(SpringExtension.class) 

    该注解,说明使用junit5的单元测试框架。这两个注解可以合并成一个注解

    @SpringJUnitConfig(locations = "classpath:bean1.xml")

    合并前两个注解

    package com.atguigu.spring5.test
    
    //@ExtendWith(SpringExtension.class) 
    //@ContextConfiguration("classpath:bean1.xml") 
    @SpringJUnitConfig(locations = "classpath:bean1.xml")//合并上面两个注解
    public class JTest5 { 
      @Autowired 
      private UserService userService;  
      @Test 
      public void test1() { 
      userService.accountMoney(); 
      } 
    }

     

     

     

     

     

    展开全文
  • 因项目需要第一次是用Maven搭建项目,在网上找了许久pom配置总是会出现一些兼容等小问题,经过多次改动版本测试,以下pom勉强能使用,但是hibernate配置实体类仍有问题。但因项目进度问题所以没有再进行测试修改...

    前言

    因项目需要第一次是用Maven搭建项目,在网上找了许久pom配置总是会出现一些包不兼容等小问题,经过多次改动版本测试,以下pom勉强能使用,但是hibernate配置实体类仍有问题。但因项目进度问题所以没有再进行测试修改了

    参考资料

    MyEclipse10.7使用Maven搭建Struts2+Spring3+Hibernate4的整合开发环境

    maven in action(十)maven项目建立和运行过程中可能的错误

    http://www.mvnrepository.com/

    Maven配置文件pom.xml详解-Chil1ax

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.donghaiair.AMS_V1</groupId>
      <artifactId>AMS_V1</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>war</packaging>
      <name>AMS_V1</name>
      <description/>
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    
      <dependencies>
            <!-- junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
    
            <!-- spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-expression</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>3.1.2.RELEASE</version>
            </dependency>
    
            <!-- hibernate -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>4.1.7.Final</version>
            </dependency>
    
            <!-- struts2 -->
            <dependency>
                <groupId>org.apache.struts</groupId>
                  <artifactId>struts2-core</artifactId>
                  <version>2.3.16</version>
                  <!-- 这里的 exclusions 是排除包,因为 Struts2中有javassist,Hibernate中也有javassist,
                    所以如果要整合Hibernate,一定要排除掉Struts2中的javassist,否则就冲突了。-->
                  <exclusions>
                    <exclusion>
                        <groupId>javassist</groupId>
                        <artifactId>javassist</artifactId>
                    </exclusion>
                  </exclusions> 
            </dependency>
    
            <!-- 使用了这个插件之后,就可以采用注解的方式配置Struts的Action,免去了在struts.xml中的繁琐配置项 -->
            <dependency>
                 <groupId>org.apache.struts</groupId>
                 <artifactId>struts2-convention-plugin</artifactId>
                 <version>2.3.20</version>
             </dependency>
             <!--config-browser-plugin插件,使用了这个插件之后,就可以很方便的浏览项目中的所有action及其与 jsp view的映射 -->
             <dependency>
                 <groupId>org.apache.struts</groupId>
                 <artifactId>struts2-config-browser-plugin</artifactId>
                 <version>2.3.20</version>
             </dependency>
    
             <!-- Struts2和Spring整合插件 -->
             <dependency>
                 <groupId>org.apache.struts</groupId>
                 <artifactId>struts2-spring-plugin</artifactId>
                 <version>2.3.4.1</version>
             </dependency>
    
             <!-- struts2-json-plugin -->
            <!-- <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-json-plugin</artifactId>
                <version>2.5</version>
            </dependency> -->
             <!-- http://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin -->
            <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-json-plugin</artifactId>
                <version>2.3.8</version>
            </dependency>
    
             <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc14</artifactId>
                <version>10.2.0.3.0</version>
            </dependency>
            <!--Druid连接池包 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.12</version>
            </dependency>
            <!--aspectjweaver包 -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.5</version>
            </dependency>
            <!-- <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-core</artifactId>
                <version>2.3.20</version>
                <exclusions>
                    <exclusion>
                        Hibernate已经还有该包的依赖
                        <artifactId>javassist</artifactId>
                        <groupId>javassist</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-spring-plugin</artifactId>
                <version>2.3.20</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.struts</groupId>
                <artifactId>struts2-convention-plugin</artifactId>
                <version>2.3.20</version>
            </dependency> -->
    
            <!-- log4j -->
            <!-- <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency> -->
            <!-- ojdbc -->
            <!-- <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc14</artifactId>
                <version>10.2.0.3.0</version>
            </dependency> -->
            <!-- mysql -->
            <!-- <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.37</version>
            </dependency> -->
    
            <!-- druid数据源 -->
            <!-- <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.16</version>
            </dependency> -->
    
            <!-- json工具 -->
            <!-- <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.7</version>
            </dependency> -->
    
            <!-- jackson也是json工具 -->
            <!-- <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>2.6.0</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>2.6.0</version>
            </dependency> -->
    
            <!-- <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.6.0</version>
            </dependency> -->
    
            <!-- aop -->
            <!-- <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.9</version>
            </dependency> -->
    
            <!-- servlet -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.0.1</version>
                <!-- 只在编译时和测试时运行 -->
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency> 
    
            <!-- http://mvnrepository.com/artifact/com.google.code.gson/gson -->
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.6.2</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.14</version>
            </dependency>
    
        </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
          </plugin>
          <!-- <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.2</version>
            <configuration>
              <version>3.1</version>
              <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
          </plugin> -->
          <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
              <executions>
                <execution>
                    <!-- 在打包成功后使用tomcat:run来运行服务 -->
                    <phase>package</phase>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
              </executions>
          </plugin>
          <plugin>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-surefire-plugin</artifactId>  
            <version>2.4.2</version>  
            <configuration>  
              <skipTests>true</skipTests>  
            </configuration>  
          </plugin> 
        </plugins>
      </build>
    </project>
    展开全文
  • 以前一直用的spring+mybatis(基于配置文件),想研究研究Hibernate了,好久没用了,都忘的差不多了,肯定有不好的地方,而且jar基本都是最新的,兼容不知道有木有问题,还请大家指点!    
  • 基于SpringMVC4+EasyUI开发的后台管理系统,已投入生产线上使用 体验系统地址:http://182.92.82.188:8280/manage/login.jsp 体验账号/密码,test1001/a12345678 后台系统源码:...
  • 通过慕课网2小时学习spring boot视频教程来看的,讲的通俗易懂,里面遇到一些问题记录下 1 @RestController = @Controller + ResponseBody ...否则会导致maven依赖中的一个兼容。应该是和hibernate相关的。 4
  • 1、微内核2、配置简单3、模块化4、开箱即用5、完全兼容Spring6、设计理念极其先进,很多思想来自OSGi,但是在现有技术的实现  缺点:  二次改造定制难缺少成熟的SOA或者RPC框架Dubbox:  1、完全兼容...
  • 整体思路:搭建springboot一定要注意版本问题,...1、添加maven依赖//创建maven工程 //修改pom.xml文件,注意的版本 2、c3p0属性文件和spring-jpa的配置 3、创建启动类Application.java 4、创建表对应的实体类User....
  • 烦透了log4j,最新版的结构变动也不做下兼容,在spring项目中用会爆找不到class,maven仓中的老版又依赖了一大堆Java1.4的东西,实在是不爽,于是果断抛弃,改用commons-logging的simplelog来输出日志。要在spring...
  • 烦透了log4j,最新版的结构变动也不做下兼容,在spring项目中用会爆找不到class,maven仓中的老版又依赖了一大堆Java1.4的东西,实在是不爽,于是果断抛弃,改用commons-logging的simplelog来输出日志。...
  • 上一遍已经讲到dubbo项目划分,现在基于项目划分实现服务提供者1.dubbo的导入(maven)(首先把问题提...原因是dubbo的com.alibaba里面spring版本是2.0的4.x以上才能兼容jdk1.8所以可以吧jdk换成1.7在运行)2.pro...
  • 前言 1.SpringBoot是对Spring框架的再封装,提供基于注解的开发,不再需要写大量的XML...4.maven一定要配置好,便于下载jar。 搭建环境 1.搭建有两种方式 (1)手动创建Maven工程 (2)pom文件依赖 <parent&g...
  • 整体思路:搭建springboot一定要注意版本问题,...1、添加maven依赖//创建maven工程//修改pom.xml文件,注意的版本2、c3p0属性文件和spring-jpa的配置3、创建启动类Application.java4、创建表对应的实体类User.java...
  • springboot参考指南

    2016-07-21 12:00:22
    使用Spring Boot Maven插件 ii. 13.2. Gradle iii. 13.3. Ant iv. 13.4. Starter POMs ii. 14. 组织你的代码 i. 14.1. 使用"default" ii. 14.2. 定位main应用类 iii. 15. 配置类 目錄 Spring Boot参考指南 2 i. ...
  • 什么是框架? 框架是是一个半成品,它对基础代码进行了封装并提供了相应的api(应用程序编程接口)。 优点:简化了代码,使用更方便,提高了代码开发效率与...4.web.xml文件引入spring的上下文监听器,用于加载spr...
  • Spring兼容性好,无缝结合 约定优于配置 功能强大:RESTful、数据验证、格式化、本地化、主题等 简洁灵活 2、SpringMVC和Struts2 跳转到目录 SpringMVC和Struts2对比 Spring MVC的前端控制器是Servlet, 而...
  • 开源中国源码

    2019-04-22 16:23:38
    4. 项目用到了阿里大于jarMaven时无法使用,可以下载doc/dysmsapi.zip,然后放本地的Maven的.m2\repository\com\alibaba\aliyun\目录下 5. 搜索和首页列表后期大部分前台列表准备都使用solr,所以要先下载目录下...
  • 直接代码静态设置pdfbox兼容低版本jdk,在IDEA中运行也不会有警告提示 移除guava、hutool等非必须的工具,减少代码体积 Office组件加载异步化,提速应用启动速度最快到5秒内 合理设置预览消费队列的线程数 修复...
  • 4.项目Maven打包问题。 打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码(群里同学提供的)。 <directory>src/main/java **/*.properties **/*.xml ...
  • 7.2 默认方法允许我们在接口里添加新的方法,而不会破坏实现这个接口的已有类的兼容性,也就是说不会强迫实现接口的类实现默认方法。接口可以提供一个默认的方法实现,所有这个接口的实现类都会通过继承得倒这个方法...
  • 目前最新版jar已提交到maven仓库,因此想直接引入的小伙伴,不需要再采用下面的两种方案了(请注意jitpack的通常来讲更新会更频繁些,而中央仓库的会更稳定些;相同的版本号对应的代码保持一致) 中央仓库引入...
  • 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle、Sqlserver、MariaDB、达梦等主流数据库。 20.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计...
  • SpringServer1.2-APIJSON 智慧党建服务器端,提供 上传 和 下载 文件的接口 apijson-builder 一个方便为 APIJSON 构建 RESTful 请求的 JavaScript 库 AbsGrade 列表级联算法,支持微信朋友圈单层评论、QQ空间双层...
  • 16.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。 17.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个...
  • 框架:Spring + Spring MVC + MyBatis 服务器:Tomcat 前端解析框架:Thymeleaf 开发工具:Idea 2017 版本管理工具:Maven 版本控制工具:GitHub 3.2 实现过程 3.2.1 商品首页实现 其他部分实现效果 3.2.2 ...

空空如也

空空如也

1 2
收藏数 29
精华内容 11
关键字:

maven包兼容spring4

spring 订阅