前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《面试集:自用》《待完善...》

《面试集:自用》《待完善...》

作者头像
发布2020-11-12 10:35:45
4570
发布2020-11-12 10:35:45
举报
文章被收录于专栏:后端JavaEE后端JavaEE后端JavaEE

1. Java并发类:

1、ConcurrentHashMap

01、和HashMap功能基本一致,主要是为了解决HashMap线程不安全问题;

02、java7中的基本设计理念就是切分成多个Segment块,默认是16个,也就是说并发度是16,可以初始化时显式指定,后期不能修改,每个Segment里面可以近似看成一个HashMap,每个Segment块都有自己独立的ReentrantLock锁,所以并发操作时每个Segment互不影响;

03、java8中将Segment块换成了Node,每个Node有自己的锁,即每个Node都有自己的并发度;

04、不允许空值和空键,否则会抛出异常;

那ConcurrentHashMap是如何保证数据操作的一致性呢? 对于数据元素的大小,ConcurrentHashMap将对应数组(HashEntry的长度)的变量为voliate类型的,也就是任何HashEntry发生变更,所有的地方都会知道数据的大小。对于元素,如何保证我取出的元素的next不发生变更呢?(HashEntry中的数据采用链表存储,当读取数据的时候可能又发生了变更),这一点,ConcurrentHashMap采取了最简单的做法,hash值、key和next取出后都为final类型的,其next等数据永远不会发生变更。

另外ConcurrentHashMap采用的锁结构是将读和写分开的,大大的提升了性能。

2.CopyOnWriteArrayList CopyOnWriteArrayList这是一个ArrayList的线程安全的变体,其原理大概可以通俗的理解为:初始化的时候只有一个容器,很常一段时间,这个容器数据、数量等没有发生变化的时候,大家(多个线程),都是读取(假设这段时间里只发生读取的操作)同一个容器中的数据,所以这样大家读到的数据都是唯一、一致、安全的,但是后来有人往里面增加了一个数据,这个时候CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。

优点:

1.解决的开发工作中的多线程的并发问题。

缺点:

1.内存占有问题:很明显,两个数组同时驻扎在内存中,如果实际应用中,数据比较多,而且比较大的情况下,占用内存会比较大,针对这个其实可以用ConcurrentHashMap来代替。

2.数据一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器

2.Spring的IOC以及AOP.

IOC(DI):把对象的创建权限交给Spring容器,让spring帮我们实例化对象,我们只是从spring容器中取得实例。

AOP:把一些非核心业务的代码抽取到一个通知类(增强),再创建需要被增强的类的代理对象,在调用代理对象的方法时,织入增强代码,并调用目标方法的一种面向切面技术,一种对OOP进行补充的编程方式。

3.Spring的Bean的加载过程.

Spring通过资源加载器加载相应的XML文件,使用读取器读取资源加载器中的文件到读取器中,在读取过程中,解析相应的xml文件元素,转化为spring定义的数据结BeanDefinition,把相应的BeanDefinition注册到注册表中。注册表中包含的BeanDefinition的数据结构,没有经过加工处理过,无法得到我们想要的bean对象。 我们如何得到Bean对象,spring都做了那些工作?BeanFactory提供了多种方式得到bean对象,getBean()方法是最核心得到bean对象 getBean主要由AbstractBeanFactory、AbstractAutowireCapableBeanFactory、以及DefaultListableBeanFactory实现 AbstractBeanFactory 实现了依赖关系处理 AbstractAutowireCapableBeanFactory 实现了bean的create过程 DefaultListableBeanFactory 实现了BeanDefinition的管理

以下是getBean方法的实现流程。

getBean经过方法重载后,最终调用的是doGetBean方法, 需要的方法参数如下: 1.name 你要得到bean对象的名称 不能为空 2.requiredType 这个bean对象的Class类型,可以为null 3.args 可以为null,如果有参数,则代表在找到这个bean定义后,通过构造方法或工厂方法或其他方法传入args参数来改变这个bean实例。 spring 工厂开始自动化处理了.

4. Spring的循环依赖处理方式.

所谓Spring的循环依赖,指的是这样一种场景:

当我们注入一个对象A时,需要注入对象A中标记了某些注解的属性,这些属性也就是对象A的依赖,把对象A中的依赖都初始化完成,对象A才算是创建成功。那么,如果对象A中有个属性是对象B,而且对象B中有个属性是对象A,那么对象A和对象B就算是循环依赖,如果不加处理,就会出现:创建对象A–>处理A的依赖B–>创建对象B–>处理B的对象A–>创建对象A–>处理A的依赖B–>创建对象B…这样无限的循环下去。

这事显然不靠谱。

Spring处理循环依赖的基本思路是这样的:

