Spring Cloud Gateway整合nacos实战(三)_spring-cloud-starter-gateway-程序员宅基地

技术标签: Java  Nginx  spring cloud  注册中心  gateway  Spring Cloud  

网关简介

Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,⽬标是取代Netflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性能⾼于Zuul,官⽅测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的API路由管理⽅式。

Spring Cloud GateWay不仅提供统⼀的路由⽅式(反向代理)并且基于 Filter(定义过滤器对请求过滤,完成⼀些功能) 链的⽅式提供了⽹关基本的功能,例如:鉴权、流量控制、熔断、路径重写、⽇志监控等。

网关在架构中的位置,可以看到是请求进来由网关路由分配找到需要请求的服务,其中Nginx是用来做网关高可用的。
在这里插入图片描述
Spring Cloud GateWay天⽣就是异步⾮阻塞的,基于Reactor模型;

⼀个请求—>⽹关根据⼀定的条件匹配—匹配成功之后可以将请求转发到指定的服务地址;⽽在这个过程中,我们可以进⾏⼀些⽐较具体的控制(限流、⽇志、⿊⽩名单)

  • 路由(route): ⽹关最基础的部分,也是⽹关⽐较基础的⼯作单元。路由由⼀个ID、⼀个⽬标URL(最终路由到的地址)、⼀系列的断⾔(匹配条件判断)和Filter过滤器(精细化控制)组成。如果断⾔为true,则匹配该路由。

  • 断⾔(predicates):参考了Java8中的断⾔java.util.function.Predicate,开发⼈员可以匹配Http请求中的所有内容(包括请求头、请求参数等)(类似于nginx中的location匹配⼀样),如果断⾔与请求相匹配则路由。

  • 过滤器(filter):⼀个标准的Spring webFilter,使⽤过滤器,可以在请求之前
    或者之后执⾏业务逻辑。

Predicates断⾔就是我们的匹配条件,⽽Filter就可以理解为⼀个⽆所不能的拦截器,有了这两个元素,结合⽬标URL,就可以实现⼀个具体的路由转发。

Spring Cloud GateWay 帮我们内置了很多 Predicates功能,实现了各种路由匹配规则(通过 Header、请求参数等作为条件)匹配到对应的路由。
在这里插入图片描述
一般都会使用请求路径正则匹配

