首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

Java 并发编程:Callable+Future+FutureTask详解

Runnable其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 : publicinterfaceRunnable{/**@seejava.lang.Thread#run()*/publicabstractvoidrun(); } CallableCallable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 : publicinterfaceCallable{/***Computesaresult,orthrowsanexceptionifunabletodoso. * *@returncomputedresult *@throwsExceptionifunabletocomputearesult*/Vcall()throwsException; } FutureExecutor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行 取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 : publicinterfaceFuture{/***Attemptstocancelexecutionofthistask.Thisattemptwill *failifthetaskhasalreadycompleted,hasalreadybeencancelled, *orcouldnotbecancelledforsomeotherreason.Ifsuccessful, *andthistaskhasnotstartedwhencanceliscalled, *thistaskshouldneverrun.Ifthetaskhasalreadystarted, *thenthemayInterruptIfRunningparameterdetermines *whetherthethreadexecutingthistaskshouldbeinterruptedin *anattempttostopthetask.*/booleancancel(booleanmayInterruptIfRunning);/***Returnstrueifthistaskwascancelledbeforeitcompleted *normally.*/booleanisCancelled();/***Returnstrueifthistaskcompleted. **/booleanisDone();/***Waitsifnecessaryforthecomputationtocomplete,andthen *retrievesitsresult. * *@returnthecomputedresult*/Vget()throwsInterruptedException,ExecutionException;/***Waitsifnecessaryforatmostthegiventimeforthecomputation *tocomplete,andthenretrievesitsresult,ifavailable. * *@paramtimeoutthemaximumtimetowait *@paramunitthetimeunitofthetimeoutargument *@returnthecomputedresult*/Vget(longtimeout,TimeUnitunit)throwsInterruptedException,ExecutionException,TimeoutException; } FutureTask FutureTask是一个RunnableFuture public class FutureTaskRunnableFuture实现了Runnbale又实现了Futrue publicinterfaceRunnableFutureextendsRunnable,Future{/***SetsthisFuturetotheresultofitscomputation *unlessithasbeencancelled.*/voidrun(); } 另外FutureTaslk还可以包装Runnable和Callable,由构造函数注入依赖。publicFutureTask(Callablecallable){if(callable==null)thrownewNullPointerException();this.callable=callable;this.state=NEW;//ensurevisibilityofcallable}publicFutureTask(Runnablerunnable,Vresult){this.callable=Executors.callable(runnable,result);this.state=NEW;//ensurevisibilityofcallable} 上面代码块可以看出:Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 : publicstaticCallablecallable(Runnabletask,Tresult){if(task==null)thrownewNullPointerException();returnnewRunnableAdapter(task,result); } RunnableAdapter适配器 /** *Acallablethatrunsgiventaskandreturnsgivenresult*/staticfinalclassRunnableAdapterimplementsCallable{finalRunnabletask;finalTresult; RunnableAdapter(Runnabletask,Tresult){this.task=task;this.result=result; }publicTcall(){ task.run();returnresult; } } FutureTask实现Runnable,所以能通过Thread包装执行, FutureTask实现Runnable,所以能通过提交给ExcecuteService来执行 注:ExecuteService:创建线程池实例对象,其中有submit(Runnable)、submit(Callable)方法 还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。 因此FutureTask是Future也是Runnable,又是包装了的Callable( 如果是Runnable最终也会被转换为Callable )。 Callable和Future接口的区别 1.Callable规定的方法是call(),而Runnable规定的方法是run().2.Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。3.call()方法可抛出异常,而run()方法是不能抛出异常的。4.运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。5.它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。6.通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。7.Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。 示例: packagecom.xzf.callable;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;importjava.util.concurrent.FutureTask;publicclassRunnableFutureTask{staticExecutorServiceexecutorService=Executors.newSingleThreadExecutor();//创建一个单线程执行器publicstaticvoidmain(String[]args){ runnableDemo(); futureDemo(); }/***newThread(Runnablearg0).start();用Thread()方法开启一个新线程 *runnable,无返回值*/staticvoidrunnableDemo(){newThread(newRunnable(){ publicvoidrun(){ System.out.println("runnabledemo:"+fibc(20));//有值} }).start(); }/***Runnable实现的是voidrun()方法,无返回值 *Callable实现的是Vcall()方法,并且可以返回执行结果 *Runnable可以提交给Thread,在包装下直接启动一个线程来执行 *Callable一般都是提交给ExecuteService来执行*/staticvoidfutureDemo(){try{ Futureresult1=executorService.submit(newRunnable(){publicvoidrun(){ fibc(20); } }); System.out.println("futureresultfromrunnable:"+result1.get());//run()无返回值所以为空,result1.get()方法会阻塞Futureresult2=executorService.submit(newCallable(){publicIntegercall()throwsException{returnfibc(20); } }); System.out.println("futureresultfromcallable:"+result2.get());//call()有返回值,result2.get()方法会阻塞FutureTaskresult3=newFutureTask(newCallable(){publicIntegercall()throwsException{returnfibc(20); } }); executorService.submit(result3); System.out.println("futureresultfromFutureTask:"+result3.get());//call()有返回值,result3.get()方法会阻塞/*因为FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行*/FutureTaskresult4=newFutureTask(newRunnable(){publicvoidrun(){ fibc(20); } },fibc(20)); executorService.submit(result4); System.out.println("futureresultfromexecuteServiceFutureTask:"+result4.get());//call()有返回值,result3.get()方法会阻塞//这里解释一下什么FutureTask实现了Runnable结果不为null,这就用到FutureTask对Runnable的包装,所以Runnable注入会被Executors.callable()函数转换成Callable类型FutureTaskresult5=newFutureTask(newRunnable(){publicvoidrun(){ fibc(20); } },fibc(20));newThread(result5).start(); System.out.println("futureresultfromThreadFutureTask:"+result5.get());//call()有返回值,result5.get()方法会阻塞}catch(Exceptione){ e.printStackTrace(); }finally{ executorService.shutdown(); } }staticintfibc(intnum){if(num==0){return0; }if(num==1){return1; }returnfibc(num-1)+fibc(num-2); } }

优秀的个人博客,低调大师

BeetlSQL 3.4.1 发布,流行的 Java DAO 工具

本次发布做了微调 修复内置Update语句表名没有经过KeywordHandler处理 删除了sql-spring集成对spring-test的依赖 <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetlsql</artifactId> <version>3.4.1-RELEASE</version> </dependency> BeetlSQL 研发自2015年,目标是提供开发高效,维护高效,运行高效的数据库访问框架,它适用范围广,定制性强,写起数据库访问代码特别顺滑。目前支持的数据库如下 传统数据库:MySQL,MariaDB,Oralce,Postgres,DB2,SQL Server,H2,SQLite,Derby,神通,达梦,华为高斯,人大金仓,PolarDB 等 大数据:HBase,ClickHouse,Cassandar,Hive 物联网时序数据库:Machbase,TD-Engine,IotDB SQL查询引擎:Drill,Presto,Druid 内存数据库:ignite,CouchBase 阅读文档源码和例子在线体验 BeetlSQL也支持IDEA插件,提供向导和自动提示

优秀的个人博客,低调大师

MyBatis 3.5.7 发布,Java 数据持久层框架

MyBatis 3.5.7 已发布,MyBatis 的前身为 iBatis,是一个数据持久层(ORM)框架,它提供的持久层能力包括 SQL Maps 和 Data Access Objects(DAO)。 主要更新内容: 优化 JDK 8 下的性能#2223 修复并发访问缓存时可能出现错误的问题#2179 将已被弃用的 Mockito.verifyZeroInteractions 替换为 verifyNoInteractions#2077 此外还有代码和文档方面的改进,详情点此查看。 下载地址: https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.7 https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.7

优秀的个人博客,低调大师

Java高级面试(一)消息队列问题整合

①消息队列运用场景: 比如有一个订单系统,每次下一个订单的时候就会发送一条消息队列里面(activeMQ)然后又有一个库存系统负责获取消息队列里面的消息,最后更新库存 ②为什么使用消息队列: 解耦: 在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。 冗余: 有时在处理数据的时候处理过程会失败。除非数据被持久化,否则将永远丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。 扩展性: 因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。 灵活性 & 峰值处理能力: 当你的应用上了Hacker News的首页,你将发现访问流量攀升到一个不同寻常的水平。在访问量剧增的情况下,你的应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住增长的访问压力,而不是因为超出负荷的请求而完全崩溃。 可恢复性: 当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。 送达保证: 消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。在此基础上,IronMQ提供了一个"只送达一次"保证。无论有多少进程在从队列中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息只是"预定"了这个消息,暂时把它移出了队列。除非客户端明确的表示已经处理完了这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。 排序保证: 在许多情况下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。IronMO保证消息浆糊通过FIFO(先进先出)的顺序来处理,因此消息在队列中的位置就是从队列中检索他们的位置。 缓冲: 在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行--写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。 理解数据流: 在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。 异步通信: 很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。 ③消息队列的优缺点: 优点: 1)解耦 场景:当A系统需要发送数据到BCD三个系统时。 如果使用接口调用,A系统是和BCD系统耦合在一起的,需要考虑BCD系统挂了怎么办?BCD系统消费失败怎么办?如果E系统也需要这个数据?如果B系统现在不需要这个数据? 如果使用MQ,A系统产生的数据,只要保证消息成功发送到MQ中。各个系统需要数据,自己到MQ中消费。如果新系统需要数据,直接从MQ里消费,如果老系统不需要数据了,直接取消对MQ的消费。 通过MQ,A系统和其他系统彻底解耦了。 2)异步 场景:A系统接到请求,需要在本系统写库,还需要在BCD三个系统写库。 自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。如果同步调用,最终请求总延时是 3 + 300 + 450 + 200 = 953ms。 如果使用MQ,A系统发送三个消息到三个MQ,假设耗时5ms,则A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms。 3)消峰 场景:每天 0:00 到 12:00,A 系统风平浪静,每秒并发请求数量就 50 个。结果每次一到 12:00 ~ 13:00 ,每秒并发请求数量突然会暴增到 5k+ 条。但是系统是直接基于 MySQL 的,大量的请求涌入 MySQL,每秒钟对 MySQL 执行约 5k 条 SQL。 一般的 MySQL,扛到每秒 2k 个请求就差不多了,如果每秒请求到 5k 的话,可能就直接把 MySQL 给打死了,导致系统崩溃,用户也就没法再使用系统了。 如果使用 MQ,每秒 5k 个请求写入 MQ,A 系统每秒钟最多处理 2k 个请求,因为 MySQL 每秒钟最多处理 2k 个。A 系统从 MQ 中慢慢拉取请求,每秒钟就拉取 2k 个请求,不要超过自己每秒能处理的最大请求数量就 ok,这样下来,哪怕是高峰期的时候,A 系统也绝对不会挂掉。 缺点: 1)系统可用性降低 外部依赖的系统多了,增加了消息队列系统。 2)系统复杂度提高 你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性? 3)一致性问题 数据可能不一致。 ③kafka、activemq、rabbitmq 、rocketmq优缺点: ④如何保证消息队列的高可用: RabbitMQ 的高可用性 RabbitMQ 是比较有代表性的,因为是基于主从(非分布式)做高可用性的,我们就以 RabbitMQ 为例子讲解第一种 MQ 的高可用性怎么实现。 RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。 单机模式 单机模式,就是 Demo 级别的,一般就是你本地启动了玩玩儿的?,没人生产用单机模式。 普通集群模式(无高可用性) 普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的 queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。 这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集群。因为这导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个 queue 所在实例消费数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。 而且如果那个放 queue 的实例宕机了,会导致接下来其他实例就无法从那个实例拉取,如果你开启了消息持久化,让 RabbitMQ 落地存储消息的话,消息不一定会丢,得等这个实例恢复了,然后才可以继续从这个 queue 拉取数据。 所以这个事儿就比较尴尬了,这就没有什么所谓的高可用性,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。 镜像集群模式(高可用性) 这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。 那么如何开启这个镜像集群模式呢?其实很简单,RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。 这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息需要同步到所有机器上,导致网络带宽压力和消耗很重!第二,这么玩儿,不是分布式的,就没有扩展性可言了,如果某个 queue 负载很重,你加机器,新增的机器也包含了这个 queue 的所有数据,并没有办法线性扩展你的 queue。你想,如果这个 queue 的数据量很大,大到这个机器上的容量无法容纳了,此时该怎么办呢? Kafka 的高可用性: Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker 是一个节点;你创建一个 topic,这个 topic 可以划分为多个 partition,每个 partition 可以存在于不同的 broker 上,每个 partition 就放一部分数据。 这就是天然的分布式消息队列,就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。 实际上 RabbmitMQ 之类的,并不是分布式消息队列,它就是传统的消息队列,只不过提供了一些集群、HA(High Availability, 高可用性) 的机制而已,因为无论怎么玩儿,RabbitMQ 一个 queue 的数据都是放在一个节点里的,镜像集群下,也是每个节点都放这个 queue 的完整数据。 Kafka 0.8 以前,是没有 HA 机制的,就是任何一个 broker 宕机了,那个 broker 上的 partition 就废了,没法写也没法读,没有什么高可用性可言。 比如说,我们假设创建了一个 topic,指定其 partition 数量是 3 个,分别在三台机器上。但是,如果第二台机器宕机了,会导致这个 topic 的 1/3 的数据就丢了,因此这个是做不到高可用的。 Kafka 0.8 以后,提供了 HA 机制,就是 replica(复制品) 副本机制。每个 partition 的数据都会同步到其它机器上,形成自己的多个 replica 副本。所有 replica 会选举一个 leader 出来,那么生产和消费都跟这个 leader 打交道,然后其他 replica 就是 follower。写的时候,leader 会负责把数据同步到所有 follower 上去,读的时候就直接读 leader 上的数据即可。只能读写 leader?很简单,要是你可以随意读写每个 follower,那么就要care 数据一致性的问题,系统复杂度太高,很容易出问题。Kafka 会均匀地将一个 partition 的所有 replica 分布在不同的机器上,这样才可以提高容错性。 这么搞,就有所谓的高可用性了,因为如果某个 broker 宕机了,没事儿,那个 broker上面的 partition 在其他机器上都有副本的。如果这个宕机的 broker 上面有某个 partition 的 leader,那么此时会从 follower 中重新选举一个新的 leader 出来,大家继续读写那个新的 leader 即可。这就有所谓的高可用性了。 写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为) 消费的时候,只会从 leader 去读,但是只有当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。 看到这里,相信你大致明白了 Kafka 是如何保证高可用机制的了,对吧?不至于一无所知,现场还能给面试官画画图。要是遇上面试官确实是 Kafka 高手,深挖了问,那你只能说不好意思,太深入的你没研究过。 ⑤怎么确保消息的顺序性: 举个例子: 有一个mysql binlog 同步系统,压力是非常大的,日同步数据达到了上亿级别,就是将数据从一个 mysql 库当中原封不动的同步到另一个 mysql 库当中去(比较常见的就是大数据组需要干的事情)。 假设在 mysql 当中增删改了一条数据,对应的生产了三条 增删改的 binlog 日志,接着这三条 binlog 发送到 MQ 里面去,然后进行消费。这时候就得保证消息队列的顺序性了。不然本来是:增加、修改、删除;你愣是换了顺序给执行成删除、修改、增加,不全错了么。 再来看看顺序会错乱的俩场景: RabbitMQ:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者2先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。具体如下图所示: Kafka:比如说建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。消费者从 partition 中取出来数据的时候,也一定是有顺序的。到这里,顺序还是 ok 的,没有错乱。接着,我们在消费者里可能会搞多个线程来并发处理消息。因为如果消费者是单线程消费处理,而处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟只能处理几十条消息,这吞吐量太低了。而多个线程并发跑的话,顺序可能就乱掉了。具体如下图: 解决方案: RabbitMQ: 拆分多个 queue,每个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。具体如下图: Kafka: 一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。 写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。具体如下图所示:

优秀的个人博客,低调大师

sagacity-sqltoy 4.17.8 发布,Java ORM 框架

sagacity-sqltoy 4.17.8 已经发布,此版本更新内容包括: 1、支持缓存翻译未匹配模板设置为空白或空字符串: uncached-template=""(之前空白当成无效设置,依旧返回xxkey 未匹配) <translate cache="dictCache" cache-type="POST_TYPE" columns="POST_TYPE" uncached-template="" /> sqltoy-orm是比hibernate+myBatis更加贴合项目的orm框架(依赖spring),具有jpa式的对象CRUD的同时具有比myBatis(plus)更直观简洁性能强大的查询功能。 支持以下数据库: oracle 11g+ db2 9.5+,建议从10.5 开始 mysql(mariadb/innosql)支持5.6、5.7、8.0 版本 postgresql(greenplum) 支持9.5 以及以上版本 sqlserver 支持2008到2019版本,建议使用2012或以上版本 sqlite DM达梦数据库 elasticsearch 只支持查询,版本支持5.7+版本,建议使用7.3以上版本 clickhouse oceanBase guassdb tidb kingbase mongodb (只支持查询) sybase_iq 支持15.4以上版本,建议使用16版本 详情查看:https://gitee.com/sagacity/sagacity-sqltoy/releases/4.17.8

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册