虽说要初始化一个Bean,必须要注入Bean里的依赖,才算初始化成功,但并不要求此时依赖的依赖也都注入成功,只要依赖对象的构造方法执行完了,这个依赖对象就算存在了,注入就算成功了,至于依赖的依赖,以后再初始化也来得及(参考Java的内存模型)。

因此,我们初始化一个Bean时,先调用Bean的构造方法,这个对象就在内存中存在了(对象里面的依赖还没有被注入),然后把这个对象保存下来,当循环依赖产生时,直接拿到之前保存的对象,于是循环依赖就被终止了,依赖注入也就顺利完成了。

举个例子:

假设对象A中有属性是对象B,对象B中也有属性是对象A,即A和B循环依赖。

创建对象A,调用A的构造,并把A保存下来。 然后准备注入对象A中的依赖,发现对象A依赖对象B,那么开始创建对象B。 调用B的构造,并把B保存下来。 然后准备注入B的构造,发现B依赖对象A,对象A之前已经创建了,直接获取A并把A注入B(注意此时的对象A还没有完全注入成功,对象A中的对象B还没有注入),于是B创建成功。 把创建成功的B注入A,于是A也创建成功了。 于是循环依赖就被解决了。

5.缓存穿透与缓存击穿问题

5.1缓存穿透(数据查询不到—>假数据、set集合放ID布隆过滤器过滤)

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

解决方案(防止mysql宕机) 在Redis中放入 1.假数据 2.set集合,里面放入所有mysql中的id,再通过布隆过滤器过滤,没有这个id的请求就不在mysql中找了

5.2、缓存击穿(热点数据到期—>访问一次加一次访问时间、加锁)

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

解决方案 1.从Redis处理:一个请求,给这个热点数据加一点时间(避免热点数据过期) 2.分布式锁:Tomcat集群synchronized-Tomcat分布式锁-Redis(避免大量数据访问数据库)

6、MySql存储引擎

mysql支持存储引擎有好几种,咱们这里主要讨论一下常用的几种存储引擎。Innodb,myisam

索引是 MySQL数据库很重要的一部分,它对数据表查询性能的好坏起着决定性的作用,尤其是对大表作用更加明显。 作为索引中最为常见的一种类型,B-Tree索引大都采用的是 B+Tree数据结构来存储数据(NDB集群存储引擎内部实际上采用 T-Tree结构存储这种索引)。B-Tree通常也意味着所有的值都是按顺序存储的。 大多数的 MySQL引擎都支持这种索引,而不同的存储引擎以不同的方式来实现 B-Tree索引,性能方面各有优劣。

1.INNODB索引实现

与 MyISAM相同的一点是,InnoDB 也采用 B+Tree这种数据结构来实现 B-Tree索引。而很大的区别在于,InnoDB 存储引擎采用“聚集索引”的数据存储方式实现B-Tree索引,所谓“聚集”,就是指数据行和相邻的键值紧凑地存储在一起,注意 InnoDB 只能聚集一个叶子页(16K)的记录(即聚集索引满足一定的范围的记录),因此包含相邻键值的记录可能会相距甚远。

在 InnoDB 中,表被称为 索引组织表(index organized table),InnoDB 按照主键构造一颗 B+Tree (如果没有主键,则会选择一个唯一的并且非空索引替代,如果没有这样的索引,InnoDB则会隐式地定义一个主键来作为聚集索引),同时叶子页中存放整张表的行记录数据,也可以将聚集索引的叶子节点称为数据页,非叶子页可以看做是叶子页的稀疏索引。

全表扫描: 当InnoDB做全表扫描时并不高效,因为 InnoDB 实际上并没有顺序读取,在大多情况下是在随机读取。做全表扫描时,InnoDB 会按主键顺序扫描页面和行。这应用于所有的InnoDB 表,包括碎片化的表。如果主键页表没有碎片(存储主键和行的页表),全表扫描是相当快,因为读取顺序接近物理存储顺序。但是当主键页有碎片时,该扫描就会变得十分缓慢

行级锁 提供行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non-locking read in SELECTs),另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

2.MyISAM索引的实现 每个MyISAM在磁盘上存储成三个文件。 树中叶子保存的是对应行的物理位置。通过该值,存储引擎能顺利地进行回表查询,得到一行完整记录。同时,每个叶子页也保存了指向下一个叶子页的指针。从而方便叶子节点的范围遍历。 而对于二级索引,在 MyISAM存储引擎中以与上图同样的方式实现,这也说明了 MyISAM的索引方式是“非聚集的”,与 Innodb的“聚集索引”形成了对比

MyISAM 默认会把索引读入内存,直接在内存中操作;

小结:Innodb强调多功能性,支持的拓展功能比较多,myisam主要侧重于性能

区别 InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务; InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。 InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快; Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;