spring:
  cloud:
    gateway:
      routes: # 路由可以有多个
        - id: service-xxx-router # 我们⾃定义的路由 ID,保持唯⼀
          uri: lb://server-name
          predicates: #路由条件
            - Path=/xx/xxxx/** 

网关⼯作过程

在这里插入图片描述
客户端向Spring Cloud GateWay发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到GateWay Web Handler;Handler再通过指定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之间⽤虚线分开是因为过滤器可能会在发送代理请求之前(pre)或者之后(post)执⾏业务逻辑。

Filter在“pre”类型过滤器中可以做参数校验、权限校验、流量监控、⽇志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改、⽇志的输出、流量监控等。

从过滤器⽣命周期(影响时机点)的⻆度来说,主要有两个pre和post:
在这里插入图片描述

从过滤器类型的⻆度 ,Spring Cloud GateWay的过滤器分为GateWayFilter和GlobalFilter两种。
在这里插入图片描述
一般情况下GlobalFilter全局过滤器是程序员使⽤⽐较多的过滤器;

可以用来自定义一些黑名单校验等

⾃定义GateWay全局过滤器时,我们实现Global Filter接⼝即可,通过全局过滤器可以实现⿊⽩名单、限流等功能。

@Slf4j
@Component
public class BlackListFilter implements GlobalFilter, Ordered {
    


    private static List<String> blackList = new ArrayList<>();

    static {
    
        blackList.add("0:0:0:0:0:0:0:1"); // 模拟本机地址
    }


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
        // 思路:获取客户端ip,判断是否在⿊名单中,在的话就拒绝访问,不在的话就放⾏
        // 从上下⽂中取出request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 从request对象中获取客户端ip
        String clientIp = request.getRemoteAddress().getHostString();
        // 拿着clientIp去⿊名单中查询,存在的话就决绝访问
        if (blackList.contains(clientIp)) {
    
            // 决绝访问,返回
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
            log.debug("=====>IP:" + clientIp + " 在⿊名单中,将被拒绝访 问!");
            String data = "请求被禁止!";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));

        }

        // 合法请求,放⾏,执⾏后续的过滤器
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
    
        return 0; //越小优先级越高
    }
}

官方全局过滤器使用规范例子

@RestController
@SpringBootApplication
public class DemogatewayApplication {
    

	@RequestMapping("/hystrixfallback")
	public String hystrixfallback() {
    
		return "This is a fallback";
	}

	@Bean
	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    
		//@formatter:off
		return builder.routes()
				.route("path_route", r -> r.path("/get")
						.uri("http://httpbin.org"))
				.route("host_route", r -> r.host("*.myhost.org")
						.uri("http://httpbin.org"))
				.route("rewrite_route", r -> r.host("*.rewrite.org")
						.filters(f -> f.rewritePath("/foo/(?<segment>.*)",
								"/${segment}"))
						.uri("http://httpbin.org"))
				.route("hystrix_route", r -> r.host("*.hystrix.org")
						.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
								.uri("http://httpbin.org"))
				.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
						.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
								.uri("http://httpbin.org"))
				.route("limit_route", r -> r
					.host("*.limited.org").and().path("/anything/**")
						.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
					.uri("http://httpbin.org"))
				.route("websocket_route", r -> r.path("/echo")
					.uri("ws://localhost:9000"))
				.build();
		//@formatter:on
	}

	@Bean
	RedisRateLimiter redisRateLimiter() {
    
		return new RedisRateLimiter(1, 2);
	}

	@Bean
	SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    
		return http.httpBasic().and()
				.csrf().disable()
				.authorizeExchange()
				.pathMatchers("/anything/**").authenticated()
				.anyExchange().permitAll()
				.and()
				.build();
	}

	@Bean
	public MapReactiveUserDetailsService reactiveUserDetailsService() {
    
		UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
		return new MapReactiveUserDetailsService(user);
	}

	public static void main(String[] args) {
    
		SpringApplication.run(DemogatewayApplication.class, args);
	}
}

当然也可以单独做过滤器,比如,黑白名单过滤器,限流,认证,以及token校验等过滤器

import org.apache.commons.chain.Command;
import org.apache.commons.chain.impl.ChainBase;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 责任链模式
 * 接口限流->黑名单->白名单->数字签名验证,解码body数据->检查api信息及api参数->远程调用对应的接口->调用结果加密->返回
 */
@Configuration
public class ChainConfig {
    
	
	@Bean
	Command interfaceFlowLimitHandler() {
    
		return new InterfaceFlowLimitHandler();
	}
	
//	@Bean
//	Command blackIpListCheckHandler() {
    
//		return new BlackIpListCheckHandler();
//	}
	
	@Bean
	Command whiteIpListCheckHandler() {
    
		return new WhiteIpListCheckHandler();
	}
	
	@Bean
	Command signatureCheckHandler() {
    
		return new SignatureCheckHandler();
	}
	
	@Bean
	Command apiInfoCheckHandler() {
    
		return new ApiInfoCheckHandler();
	}
	
	@Bean
	Command invokeInterfaceHandler() {
    
		return new InvokeInterfaceHandler();
	}
	
	@Bean
	Command encodeResponseHandler() {
    
		return new EncodeResponseHandler();
	}
	
