Flyway 数据库脚本版本控制工具
Flyway简介
Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等,还提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。
官方网站:https://flywaydb.org/
概念
版本:对数据库的每一次变更可称为一个版本。
迁移:Flyway把数据库结构从一个版本更新到另一个版本叫做迁移。
可用的迁移:Flyway的文件系统识别出来的迁移版本。
已经应用的迁移:Flyway已经对数据库执行过的迁移。
flyway基本命令
Migrate:应用所有的迁移到最新版本,它会在你的DB中新建个表schema_version来存放每次升级的版本信息。
Clean:clean all objects
Info:打印所有的迁移的信息以及状态。
Validate:迁移之前进行验证。
Baseline:初始化schema_version表,并插入一条原始verion=1。
Repair:它主要做了两件事,移除所有失败的迁移(升级),重置校验和。
SQL脚本的命名规则
- 前缀:
V
用于版本化(可配置),U
用于撤消(可配置)和R
用于可重复迁移(可配置) - 版本:带点或下划线的版本可以根据需要分开多个部分(不适用于可重复的迁移)
- 分隔符 :(
__
两个下划线)(可配置) - 描述:下划线或空格分隔单词
- 后缀:
.sql
(配置)
SQL存放路径规则
SQL句法
Flyway支持所有常规SQL语法元素,包括:
- 单行或多行语句
- 单( - )或多行(/ * * /)注释跨越完整的行
- 特定于数据库的SQL语法扩展(PL / SQL,T-SQL,...)通常用于定义存储过程,包,...
此外,对于Oracle,Flyway还支持SQL * Plus命令。
命令-迁移
Migrate(迁移)是Flyway工作流程的核心。它将扫描文件系统或类路径以获取可用的迁移。然后将它们与已应用于数据库的迁移进行比较。如果发现任何差异,它将迁移数据库以缩小差距。迁移最好应在应用程序启动时执行,以避免数据库与代码期望之间的任何不兼容性。
执行migrate是幂等的,无论当前版本的架构如何,都可以安全地执行。
示例1:我们的迁移可用版本9,数据库版本为5。
迁移将按顺序应用迁移6,7,8和9。示例2:我们的迁移可用版本9,数据库版本为9。
迁移什么都不做。
命令-清理
删除配置的模式中的所有对象。清理对开发和测试有很大帮助。通过彻底清除已配置的模式,它将有效地为您提供一个全新的开始。将删除所有对象(表,视图,过程......)。
注:请不要在生产库执行此操作。
命令-信息
打印有关所有迁移的详细信息和状态信息。信息让您知道自己的位置。您可以一目了然地看到哪些迁移已经应用,哪些迁移尚未处理,何时执行以及它们是否成功。
命令-验证
根据可用的迁移验证应用的迁移。验证可帮助您验证应用于数据库的迁移是否与本地可用的迁移相匹配。这对于检测可能阻止您可靠地重新创建架构的意外更改非常有用。
命令-撤销
撤消最近应用的版本化迁移。如果target
已指定,Flyway将尝试按照应用顺序撤消版本化迁移,直到它遇到版本低于目标的版本。如果group
处于活动状态,Flyway将尝试在单个事务中撤消所有这些迁移。如果没有要撤消的版本化迁移,则调用undo无效。没有可重复迁移的撤消功能。在这种情况下,应修改可重复迁移以包括所需的旧状态,然后使用migrate重新应用。
注:该命令的设计初衷不错,但是实际上不实用,因为不是所有的命令都支持回滚。
命令-底线
基准现有数据库,不包括所有迁移,包括baselineVersion。基线是将Flyway引入现有数据库,方法是将它们基于特定版本。这将导致迁移忽略所有迁移,包括基线版本。然后将照常应用较新的迁移。
命令-修复
修复架构历史记录表,修复是修复模式历史记录表问题的工具。它有两个主要用途:
- 删除失败的迁移条目(仅适用于不支持DDL事务的数据库)
- 将应用的迁移的校验和,描述和类型与可用的迁移重新对齐
JAVA项目应用
- 第一步,在
pom.xml
中增加flyway的依赖:
<dependency><groupId>org.flywaydb</groupId><artifactId>flyway-core</artifactId><version>5.2.4</version>
</dependency>
- 第二步,按Flyway的规范创建版本化的SQL脚本。
- 在工程的
src/main/resources
目录下创建db
目录,然后在db目录下创建migration目录
- 在migration目录下创建版本化的SQL脚本
V2__export.sql , 如果不创建脚本启动会报错,应该是有什么参数需要配置。
CREATE TABLE `flyway_test` (`id` int(4) NOT NULL,`name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
- 第三步,在
application.yml
文件中配置Flyway属性(在spring节点下)。
如果没有特殊要求,那么默认的配置参数即可满足需求,不需要额外配置。
flyway:baseline-on-migrate: true
按住CTRL键,鼠标左键单击,即可发现flyway的配置参数有哪些,目前最新的版本是 6.0.0 测试版本,配置参数很多会在6.0.x 之后废弃掉,这里需要注意下:
2019-05-13 10:43:29 WARN 51032 [main] org.flywaydb.core.Flyway : Direct configuration of the Flyway object has been deprecated and will be removed in Flyway 6.0. Use Flyway.configure() instead.
2019-05-13 10:43:29 WARN 51032 [main] org.flywaydb.core.Flyway : Direct configuration of the Flyway object has been deprecated and will be removed in Flyway 6.0. Use Flyway.configure() instead.
这里贴俩个关键的配置类,springboot2默认是集成了flyway的,如果配置了datasource,那么不需要配置flyway的user/password/url 参数。如果使用druid的数据源,那么需要修改一个配置参数“wall”,它会组织flyway执行脚本:
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙filters: stat,slf4j
package org.springframework.boot.autoconfigure.flyway;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "spring.flyway",ignoreUnknownFields = true
)
public class FlywayProperties {private List<String> locations = new ArrayList(Collections.singletonList("classpath:db/migration"));private boolean checkLocation = true;private boolean enabled = true;private String user;private String password;private String url;private List<String> initSqls = new ArrayList();public FlywayProperties() {}。。。
}
package org.flywaydb.core.api.configuration;import java.io.File;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import javax.sql.DataSource;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.Location;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.FlywayCallback;
import org.flywaydb.core.api.errorhandler.ErrorHandler;
import org.flywaydb.core.api.logging.Log;
import org.flywaydb.core.api.logging.LogFactory;
import org.flywaydb.core.api.resolver.MigrationResolver;
import org.flywaydb.core.internal.callback.LegacyCallback;
import org.flywaydb.core.internal.configuration.ConfigUtils;
import org.flywaydb.core.internal.jdbc.DriverDataSource;
import org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException;
import org.flywaydb.core.internal.util.ClassUtils;
import org.flywaydb.core.internal.util.Locations;
import org.flywaydb.core.internal.util.StringUtils;public class ClassicConfiguration implements Configuration {private static final Log LOG = LogFactory.getLog(ClassicConfiguration.class);private String driver;private String url;private String user;private String password;private DataSource dataSource;private int connectRetries;private String initSql;private ClassLoader classLoader;private Locations locations;private Charset encoding;private String[] schemaNames;private String table;private MigrationVersion target;private boolean placeholderReplacement;private Map<String, String> placeholders;private String placeholderPrefix;private String placeholderSuffix;private String sqlMigrationPrefix;private String repeatableSqlMigrationPrefix;private String sqlMigrationSeparator;private String[] sqlMigrationSuffixes;private boolean ignoreMissingMigrations;private boolean ignoreIgnoredMigrations;private boolean ignorePendingMigrations;private boolean ignoreFutureMigrations;private boolean validateOnMigrate;private boolean cleanOnValidationError;private boolean cleanDisabled;private MigrationVersion baselineVersion;private String baselineDescription;private boolean baselineOnMigrate;private boolean outOfOrder;private final List<Callback> callbacks;private boolean skipDefaultCallbacks;private MigrationResolver[] resolvers;private boolean skipDefaultResolvers;private boolean mixed;private boolean group;private String installedBy;public ClassicConfiguration() {this.classLoader = Thread.currentThread().getContextClassLoader();this.locations = new Locations(new String[]{"db/migration"});this.encoding = Charset.forName("UTF-8");this.schemaNames = new String[0];this.table = "flyway_schema_history";this.placeholderReplacement = true;this.placeholders = new HashMap();this.placeholderPrefix = "${";this.placeholderSuffix = "}";this.sqlMigrationPrefix = "V";this.repeatableSqlMigrationPrefix = "R";this.sqlMigrationSeparator = "__";this.sqlMigrationSuffixes = new String[]{".sql"};this.ignoreFutureMigrations = true;this.validateOnMigrate = true;this.baselineVersion = MigrationVersion.fromVersion("1");this.baselineDescription = "<< Flyway Baseline >>";this.callbacks = new ArrayList();this.resolvers = new MigrationResolver[0];}public ClassicConfiguration(ClassLoader classLoader) {this.classLoader = Thread.currentThread().getContextClassLoader();this.locations = new Locations(new String[]{"db/migration"});this.encoding = Charset.forName("UTF-8");this.schemaNames = new String[0];this.table = "flyway_schema_history";this.placeholderReplacement = true;this.placeholders = new HashMap();this.placeholderPrefix = "${";this.placeholderSuffix = "}";this.sqlMigrationPrefix = "V";this.repeatableSqlMigrationPrefix = "R";this.sqlMigrationSeparator = "__";this.sqlMigrationSuffixes = new String[]{".sql"};this.ignoreFutureMigrations = true;this.validateOnMigrate = true;this.baselineVersion = MigrationVersion.fromVersion("1");this.baselineDescription = "<< Flyway Baseline >>";this.callbacks = new ArrayList();this.resolvers = new MigrationResolver[0];if (classLoader != null) {this.classLoader = classLoader;}}}
配置参数解释:
flyway.baseline-description对执行迁移时基准版本的描述.
flyway.baseline-on-migrate当迁移时发现目标schema非空,而且带有没有元数据的表时,是否自动执行基准迁移,默认false.
flyway.baseline-version开始执行基准迁移时对现有的schema的版本打标签,默认值为1.
flyway.check-location检查迁移脚本的位置是否存在,默认false.
flyway.clean-on-validation-error当发现校验错误时是否自动调用clean,默认false.
flyway.enabled是否开启flywary,默认true.
flyway.encoding设置迁移时的编码,默认UTF-8.
flyway.ignore-failed-future-migration当读取元数据表时是否忽略错误的迁移,默认false.
flyway.init-sqls当初始化好连接时要执行的SQL.
flyway.locations迁移脚本的位置,默认db/migration.
flyway.out-of-order是否允许无序的迁移,默认false.
flyway.password目标数据库的密码.
flyway.placeholder-prefix设置每个placeholder的前缀,默认${.
flyway.placeholder-replacementplaceholders是否要被替换,默认true.
flyway.placeholder-suffix设置每个placeholder的后缀,默认}.
flyway.placeholders.[placeholder name]设置placeholder的value
flyway.schemas设定需要flywary迁移的schema,大小写敏感,默认为连接默认的schema.
flyway.sql-migration-prefix迁移文件的前缀,默认为V.
flyway.sql-migration-separator迁移脚本的文件名分隔符,默认__
flyway.sql-migration-suffix迁移脚本的后缀,默认为.sql
flyway.tableflyway使用的元数据表名,默认为schema_version
flyway.target迁移时使用的目标版本,默认为latest version
flyway.url迁移时使用的JDBC URL,如果没有指定的话,将使用配置的主数据源
flyway.user迁移数据库的用户名
flyway.validate-on-migrate迁移时是否校验,默认为true.
- 第四步,运行项目
flyway相关日志信息:
2019-05-13 11:21:26 INFO 27236 [main] org.flywaydb.core.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2019-05-13 11:21:26 INFO 27236 [main] org.flywaydb.core.internal.database.DatabaseFactory : Database: jdbc:mysql://192.168.200.51:3306/ems (MySQL 5.7)
2019-05-13 11:21:26 INFO 27236 [main] org.flywaydb.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.094s)
2019-05-13 11:21:26 INFO 27236 [main] o.f.core.internal.schemahistory.JdbcTableSchemaHistory : Creating Schema History table: `ems`.`flyway_schema_history`
2019-05-13 11:21:27 INFO 27236 [main] org.flywaydb.core.internal.command.DbBaseline : Successfully baselined schema with version: 1
2019-05-13 11:21:27 INFO 27236 [main] org.flywaydb.core.internal.command.DbMigrate : Current version of schema `ems`: 1
2019-05-13 11:21:27 INFO 27236 [main] org.flywaydb.core.internal.command.DbMigrate : Schema `ems` is up to date. No migration necessary.
数据库的初始化工作已经做完,由于默认的版本号是1,所以新建的脚本没有执行。
- 第五步,修改SQL脚本文件名,再次启动应用
将 “V1_export.sql” 修改为:“V2_export.sql”,重新启用应用,日志如下:
2019-05-13 11:29:22 INFO 27840 [main] org.flywaydb.core.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2019-05-13 11:29:22 INFO 27840 [main] org.flywaydb.core.internal.database.DatabaseFactory : Database: jdbc:mysql://192.168.200.51:3306/ems (MySQL 5.7)
2019-05-13 11:29:22 INFO 27840 [main] org.flywaydb.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.141s)
2019-05-13 11:29:22 INFO 27840 [main] org.flywaydb.core.internal.command.DbMigrate : Current version of schema `ems`: 1
2019-05-13 11:29:22 INFO 27840 [main] org.flywaydb.core.internal.command.DbMigrate : Migrating schema `ems` to version 2 - export
2019-05-13 11:29:23 INFO 27840 [main] org.flywaydb.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `ems` (execution time 00:00.551s)
不做任何修改重新启动后
2019-05-13 11:35:58 INFO 30420 [main] org.flywaydb.core.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2019-05-13 11:35:58 INFO 30420 [main] org.flywaydb.core.internal.database.DatabaseFactory : Database: jdbc:mysql://192.168.200.51:3306/ems (MySQL 5.7)
2019-05-13 11:35:58 INFO 30420 [main] org.flywaydb.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.154s)
2019-05-13 11:35:58 INFO 30420 [main] org.flywaydb.core.internal.command.DbMigrate : Current version of schema `ems`: 2
2019-05-13 11:35:58 INFO 30420 [main] org.flywaydb.core.internal.command.DbMigrate : Schema `ems` is up to date. No migration necessary.
- 第六步,将已经执行的脚本,修改文件内容再次执行一遍(验证flyway的脚本校验功能)
将 “id”字段修改为“ids”
CREATE TABLE `flyway_test` (`ids` int(4) NOT NULL,`name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
再次启动,后台报错,日志如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 2
-> Applied to database : -1894925178
-> Resolved locally : 2074103328at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1710)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:758)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:549)at org.springframework.context.support.AbstractApplicationContext.jrLockAndRefresh(AbstractApplicationContext.java:40002)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:41008)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:138)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:751)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:387)at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1245)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)at com.ems.EmsSpringBootApplication.main(EmsSpringBootApplication.java:19)
Caused by: org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 2
-> Applied to database : -1894925178
-> Resolved locally : 2074103328at org.flywaydb.core.Flyway.doValidate(Flyway.java:1482)at org.flywaydb.core.Flyway.access$100(Flyway.java:85)at org.flywaydb.core.Flyway$1.execute(Flyway.java:1364)at org.flywaydb.core.Flyway$1.execute(Flyway.java:1356)at org.flywaydb.core.Flyway.execute(Flyway.java:1711)at org.flywaydb.core.Flyway.migrate(Flyway.java:1356)at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:66)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706)... 18 common frames omitted
因此按照版本号递增脚本,即可实现脚本的增量部署。R开头的脚本会在应用每次启动后重复执行,适合放配置数据DML脚本。V开头的只会执行一次,优先级高于R开头的脚本。
插件支持
有如下插件支持:Maven, Gradle,SBT和Ant,还有更多Plugins,提供对Spring Boot, Dropwizard, Grails, Play,Griffon, Grunt, Ninja 的支持。其中可以研究下flyway-test-extensions,有Usage flyway dbunit test、Usage-flyway-spring-test 功能很强大。
POM依赖
<plugin><groupId>org.flywaydb</groupId><artifactId>flyway-maven-plugin</artifactId><version>5.2.4</version>
</plugin>
参考:
Flyway官网 https://flywaydb.org/documentation/
Flyway 数据库脚本版本控制工具相关推荐
- flyway数据库版本控制
一.Flyway简介 Flyway是一款数据库迁移(migration)工具.简单点说,就是在你部署应用的时候,帮你执行数据库脚本的工具.Flyway支持SQL和Java两种类型的脚本,你可以将脚本打 ...
- sql脚本对比工具_Java开发中用到的数据库迁移工具(flyway)
什么是数据库版本管理? 任何web软件和应用程序都需要强大的数据库管理工具,因此开发者选择一款合适的数据库管理工具尤为重要.本文列出了几款好用的数据库管理工具(有些并非开源或免费),以供开发者们参考选 ...
- flyway版本号_Flyway版本化管理数据库脚本
假如我们有一个叫shiny的项目,它是由一个程序Shiny-Server 和一个数据库 Shiny-DB组成的; 简单结构图如下: image.png 但是很多时候,现实开发团队是这样的: image ...
- 数据库版本控制工具介绍
Source Safe for SQL Server 网址:http://www.grqsh.com/products.htm?tab=sourcesafe-for-sql-server Source ...
- 数据库文档生成数据库脚本工具
数据库文档生成数据库脚本工具,txt->sql word文档: ---------------------------------------------------------- 图一 复制到 ...
- CYQ.DBImport 数据库反向工程及批量导数据库工具 V2.0 发布[增加批量导出数据库脚本及数据库设计文档]...
上次发布的:CYQ.DBImport V1.0的相关介绍:CYQ.DBImport 数据库反向工程及批量导数据库工具 V1.0 本次发布的V2.0 版本,准备突击海外,下面为相关的介绍. 一:新版本2 ...
- 【SQL管理】-Flyway数据库版本管理利器从入门到入味
Flyway是什么? Flyway是独立于数据库的应用.管理并跟踪数据库变更的数据库版本管理工具.用通俗的讲,Flyway可以像Git管理不同人的代码那样,管理不同人的sql脚本,整个过程自动化,可回 ...
- Flyway数据库迭代升级迁移
Flyway简介 Flyway 是一款开源的数据库版本管理工具.它可以很方便的在命令行中使用,或者在Java应用程序中引入,用于管理我们的数据库版本. 在项目或产品中,很难一开始就把业务理清楚,把数据 ...
- mysql数据库version版本控制_MySQL数据库版本控制
你用什么方法来控制你的数据库?我已经将所有数据库表作为单独的.sql脚本提交到我们的respository(mercurial).这样,如果团队中的任何成员对employee表进行了更改,比如说,当我 ...
最新文章
- oracle oats 安装,Mentor完整培训教程.pdf
- Anaconda闪退问题
- kafka 修改分区_kafka修改分区和副本数
- 很棒的远程执行工具psexec的用法
- C++俄罗斯方块(linux环境)-转 感觉非常好
- 蓝牙nrf52832的架构和开发(转载)
- mysql多库备份_Mysql 之多库备份
- 微信发朋友圈功能测试点小结
- 猜价格游戏c语言课程设计,肿么用C#编写一个猜价格的小程序?
- 饥荒插件制作应注意的几个问题
- SpringCloud学习笔记(一)(狂神视频笔记)
- C++:构造函数以及析构函数
- 网络安全系列-VI: 网络安全大数据分析的粗浅认识
- 使用电子邮件营销可以更快速推广餐厅
- 博通Broadcom SDK源码学习与开发12终结篇——TR069网管协议
- RocketMQ吐血整理
- 黑马程序员_常见异常
- php拼接循环拼接字符串数组,PHP数组拼接
- QT小项目Demo【附功能图及源码】
- Vim编辑器实用指令
热门文章
- 用python和sympy库解决方程组问题_Python语言 SymPy库数学方程问题——线性方程组篇...
- linux命令fsck和fcsk,在ubuntu中shutdown和reboot的各参数的作用是什么? | 星尘
- CAPS BHCA
- 产品质量不过关怎么办?一招帮你大幅提高生产质量
- Linux 抓包工具:tcpdump
- SPASVO 软件生命周期管理 ALM V2.1 正式发布!
- Swift -- 7.3 类和结构体
- Solr的学习使用之(三)IKAnalyzer中文分词器的配置
- 招聘 | 深圳人工智能与机器人研究院 扩展现实研究中心
- 亚马逊开源模型设计神器:AutoGluon,三行代码自动生成SOTA模型!