如何选择 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM; 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使用InnoDB。 系统奔溃后,MyISAM恢复起来更困难,能否接受; MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。

7.Mybatis的一级缓存和二级缓存的区别?

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

Mybatis的一级缓存和二级缓存的区别

一级缓存(默认开启) SqlSession级别的缓存,实现在同一个会话中数据的共享. 基于sqlSession默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互相不影响的。 二级缓存 SqlSessionFactory级别的缓存,实现不同会话中数据的共享,是一个全局变量。 不同的sqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。

8.HashMap

HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量 调整为16,当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍。目的是 减少调整元素的个数,jdk1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,目 的提高执行效率,jdk1.8 当链表长度小于等于6时,调整成链表,jdk1.8以前,链表是头插入(容易在扩容的时候,形成循环链表),jdk1.8以后是尾插入(避免循环链表)

HashMap的安全问题

jdk1.7及之前的HashMap

在HashMap扩容的是时候会调用resize()方法中的transfer()方法,在这里由于是头插法所以在多线程情况下可能出现循环链表,所以后面的数据定位到这条链表的时候会造成数据丢失。和读取的可能导致死循环。

jdk1.8HashMap

1.8的HashMap对此做了优化,resize采用了尾插法,即不改变原来链表的顺序,所以不会出现1.7的循环链表的问题。但是它也不是线程线程安全的。不安全性如下:

在多线程情况下put时计算出的插入的数组下标可能是相同的,这时可能出现值的覆盖从而导致size也是不准确的。

9. final , finally , finalize区别

final修饰成员变量,成员方法,类 finally修饰代码块 finalize是Object类中的一个方法 -> 复活币 × 1

10.static关键字修饰什么

内部类 方法 变量 代码块 导包

11.volatile关键字

1.被volatile修饰的变量保证对所有线程可见。 2.禁止指令重排优化

12.CAS乐观锁(比较和交换)

CAS介绍(compare and swap比较和交换): CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS是一种非阻塞式的同步方式。 CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。 CAS导致ABA问题:添加版本 线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以CAS成功。但实际上这时的现场已经和最初不同了,尽管CAS成功,但可能存在潜藏的问题,如果CAS次数过多,会额外损耗CPU性能 解决ABA问题:增加版本号

13.GC的垃圾回收

1.JVM内存分代模型 年轻代和老年代 JVM将堆内存划分为了两个区域,即年轻代和老年代。年轻代主要存放的是创建和使用完即将被回收的对象,老年代存放的是一些长期被使用的对象。 2.确定是否回收

1、引用计数算法

判断对象的引用数量
   通过判断对象的引用数量来决定对象是否可以被回收;
   每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1;
   任何引用计数为0的对象实例可以被当作垃圾收集。
优点:执行效率高,程序执行受影响较小。
缺点:无发检测出循环引用的情况,导致内存泄露。
2.可达性分析算法

有一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径被称
为“引用链”。
如果一个对象到GC Roots没有任何引用链相连接时,说明这个对象是不可用的。如果一个对象
到GC Roots有引用链相连接时,说明这个对象是可用的。
也就是说,给定一个集合的引用作为根节点出发,通过引用关系遍历对象图,能够遍历到的对象
就被判定为存活,不能够被遍历到的对象说明对象死亡。

3.常用垃圾算法

在这里插入图片描述
在这里插入图片描述
1.复制算法(新生代回收算法)

复制算法主要运用在新生代中,把新生代内存划分为两块内存区域,然后只使用其中一块,待
那块内存快满的时候,就把里面的存活对象一次性转移到另外一块内存区域,然后回收原来那
块的垃圾对象。

整个垃圾回收的流程就是,刚开始创建的对象都是在Eden区域的,如果Eden区域快满了,就会
触发垃圾回收。Eden区把存活的对象都转移到空着的S1区域,接着Eden区就会被请客。然后再
次分配对象到Eden区中直到满了进行下一次垃圾回收,这时会将S1中存活的对象和Eden区存活
的对象转移到空的Survivor区中(S2) 。这就是为什么新生代会被划分为8:1:1的结构了,
这样对内存的利用率会大大提升。
2.标记清除法

标记-清除算法采用从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,
再扫描整个空间中未被标记的对象,进行回收,如下图所示。标记-清除算法不需要进行对
象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标
记-清除算法直接回收不存活的对象,因此会造成内存碎片。
3.标记整理算法(老年代回收算法)

标记-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活
的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整
理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存
碎片的问题。

可以作为GC Root的对象 虚拟机栈中引用的对象(栈帧中的本地变量) 方法区中的常量引用的对象 方法区中的类静态属性引用的对象 本地方法中JNI(native方法)的引用对象 活跃线程的引用对象

15.class文件是如何加载到JVM内存的

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