	@Bean
	ChainBase chains() {
    
		ChainBase chainBase = new ChainBase();
		chainBase.addCommand(interfaceFlowLimitHandler());
		chainBase.addCommand(blackIpListCheckHandler());
		chainBase.addCommand(whiteIpListCheckHandler());
		chainBase.addCommand(signatureCheckHandler());
		chainBase.addCommand(apiInfoCheckHandler());
		chainBase.addCommand(invokeInterfaceHandler());
		chainBase.addCommand(encodeResponseHandler());
		return chainBase;
	}	
}

每个bean类实现Command接口。命令封装要执行的处理工作单元,其目的是检查或修改由上下文表示的事务的状态。单个命令可以被组装成一个链,这允许它们完成所需的处理,或者将进一步的处理委托给链中的下一个命令。命令实现应该以线程安全的方式设计,适合包含在可能由不同线程同时处理的多个链中。
一般来说,这意味着命令类不应该维护实例变量中的状态信息。相反,应该通过对传递给execute()命令的上下文属性的适当修改来维护状态信息。
命令实现通常在上下文实例中检索和存储状态信息,这些信息作为参数传递给execute()方法.

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.commons.chain;
public interface Command {
    
    boolean CONTINUE_PROCESSING = false;
    boolean PROCESSING_COMPLETE = true;

    boolean execute(Context var1) throws Exception;
}