各个加载器的工作责任:

1)Bootstrap ClassLoader:负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

2)Extension ClassLoader:负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

3)App ClassLoader:负责记载classpath中指定的jar包及目录中class

工作过程:

1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载
请求委派给父类加载器ExtClassLoader去完成。

2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加
载请求委派给BootStrapClassLoader去完成。

3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class)
,会使用ExtClassLoader来尝试加载;

4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载

5、如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

这就是所谓的双亲委派模型。简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。

好处:防止内存中出现多份同样的字节码(安全性角度)

特别说明:类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。

类加载详细过程

加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象。
连接,连接又包含三块内容:验证、准备、解析。
1)验证,文件格式、元数据、字节码、符号引用验证;
2)准备,为类的静态变量分配内存,并将其初始化为默认值;
3)解析,把类中的符号引用转换为直接引用
初始化,为类的静态变量赋予正确的初始值。

16.JVM内存模型(待完善)

在这里插入图片描述
在这里插入图片描述
1.程序计数器(PC寄存器):

程序计数器是一块较小的内存空间,是当前线程正在执行的哪一条字节码指令的地址,若当前
线程正在执行的是一个本地方法
2.Java虚拟机栈(待完善)

描述Java方法运行过程的内存模型,保存局部变量、基本数据类型以及堆内存中对象的引用变量
随着线程创建而创建,随着线程的结束而销毁
3.本地方法栈

为JVM提供使用native方法的服务,本地方法栈描述本地方法运行过程的内存模型
也会抛出StackOverFlowError和OutOfMemoryError异常
4.堆

线程共享、垃圾回收的主要场地,在虚拟机启动的时候就被创建
堆这块区域是JVM中最大的,堆内存的大小是可以调节的
5.方法区

线程共享、 存储的是类信息+普通常量+静态常量+编译器编译后的代码等,
常量池(Constant Pool)是方法区的一部分

16.1虚拟机栈如何执行方法的

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

16.2方法区在JDK各个版本的更新

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

17.SQL语句的优化

sql本身优化,避免全盘扫描

18.聚簇索引和非聚簇索引

主键索引: 其他索引:

19.索引的常见结构

hash:数据量不大,效率远高于BTree

BTree,B+Tree:数据量大,更加稳定 树高问题,叶子节点指针

20.ES保存数据后,为什么不能立即查看到

我们经常有这样的需求,在对 Elasticsearch 数据进行操作的时候,要及时返回刚刚操作完毕的数据,或者数据列表。

比如加入存储一条数据后,我马上要返回数据的总条数,这个时候,会出问题,Elasticsearch会返回操作之前的数据,也就是假如开始有500条数据,我Insert了一条进去,按道理来说应该是501条,但是这个时候查询会发现,只有500条数据,再次请求又得到501条数据。

BulkRequestBuilder bulkRequest = ESTools.client.prepareBulk().setRefresh(true);

这里的setRefresh(true);

就是自动刷新的用处。所以在我们CRUD的时候,如果对数据增删改操作的时候,如果要及时返回最新数据,那么我们就需要加这个方法,及时刷新数据。

21.SpringMVC运行流程

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

22.SpringBoot自动装配

@SpringBootApplication中有一个@import的注解,这个注解里面加载一个

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

里面有一个selectImports方法,将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。

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

会从META-INF/spring.factories中获取资源,然后通过Properties加载资源:

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

Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。

23.Redis集群架构

(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽;

(2)节点的Fail是通过集群中超过半数的节点检测失效时才生效;

(3)客户端与redis节点直连,不需要中间proxy层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可;

(4)redis-cluster把所有的物理节点映射到[0-16383]slot(插槽)上,cluster 负责维护node<->slot<->value。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Java并发类:
  • 2.Spring的IOC以及AOP.
  • 3.Spring的Bean的加载过程.
  • 4. Spring的循环依赖处理方式.
  • 5.缓存穿透与缓存击穿问题
  • 6、MySql存储引擎
  • 7.Mybatis的一级缓存和二级缓存的区别?
  • 8.HashMap
  • 9. final , finally , finalize区别
  • 10.static关键字修饰什么
  • 11.volatile关键字
  • 12.CAS乐观锁(比较和交换)
  • 13.GC的垃圾回收
  • 15.class文件是如何加载到JVM内存的
  • 16.JVM内存模型(待完善)
  • 16.1虚拟机栈如何执行方法的
  • 16.2方法区在JDK各个版本的更新
  • 17.SQL语句的优化
  • 18.聚簇索引和非聚簇索引
  • 19.索引的常见结构
  • 20.ES保存数据后,为什么不能立即查看到
  • 21.SpringMVC运行流程
  • 22.SpringBoot自动装配
  • 23.Redis集群架构
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档