网关基本概念

  1. 路由
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: demo
        uri: lb://demo
        predicates:
          - Path=/rest-web/**
        filters:
            - StripPrefix=1

在这里插入图片描述
Java配置:
在这里插入图片描述
代表将 ip地址为10.1.1.1的访问转发到 down。。。。

  1. 断言
    predicates:
    下面加个 -可以添加多种断言

在这里插入图片描述

  1. 过滤器

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的xGatewayFilter工厂。

配置:

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: demo
        uri: lb://demo
        predicates:
          - Path=/rest-web/**
        filters:
            - StripPrefix=1 # 将url前缀去掉比如ip,port,http等
            - AddRequestHeader=X-Request-red, blue

此清单将X-Request-red:blue标头添加到所有匹配请求的下游请求的标头中。

AddRequestHeader了解用于匹配路径或主机的URI变量。URI变量可以在值中使用,并在运行时扩展。

java config形式使用ModifyRequestBody过滤器过滤器在网关向下游发送请求主体之前对其进行修改。

尝试通过代码的形式将转发的请求添加头信息:

@Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
    
        return builder.routes()
                .route("route1", r -> r.path("/payment/nacos/header/**")
                        .filters(f->f.addRequestHeader("json", "123"))
                        .uri("lb://nacos-payment-provider")).build();
    }

常见网关的区别

常见的有Zuul、Gateway、Nginx

  • zuul
    是Netflix的,早期在微服务中使用较广泛,是基于servlet实现的,阻塞式的api,不支持长连接。 只能同步,不支持异步。
    不依赖spring-webflux,可以扩展至其他微服务框架。 内部没有实现限流、负载均衡,其负载均衡的实现是采用 Ribbon +
    Eureka 来实现本地负载均衡。 代码简单,注释多,易理解。
  • Gateway
    是springcloud自己研制的微服务网关,是基于Spring5构建,,能够实现响应式非阻塞式的Api,支持长连接。 支持异步。功能更强大,内部实现了限流、负载均衡等,扩展性也更强。Spring Cloud Gateway明确的区分了Router 和Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。依赖于spring-webflux,仅适合于Spring Cloud套件。代码复杂,注释少。
  • nginx
    C语言编写,采用服务器实现负载均衡,高性能的HTTP和反向代理web服务器。 Nginx适合于服务器端负载均衡,Zuul和gateway
    是本地负载均衡,适合微服务中实现网关。Spring Cloud Gateway 天然适合Spring Cloud 生态。

Gateway网关实战

首先创建父类工程和两个子工程:demo和gateway

在这里插入图片描述

父工程

父类pom文件定义版本

 <modules>
        <module>gateway</module>
        <module>dubbo-api</module>
        <module>rest-web</module>
    </modules>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

子工程demo

pom.xml

<dependencies>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--nacos 配置中心-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
		</dependency>
		<!-- commons-lang3 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.9</version>
		</dependency>
	</dependencies>

配置文件application.yml


server:
  port: 8000

spring:
  application:
    name: demo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml

简单的controller路由

package com.demo.restweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class RestWebApplication {
    

	public static void main(String[] args) {
    
		SpringApplication.run(RestWebApplication.class, args);
	}
	@GetMapping("/demo")
	public String demo(String name) {
    
		System.out.println("ssss " + name);
		return "hello, " + name + "i am demo";
	}
}

子工程gateway

pom.xml

<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.csp</groupId>
			<artifactId>sentinel-datasource-nacos</artifactId>
		</dependency>
</dependencys>

配置文件application.yml

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: demo
        uri: lb://demo
        predicates:
          - Path=/rest-web/**
        filters:
            - StripPrefix=1
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        enabled: true

启动两个子工程

访问地址:http://127.0.0.1:8085/rest-web/demo?name=Java技术债务
在这里插入图片描述

本文作者:Java技术债务
原文链接:https://www.cuizb.top/myblog/article/1650294609
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。


在这里插入图片描述
JVM内存泄漏和内存溢出的原因
JVM常用监控工具解释以及使用
Redis 常见面试题(一)
ClickHouse之MaterializeMySQL引擎(十)
三种实现分布式锁的实现与区别
线程池的理解以及使用


咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳咳

最近面试BAT,整理一份面试资料,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。想获取吗?如果你想提升自己,并且想和优秀的人一起进步,感兴趣的朋友,可以在扫码关注下方公众号。资料在公众号里静静的躺着呢。。。

  • 喜欢就收藏
  • 认同就点赞
  • 支持就关注
  • 疑问就评论

一键四连,你的offer也四连

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40124555/article/details/124261040

智能推荐

新浪微博会员制-程序员宅基地

新浪微博,应该是08年那会推出的,此时国外的twiter正值热火朝天之际,反观国内,那时只有新浪一家在做微博,玩的人不多,蛮冷清的,那会上去玩也是听同学介绍的,不过那会心理面想想,国外twiter那么火,人家老外都在上面玩了,咱也不能落后是不,但twiter又被墙了,而且没中文版,只能是找一款同类型产品替代她,于是就去新浪微博了。咱也来装下逼,。。还有一种心理也在影响着我,“名人”,...

第一个JAVA实战项目!_java开始实战项目-程序员宅基地

只是一个新手入门级项目,希望新手同学能和我得到学习,大佬请手下留情桌球小游戏项目先放代码和效果图import java.awt.*;import javax.swing.*;public class Ballgame extends JFrame { Image ball=Toolkit.getDefaultToolkit().getImage("images/ball.png"); Image table=Toolkit.getDefaultToolkit().getImage_java开始实战项目

Problem F: Fibonacci Again_f - fibonacci again-程序员宅基地

Problem F: Fibonacci AgainTime Limit: 1 Sec Memory Limit: 128 MBSubmit: 64 Solved: 18[Submit][Status][Web Board]DescriptionThere are another kind of Fibonacci numbers: F(0) = 7, F(_f - fibonacci again

[Python]北京交通大学研究生教务系统爬虫_python北京交通大学选课爬虫-程序员宅基地

本来想尝试自己爬一下全部学生的成绩,结果发现实在是弄不到账号密码,就此作罢。万一有学弟学妹以后想尝试可以参考。import urllibimport urllib2import requestsimport restudent = 八位学号password = 密码postdata = urllib.urlencode({ 'u':student, 'p':password_python北京交通大学选课爬虫

信息系统项目管理师-计算题专题(四)运筹学计算_最小机会损失准则怎么算_霸道流氓气质的博客-程序员宅基地

运筹学注:博客:https://blog.csdn.net/badao_liumang_qizhi关注公众号霸道的程序猿获取编程相关电子书、教程推送与免费下载。涉及知识点可能涉及到如下知识点: 规划论:线性规划、非线性规划}、整数规划、目标规划、动态规划 图论与网络 存储论 排队论 决策论 对策论 计算机仿真运筹学中常考的有最短和最长路径问题、线性规划的问题、传输运输学解决资源分配、最小生成树、匈牙利法、最大流量、后悔值的问题求最短和最长..._最小机会损失准则怎么算

html案例:导航栏布局案例_html导航栏案例-程序员宅基地

要求实现一个简单的导航菜单,没有子菜单。代码如下:<!doctype html><html lang="zh-Han-cmn"><head> <meta charset="UTF-8"> <title>导航栏布局案例</title> <style type="text/css" rel="styleshe..._html导航栏案例

随便推点

基于 golang 的实现简单的发布订阅模型_go 实现 sub publish-程序员宅基地

本文主要参考《Go 语言高级编程》一书!发布订阅(publish-and-subscribe)模型通常被简写为 pub/sub 模型。在这个模型中,消息生产者成为发布者(publisher),而消息消费者则成为订阅者(subscriber),生产者和消费者是 M:N 的关系。在传统生产者和消费者模型中,是将消息发送到一个队列中,而发布订阅模型则是将消息发布给一个主题。// Package pu..._go 实现 sub publish

高效清理华为手机内存实用攻略_手机清理输入什么代码-程序员宅基地

今天,前台的小妹找我帮忙;原因是她的华为手机内存不够用了,请我帮她清理一下。其实,我的内心是抗拒的。虽然,我是做手机软件开发的;但是,我不是修手机的啊。可是,看到她哀求的眼神;我又不忍心拒绝。故,特意写此篇博客丢给她,日后备用。_手机清理输入什么代码

概率论札记 - 2 - 用贝叶斯定理来讨论“医疗诊断的可靠性到底有多少”-程序员宅基地

只有愚蠢的人才会相信眼睛看到的。 ——安·兰德故事要从一道贝叶斯定理的简单习题讲起。大意是艾滋病患病率为万分之一,误诊率为5%,患有艾滋病者被诊断出来的概率为99%,请问在这样的设定下如果你被诊断为艾滋病阳性,那么你患艾滋病的概率是多少,原题如下——Problem Denoted blood is screened for AIDS. Suppose the test has 99% acc

JAVA 夏令营_2019夏令营游记-程序员宅基地

第九天:早早的起床本来以为是美好的结束结果车开到一半大家的行李箱都飞出去辽然后教练们都集体下去捡箱子窝还看到mxl那个突出的小肚子上那块地方有泥还有个箱子滚到绿化带那个深沟沟里了qwqlkp的箱子好像还拿错了拿了一个磕的很烂了的打都打不开我发誓我没笑第八天:今天晚上提前去吃饭迎面撞上mxl气势不能输所以就那样走过去了然后前边的路上有泥巴lkx悄悄和我说:咱俩走小路 甩开mxl然后我们就走了小路然后...

JAVA版本8u171与8u172的区别-程序员宅基地

用了java 7好几年了,今天闲来无事,想升级到 java 8,到官网下载的时候发现JAVA放出了8u171与8u172两个版本。什么情况?百度一下找到答案:https://blog.csdn.net/u014653815/article/details/80435226这是官方对于奇数版本与偶数版本区别的解释:从JDK版本7u71以后,JAVA将会在同一时间发布两个版本的JDK,..._如何看java是8u多少

Sql中的数据类型及区别-程序员宅基地

1,char,nchar,nvarchar,varchar有什么区别? 2,text和ntext有什么区别以及和上面各种字符类有什么区别? 3,关于带big和带small的类型,比如:smallint,int和bigint;以及smalldatetime,datetime和bigdatetime有什么区别? ========================================...

推荐文章

热门文章

相关标签