实战:MyBatis适配多种数据库:MySQL、Oracle、PostGresql等
概叙
很多时候,一套代码要适配多种数据库,主流的三种库:MySQL、Oracle、PostGresql,刚好mybatis支持这种扩展,如下图所示,在一个“namespace”,判断唯一的标志是id+databaseId,刚好写了三个同样的方法,一个不带databaseId,两个带databaseId,此时当前库如果连接的是oracle则执行databaseId=’oracle‘的方法,如果连接的是MySQL则执行databaseId=’mysql‘的方法。不带databaseId的方法,只有在不写databaseId的方法且唯一只有一个不带databaseId方式时才会被执行。
不足:本文中mybatis虽然可以适配多种类型的数据库,但是启动后,只支持一种库;即要么连接oracle,要么连接MySQL,不能同时连接和操作两种库。
思考:如何改进不足,同时支持操作多种库?如果用原生的jdbc很好解决,但是我们用的是mybatis框架,如何让mybatis支持同时操作多种数据库?(动态数据源,其实和jdbc一样,系统启动时,就要初始化好多种库的连接,然后动态切换;具体实现,大家可以自行试试)
详细的我们接着往后看
一、启用数据库识别DatabaseIdProvider
1. 调查数据库产品名
要想做兼容多种数据库,那毫无疑问,我们首先得明确我们要兼容哪些数据库,他们的数据库产品名称是什么。得益于SPI设计,java语言制定了一个java.sql.DatabaseMetaData接口(jdbc接口),要求各个数据库的驱动都必须提供自己的产品名。因此我们如果想要兼容某数据库,只要在对应的驱动包中找到其对DatabaseMetaData
的实现即可。
比如Mysql的驱动包mysql-connector-java下的DatabaseMetaData
Oracle 的驱动包com.oracle.ojdbc6下的OracleDatabaseMetaData
DatabaseMetaData接口是由JDBC驱动程序实现的,用于提供底层数据源相关的信息。该接口主要用于为应用程序或工具确定如何与底层数据源交互。应用程序也可以使用DatabaseMetaData接口提供的方法获取数据源信息。
DatabaseMetaData接口中包含超过150个方法,根据这些方法的类型可以分为以下几类:
(1)获取数据源信息。
(2)确定数据源是否支持某一特性或功能。
(3)获取数据源的限制。
(4)确定数据源包含哪些SQL对象以及这些对象的属性。
(5)获取数据源对事务的支持。
创建DatabaseMetaData对象
DatabaseMetaData对象的创建比较简单,需要依赖Connection对象。Connection对象中提供了一个getMetadata()方法,用于创建DatabaseMetaData对象。
一旦创建了DatabaseMetaData对象,我们就可以通过该对象动态地获取数据源相关的信息了。下面是创建DatabaseMetaData对象并使用该对象获取数据库表名允许的最大字符数的案例,代码如下:
Connection connection = DriverManager.getConnection("jdbc:mysql://XXXX/demo","XXXX","XXXX");
DatabaseMetaData dmd = connection.getMetaData();
获取数据源的基本信息
//获取数据源的基本信息System.out.println("数据库URL:" + dmd.getURL());System.out.println("数据库用户名:" + dmd.getUserName());System.out.println("数据库产品名:" + dmd.getDatabaseProductName());System.out.println("数据库产品版本:" + dmd.getDatabaseProductVersion());System.out.println("驱动主版本:" + dmd.getDriverMajorVersion());System.out.println("驱动副版本:" + dmd.getDriverMinorVersion());System.out.println("数据库供应商用于schema的首选术语:" + dmd.getSchemaTerm());System.out.println("数据库供应商用于catalog的首选术语:" + dmd.getCatalogTerm());System.out.println("数据库供应商用于procedure的首选术语:" + dmd.getProcedureTerm());System.out.println("null值是否高排序:" + dmd.nullsAreSortedHigh());System.out.println("null值是否低排序:" + dmd.nullsAreSortedLow());System.out.println("数据库是否将表存储在本地文件中:" + dmd.usesLocalFiles());System.out.println("数据库是否为每个表使用一个文件:" + dmd.usesLocalFilePerTable());System.out.println("数据库SQL关键字:" + dmd.getSQLKeywords());
**注意:**由于HSQLDB驱动对DatabaseMetaData接口的getSQLKeywords()方法没有任何实现逻辑,只返回一个空字符串,因此上面的代码获取数据库SQL关键字内容为空。
获取数据源支持特性
DatabaseMetaData接口中提供了大量的方法用于确定数据源是否支持某个或一组特定的特性。除此之外,有些方法用于描述数据源对某一特性的支持级别。
获取数据源限制
获取SQL对象及属性
获取SQL对象及属性
2. 启用databaseId
既然各个驱动都提供了产品名,那么接下来就是让项目在启动中能够识别这些数据库,并赋予以不同数据库不同的id。MyBatis
其实有这项功能,但是这个功能默认没有被启用,若要启用我们首先得建立一个配置,即databaseIdProvider
,可以在配置类里面加上这个Bean来实现
@Beanpublic DatabaseIdProvider databaseIdProvider() throws SQLException {DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();Properties properties = new Properties();// Key值(即产品名)来源于数据库,需要提前查清楚 ,// value值(即databaseId)可以随便填,你填“1” "2" "3"也行,但建议有明确意义,像下面这样properties.setProperty("0racle", "oracle");properties.setProperty("MySQL", "mysql");properties.setProperty("DB2", "db2");properties.setProperty("Derby", "derby");properties.setProperty("H2", "h2");properties.setProperty("HSQL", "hsql");properties.setProperty("Informix", "informix");properties.setProperty("MS-SQL", "ms-sql");properties.setProperty("PostgresqL", "racle");properties.setProperty("sybase", "sybase");properties.setProperty("Hana", "hana");databaseIdProvider.setProperties(properties);return databaseIdProvider;}@Beanpublic SqlSessionFactory testdbSqlSessionFactory(@Qualifier("testdbDataSource") DataSource testdbDataSource)throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(testdbDataSource);//set 注入databaseIdProvider 到当前SqlSessionFactoryBean sessionFactory.setDatabaseIdProvider(databaseIdProvider()); sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(TestDbDataSourceConfig.MAPPER_LOCATION));return sessionFactory.getObject();}
完成了上述配置后,我们的项目就能主动去识别数据库类型了。
二、SQL语法鉴别
对于大部分SQL,因为有SQL规范的限制,它们通常是通用的,一段SQL可以在不同的数据库上跑。但是对于部分复杂SQL,就得针对不同数据库,来写不同的SQL了,我们以Mysql 、 Oracle 为例,看一些常见功能的语法差异
1. 分页查询
MySQL中使用LIMIT
关键字来实现分页查询,例如:
1
SELECT
*
FROM
table_name LIMIT offset,
count``;
而Oracle中使用ROWNUM
关键字来实现分页查询,例如:
1
2
3
4
5
SELECT
*
FROM
(``SELECT
t.*, ROWNUM
AS
rn
??????``FROM
table_name t
??????``WHERE
ROWNUM <= offset +
count``)
WHERE
rn > offset;
2. 获取当前时间
MySQL中可以使用NOW()函数来获取当前时间,例如:
1
SELECT
NOW();
而Oracle中可以使用SYSDATE关键字来获取当前时间,例如:
1
SELECT
SYSDATE
FROM
DUAL;
3. 获取自增主键的值
MySQL中可以使用LAST_INSERT_ID()函数来获取最后插入行的自动生成的主键值,例如:
1
2
INSERT
INTO
table_name (column1, column2)
VALUES``(value1, value2);
SELECT
LAST_INSERT_ID();
而Oracle中可以使用SEQUENCE和CURRVAL来获取自增主键的值,例如:
1
2
INSERT
INTO
table_name (column1, column2)
VALUES``(seq.nextval, value2);
SELECT
seq.currval
from
dual;
4. 转换数据类型
MySQL 使用 CAST() 或 CONVERT() 函数转换数据类型,例如:
1
2
3
SELECT
CAST``(``'123'
AS
SIGNED)
AS
converted_value;?
-- 或者?
SELECT
CONVERT``(``'123'``, SIGNED)
AS
converted_value;
而Oracle使用 TO_NUMBER(), TO_CHAR(), TO_DATE() 等函数进行数据类型转换,例如:
1
2
INSERT
INTO
table_name (column1, column2)
VALUES``(seq.nextval, value2);
SELECT
seq.currval
from
dual;
5. 字符串拼接
MySQL中可以使用CONCAT()函数来进行字符串拼接,例如:
1
SELECT
CONCAT(column1, column2)
FROM
table_name;
而Oracle中可以使用||运算符来进行字符串拼接,例如:
1
SELECT
column1 || column2
FROM
table_name;
6. 字符串截取
MySQL 使用 SUBSTRING() 函数,例如:
1
SELECT
SUBSTRING``(``'Hello World'``, 1, 5)
AS
substring_result;
而Oracle 使用 SUBSTR() 函数,例如:
1
SELECT
SUBSTR(``'Hello World'``, 1, 5)
AS
substring_result
FROM
DUAL;
7. 判空函数
MySQL中可以使用IFNULL()函数来进行字符串拼接,例如:
1
SELECT
IFNULL(column1,
"1"``)
FROM
table_name;
而Oracle中可以使用NVL()来进行字符串拼接,例如:
1
SELECT
NVL(column1,
"1"``)
FROM
table_name;
8. 正则表达式
MySQL 使用 REGEXP 或 RLIKE 进行正则表达式匹配,例如:
1
SELECT
'Hello World'
REGEXP
'^Hello'
AS
is_matched;
而Oracle 使用 REGEXP_LIKE, REGEXP_INSTR, REGEXP_SUBSTR, 和 REGEXP_REPLACE 等函数,例如:
1
SELECT
CASE
WHEN
REGEXP_LIKE(``'Hello World'``,
'^Hello'``)
THEN
'Matched'
ELSE
'Not Matched'
END
AS
is_matched
FROM
DUAL;
9. 窗口函数
MySQL 低版本不支持窗口函数,可以使用自连接模拟窗口函数,例如:
1
2
3
4
5
SELECT
t1.*
FROM
table_name t1
LEFT
JOIN
table_name t2
ON
t1.column_name = t2.column_name
AND
t1.order_column > t2.order_column
WHERE
t2.column_name
IS
NULL``;
而Oracle 或 MySQL高版本则可以 使用 窗口函数,例如:
1
2
3
4
SELECT
*
FROM
(``SELECT
*, ROW_NUMBER() OVER (PARTITION
BY
column_name
ORDER
BY
order_column)
as
rn
??????``FROM
table_name)
as
t
WHERE
rn = 1;
三、SQL兼容处理
如果我们的项目有SQL语法不兼容的情况,如上面那些场景,那么我们就需要对这些SQL做特殊处理了,比如一个常用的功能,获取当前数据库时间。我们需要在同一个XML文件中写两份,注意两份SQL的databaseId
是不同的,而不同数据库的databaseId
是什么,则依赖我们最开始维护的databaseIdProvider?
里的value值了
1
2
3
4
5
6
7
8
9
10
11
12
<``select
id =
"getSysDateTime"
databaseId=``"oracle"``>
????``select
????????????``TO_CHAR (sysdate,
'yyyyMMdd'``) sys_date,
????????????``TO_CHAR (sysdate,
'HH24miss'``) sys_time
????``from
dual
</``select``>
<``select
id =
"getSysDateTime"
databaseId=``"mysql"``>
????``select
????????????``date_format (now(),
'%Y%m%d'``) sys_date,
????????????``date_format (now(),
'%H%i%s'``) sys_time
????``from
dual
</``select``>
而一些可以跑在所有平台的SQL,则不需要改造,即databaseId
不要填,如
1
2
3
4
<``select
id =
"getUserInfo"
resultType =
"UserInfo"``>
????``select
user_name, user_age
????``from
USERINFO
</``select``>
四、运行原理
做完上述步骤后,我们的项目就能在多种数据库环境运行了,而其内部原理,其实也非常简答
1. 配置载入
在项目启动的时候,MyBatis 需要创建会话工厂,其中就有如下代码,他的意义很明确,就是找到当前连接的数据库,对应的是什么databaseId
。并且将这个值保存进配置中。
1
2
3
4
5
6
7
8
9
10
11
12
// SqlSessionFactoryBean
protected
SqlSessionFactory buildSqlSessionFactory()
throws
Exception {
????``// 省略无关代码
????``if
(``this``.databaseIdProvider !=
null``) {
??????``try
{
????????``targetConfiguration.setDatabaseId(``this``.databaseIdProvider.getDatabaseId(``this``.dataSource));
??????``}
catch
(SQLException e) {
????????``throw
new
NestedIOException(``"Failed getting a databaseId"``, e);
??????``}
????``}
????``// 省略无关代码
}
2. SQL选择
我们在Mybatis之动态SQL使用小结(全网最新)?中介绍过MyBatis的启动流程,其中就有对xml文件的解析,而我们现在在一个xml中写了多个id相同的SQL,MyBatis会怎么做呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// XMLMapperBuilder
??``private void buildStatementFromContext(List<``XNode``> list) {
????``// 如果当前环境有DatabaseId,则以这个DatabaseId去加载对应的SQL
????``if (configuration.getDatabaseId() != null) {
??????``buildStatementFromContext(list, configuration.getDatabaseId());
????``}
????``// 兜底,把某些没有指明DatabaseId的SQL加载进来
????``buildStatementFromContext(list, null);
??``}
??``private void buildStatementFromContext(List<``XNode``> list, String requiredDatabaseId) {
????``for (XNode context : list) {
??????``final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
??????``try {
????????``statementParser.parseStatementNode();
??????``} catch (IncompleteElementException e) {
????????``configuration.addIncompleteStatement(statementParser);
??????``}
????``}
??``}
可以看到对于一个XML文件的解析,会先后以指定databaseId 和无指定databaseId 两种情况去解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// XMLStatementBuilder
??``public
void
parseStatementNode() {
????``String id = context.getStringAttribute(``"id"``);
????``String databaseId = context.getStringAttribute(``"databaseId"``);
????``if
(!databaseIdMatchesCurrent(id, databaseId,
this``.requiredDatabaseId)) {
??????``return``;
????``}
????``// 省略无关代码
}
??``private
boolean
databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
????``if
(requiredDatabaseId !=
null``) {
??????``return
requiredDatabaseId.equals(databaseId);
????``}
????``if
(databaseId !=
null``) {
??????``return
false``;
????``}
????``id = builderAssistant.applyCurrentNamespace(id,
false``);
????``if
(!``this``.configuration.hasStatement(id,
false``)) {
??????``return
true``;
????``}
????``// skip this statement if there is a previous one with a not null databaseId
????``MappedStatement previous =
this``.configuration.getMappedStatement(id,
false``);
// issue #2
????``return
previous.getDatabaseId() ==
null``;
??``}
可以看到,在读取每一段SQL块的时候,会判断SQL上标注的databaseId
是否符合当前数据库环境,只有符合的才会被解析。
五、坑点
1. 避免歧义
不难发现,因为兜底逻辑的存在,有时可能会存在歧义,假设我们在mysql环境,我们写下这样的代码,是不是会把两段都解析掉?
1
2
3
4
5
6
7
8
9
10
11
12
<select id = "getSysDateTime" databaseId="mysql">
????``select
????????????``date_format (now(), '%Y%m%d') sys_date,
????????????``date_format (now(), '%H%i%s') sys_time
????``from dual
</select>
<select id = "getSysDateTime">
????``select
????????????``TO_CHAR (sysdate, 'yyyyMMdd') sys_date,
????????????``TO_CHAR (sysdate, 'HH24miss') sys_time
????``from dual
</select>
其实是不会的,因为在解析完后我们会把解析的结果存入一个map中,它的key值就是每一块的id
,因为这个map是个内部定义的StrictMap
,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
@SuppressWarnings``(``"unchecked"``)
public
V put(String key, V value) {
??``if
(containsKey(key)) {
????``throw
new
IllegalArgumentException(name +
" already contains value for "
+ key
????????``+ (conflictMessageProducer ==
null
?
""
: conflictMessageProducer.apply(``super``.get(key), value)));
??``}
??``if
(key.contains(``"."``)) {
????``final
String shortKey = getShortName(key);
????``if
(``super``.get(shortKey) ==
null``) {
??????``super``.put(shortKey, value);
????``}
else
{
??????``super``.put(shortKey, (V)
new
Ambiguity(shortKey));
????``}
??``}
??``return
super``.put(key, value);
}
不难发现,一旦有两个id冲突(同一个命名空间下)直接就会报错,所以我们要知道,每一个id实际上只会被存储一次,我们应尽量避免出现歧义的写法
2. 复杂数据库场景
对于大部分场景,按照上面的做法就能解决,但是仍有部分场景是需要特殊处理的,比如同一个数据库的不同版本。
比如说都属于 MySQL 族,但是 MySQL 下又分 5.7 或 8.0,有些语法在低版本上不支持,又或者与Percona 和 Maria-db 等不兼容
此时就需要使用通用性SQL来写了,一般都是顺着低版本来写,但往往也是性能最差的写法。
Mybatis 类型映射
Mybatis 类型处理器映射关系图
这里列出一些默认的类型处理器处理JAVA与JDBC数据类型的映射关系图:
mybatis jdbcType与PostGreSQL数据类型对应表
mybatis jdbcType与Oracle mysql数据类型对应表
Mybatis
JdbcType
Oracle
MySql
JdbcType
ARRAY
JdbcType
BIGINT
BIGINT
JdbcType
BINARY
JdbcType
BIT
BIT
JdbcType
BLOB
BLOB
BLOB
JdbcType
BOOLEAN
JdbcType
CHAR
CHAR
CHAR
JdbcType
CLOB
CLOB
CLOB
JdbcType
CURSOR
JdbcType
DATE
DATE
DATE
JdbcType
DECIMAL
DECIMAL
DECIMAL
JdbcType
DOUBLE
NUMBER
DOUBLE
JdbcType
FLOAT
FLOAT
FLOAT
JdbcType
INTEGER
INTEGER
INTEGER
JdbcType
LONGVARBINARY
JdbcType
LONGVARCHAR
LONG VARCHAR
JdbcType
NCHAR
NCHAR
JdbcType
NCLOB
NCLOB
JdbcType
NULL
JdbcType
NUMERIC
NUMERIC/NUMBER
NUMERIC/
JdbcType
NVARCHAR
JdbcType
OTHER
JdbcType
REAL
REAL
REAL
JdbcType
SMALLINT
SMALLINT
SMALLINT
JdbcType
STRUCT
JdbcType
TIME
TIME
JdbcType
TIMESTAMP
TIMESTAMP
TIMESTAMP
JdbcType
TINYINT
TINYINT
JdbcType
UNDEFINED
JdbcType
VARBINARY
JdbcType
VARCHAR
VARCHAR
VARCHAR
mybatis的jdbcType中部分没有对应的oracle和mysql的数据类型中,后续碰到再具体分析。
更新日志
Mysql中没有CLOB类型
相关文章:
实战:MyBatis适配多种数据库:MySQL、Oracle、PostGresql等
概叙 很多时候,一套代码要适配多种数据库,主流的三种库:MySQL、Oracle、PostGresql,刚好mybatis支持这种扩展,如下图所示,在一个“namespace”,判断唯一的标志是iddatabaseId,刚好写…...
2024年天津市职业院校技能大赛高职组 “信息安全管理与评估”样题第三阶段
(四)第三阶段竞小组(赛项)目(300分) 第三阶段竞赛内容是:网络安全渗透(夺旗挑战赛CTF) 本模块要求参赛者作为攻击方,运用所学的信息收集、漏洞发现、漏洞利用等渗透测试技…...
游戏引擎学习第36天
仓库 :https://gitee.com/mrxiao_com/2d_game 回顾之前的内容 在这个程序中,目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎,这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中࿰…...
数仓技术hive与oracle对比(一)
准备 包括软硬件环境、数据、测试数据三方面的准备内容。 环境 虚拟机软件virtualbox7,同样的虚拟机配置:内存2G、cpu一核,物理主机同一台macbookpro(13-2020款),所以硬盘IO读写速度一致。 综上&#x…...
LeetCode题集-5 - 最长回文子串(一)
题目:给你一个字符串 s,找到 s 中最长的回文子串。 这一题作为中等难度,常规解法对于大多数人应该都没有难度。但是其中也有超难的解决办法,下面我们就一起由易到难,循序渐进地来解这道题。 01、暴力破解法 对于大多…...
A3026 Java+jsp+servlet+mysql高校学生请假管理系统
高校学生请假管理系统 1.摘要2. 绪论3.功能结构4.界面展示5.源码获取 1.摘要 高校学生请假管理系统 摘要:随着计算机的发展与不断进步,各个领域都出现了新的技术,曾经各种规模之间的竞争已经发展成为技术之间的竞争,管理和人才之…...
LDO低压差线性稳压器
1. 简介 LDO 是 “Low Dropout Regulator” 的缩写,中文称为“低压差线性稳压器”。LDO 稳压器是一种用于电压调节的电子设备,它的主要特点是输出电压和输入电压之间的压差非常低。这种特性使得 LDO 在许多应用场景中非常有用,特别是在需要高…...
Angular由一个bug说起之十一:排序之后无法展开 Row
问题现象 在使用 Material Table 时,排序功能触发了一个奇怪的 Bug:表格的 Row 无法展开。最终排查发现,问题的根源在于 trackBy 的错误使用。trackBy 方法接受两个参数:index(数据索引)和 row(…...
wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法
在遇到各种系统文件错误当中,其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上,特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件,它负责处理Windows无线网络服务的许多功能。…...
redis安装和使用教程【保姆级】
1.下载 通过网盘分享的文件:redis 链接: https://pan.baidu.com/s/1Tu1KZkf33YJFdul8s6SzqQ?pwd8888 提取码: 8888 2.启动 进入根目录,使用redis-server redis.windows.conf命令启行启动Redis服务, 如下图所示为启动成功,默认…...
Github 2024-12-01 开源项目月报 Top20
根据Github Trendings的统计,本月(2024-12-01统计)共有20个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10TypeScript项目9Go项目2HTML项目1Shell项目1Jupyter Notebook项目1屏幕截图转代码应用 创建周期:114 天开发语言:TypeScript, Py…...
C总结(C语言知识点,深化重难点)
C语言 1.使用C语言的7个步骤2.ASCII码3.提高程序可读性的机巧4.如何使用多种整形5.打印多种整形6.课移植类型:stdint.h和inttypes.h7.浮点数常量8.浮点值的上溢和下溢9.使用数据类型11.常量和C预处理器12.转换说明的意义12.1转换不匹配13.副作用和序列点14.数组简介…...
[Collection与数据结构] 位图与布隆过滤器
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
Redis与缓存
目录 缓存 缓存优缺点 缓存更新策略 超时剔除 先删缓存再更新数据库 旁路缓存(先更新数据库,再删缓存) 先更新数据库,再更新缓存 读写穿透 编辑 异步缓存写入模式 缓存常见问题 缓存穿透 缓存雪崩 缓存击穿 缓存 在业务开发…...
Ubuntu Linux 文件、目录权限问题(五)
本文为Ubuntu Linux操作系统- 第五弹 此文是在上期文件目录的内容操作基础上接着讲权限问题 上期回顾:Ubuntu Linux 目录和文件的内容操作 文件访问者身份与文件访问权限 Linux文件结构 所有者(属主)所属组(属组)其他…...
AI 名人堂:Jeff Dean
Jeff Dean,谷歌的高级研究员和人工智能领域的领军人物,以其在大规模分布式计算系统和人工智能系统的杰出贡献而闻名。 谷歌AI掌门人 TensorFlow项目负责人 美国工程院院士 2AGI.NET AI 名人堂 AI 名人堂:Jeff DeanAI 名人堂:Je…...
基础排序算法详解:冒泡排序、选择排序与插入排序
引言 上一章,我们聊到了排序的基本概念和常见算法的分类。这一次,我们从基础开始,深入剖析三种常见的O(n) 排序算法:冒泡排序、选择排序 和 插入排序。 它们是学习排序算法的入门神器,不仅实现简单,还能帮…...
Flink如何基于数据版本使用最新离线数据
业务场景 假设批量有一张商户表,表字段中有商户名称和商户分类两个字段。 批量需要将最新的商户名称和分类的映射关系推到hbase供实时使用。 原实现方案 a.原方案内容 为解决批量晚批问题,批量推送hbase表时一份数据产生两类rowkey:T-1和…...
什么是反向代理?作用、原理和实例详解
🚀 什么是反向代理?作用、原理和实例详解 在现代的网络架构中,反向代理(Reverse Proxy)无处不在。无论是负载均衡、加速缓存,还是WebSocket 支持,反向代理都是必不可少的工具。 这篇文章将带您…...
国产GPU中,VLLM0.5.0发布Qwen2.5-14B-Instruct-GPTQ-Int8模型,请求返回结果乱码
概述 国产GPU: DCU Z100 推理框架: vllm0.5.0 docker容器化部署 运行如下代码: python -m vllm.entrypoints.openai.api_server --model /app/models/Qwen2.5-14B-Instruct-GPTQ-Int8 --served-model-name qwen-gptq --trust-remote-code --enforce…...
Stable Diffusion本地部署:从零开始的完整指南
1、引言 Stable Diffusion是计算机视觉领域的一个生成式大模型,能够进行文生图(txt2img)和图生图(img2img)等图像生成任务。它利用深度学习技术,特别是RealisticVision v2.0模型,能够创造出接近…...
隐式神经网络实现低光照图像增强
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
Flutter动画(三)内建显式动画Widget
常见的内建显式动画Widget: ListenableBuilder: AnimatedBuilder AnimatedWidget AlignTransition DecoratedBoxTransition DefaultTextStyleTransition PositionedTransition RelativePositionedTransition RotationTransition ScaleTransiti…...
springSecurity自定义登陆接口和JWT认证过滤器
下面我会根据该流程图去自定义接口: 我们需要做的任务有: 登陆:1、通过ProviderManager的方法进行认证,生成jwt;2、把用户信息存入redis;3、自定义UserDetailsService实现到数据库查询数据的方法。 校验&a…...
Spring Boot日志:从Logger到@Slf4j的探秘
写在前面 Hello大家好,今日是2024年的第一天,祝大家元旦快乐?? 2024第一篇文章从SpringBoot日志开始 文章目录 一、前言二、日志有什么用?三、日志怎么用?四、自定义日志打印 ?? 常见日志框架说明4.1 在程序中得到?志对象【…...
使用 LabVIEW 与 PLC 通信的方式
要将 PLC 与 LabVIEW 或其他 NI 产品进行通信,首先需要明确 PLC 支持的通信协议和接口类型。NI 提供了多种方案,包括 OPC 服务器、Modbus、Ethernet/IP 和其他工业通信协议。下面将详细介绍这些方法,并进行比较分析,帮助你选择最适…...
python录制鼠标键盘操作循环播放
依赖 pip install pynput 程序: from pynput import mouse, keyboard import time import threading# 用于存储录制的鼠标和键盘事件 mouse_events [] keyboard_events []# 定义事件处理函数# 处理鼠标事件 def on_move(x, y):mouse_events.append((move, x, y))def on_cl…...
开发者如何使用GCC提升开发效率Opencv操作
看此篇前请先阅读 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144216351?spm=1001…...
异常与文件
目录 1.异常 1.1.概念 1.2.常见异常 1.3.异常处理方式 1.3.1.try except 1.3.2.try except else 1.3.3.try except else finally 2.文件 2.1.文件分类 ps:python 程序的数据保存在哪里? 2.2.常见的文件类型 2.3.python 操作文件的函数 2.3.1.读取文件…...
【C语言】完成程序设计填空
文章目录 1、请阅读下面的程序,在空白处填写正确的代码,要求各在一行从头开始输出m和n的值。2、求100~599之间的所有水仙花数,即各位数字的立方和恰好等于该数本身的数。3、以下程序的功能是:将值为三位正整数的变量x中的数值按照个位、十位、百位的顺序 拆分并输出。请填空…...
西湖大学:LLM零样本推理任务校准
📖标题:Task Calibration: Calibrating Large Language Models on Inference Tasks 🌐来源:arXiv, 2410.18764 🌟摘要 🔸大型语言模型(LLM)在推理任务上表现出令人印象深刻的零样本…...
windows下Qt5自动编译配置QtMqtt环境(11)
文章目录 [toc]1、概述2、准备1.1 下载源码1.2 配置环境1.3 解释原理 3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配…...
每天五分钟深度学习:神经网络的前向传播的计算(多样本)
本文重点 前面我们学习了单样本的前向传播,本文我们学习多样本的前向传播,我们先来回忆一下,神经网络的单样本的前向传播的向量化的方式: m个样本依次进行前向传播 这里我们说明一下符号: 我们使用(m)表示第m个样本,用[m]表示神经网络的第m层 a[2](i) 表示第i个样本计…...
基于 NXP S32K312+FS23 的汽车通用评估板方案
S32K3 系列是 NXP 推出的面向汽车电子和工业应用的微控制器,基于 ARMCortex-M7 内核,支持单核、双核和锁步内核配置。S32K3 系列具有内核、内存和外设数量方面的可扩展性,符合 ISO26262 标准,能达到 ASIL B/D 安全等级,…...
11进阶篇:专业课论文阅读方向指南(2025版)
文章目录 第一个检索式:图情档核心期刊(北大 + CSSCI)发文情况研究方法类关键词研究主题类关键词论文阅读建议第二个检索式:川大公共管理学院在核心期刊(北大 + CSSCI)的发文情况研究方法类关键词研究主题类关键词特点关键词与2024年972(现815)两道题目的映射情况815信…...
Qt之第三方库QXlsx使用(三)
Qt开发 系列文章 - QXlsx(三) 目录 前言 一、Qt开源库 二、QXlsx 1.QXlsx介绍 2.QXlsx下载 3.QXlsx移植 4.修改项目文件.pro 三、使用技巧 1.写入数据 2.读出数据 总结 前言 Qt第三方控件库是指非Qt官方提供的、用于扩展Qt应用程序功能的控件…...
第145场双周赛: 使数组的值全部为 K 的最少操作次数、破解锁的最少时间 Ⅰ、使两个整数相等的位数操作、统计最小公倍数图中的连通块数目
Q1、使数组的值全部为 K 的最少操作次数 1、题目描述 给你一个整数数组 nums 和一个整数 k 。 如果一个数组中所有 严格大于 h 的整数值都 相等 ,那么我们称整数 h 是 合法的 。 比方说,如果 nums [10, 8, 10, 8] ,那么 h 9 是一个 合法…...
AJAX三、XHR,基本使用,查询参数,数据提交,promise的三种状态,封装-简易axios-获取省份列表 / 获取地区列表 / 注册用户,天气预报
一、XMLHttpRequest基本使用 XMLHttpRequest(XHR)对象用于与服务器交互。 二、XMLHttpRequest-查询参数 语法: 用 & 符号分隔的键/值对列表 三、XMLHttpRequest-数据提交 核心步骤 : 1. 请求头 设置 Content-Type 2. 请求体 携带 符合要求 的数…...
Android期末复习题
1.如何搭建Android开发环境? 答案:搭建Android开发环境需要以下几个步骤: (1)下载和安装JDK (2)配置PATH环境变量 (3)下载和安装Android Studio (4)创建A…...
《蓝桥杯比赛规划》
一、比赛简介 蓝桥杯全国软件和信息技术专业人才大赛是一项具有较高影响力的编程竞赛,旨在促进软件和信息技术领域专业技术人才的培养,提升高校毕业生的就业竞争力。比赛涵盖了多个编程语言和专业方向,包括 C/C、Java、Python 等。 二、目标…...
三、Zookeeper
Zookeeper 三、Zookeeper3.1什么是zookeeper?3.2为什么需要zookeeper3.3Zookeeper基本运行流程3.4Zookeeper数据模型3.5Zookeeper主要角色3.6Zookeeper工作原理3.7Zookeeper节点数据操作流程三、Zookeeper 3.1什么是zookeeper? ZooKeeper是一个分布式的,开放源码的分布式应…...
Wireshark数据抓包分析之传输层协议(TCP协议)
根据实验环境,本实验的步骤如下: 1.在测试环境使用发包工具和Wireshark抓取TCP三次握手和四次断开的数据包。 2.详细分析TCP协议的三次握手以及四次断开。 任务描述:安装发包工具,并配置TCP客户端,服务端࿰…...
用ai做机器视觉的事情
cnn(卷积神经网络)是典型的ai算法。 我们已经cnn实现像机器视觉中形状匹配的功能,因为使用了roi抠图匹配,所以就叫做roicnn,以区分整图匹配。下面是roicnn笔记总结: 20241022,roicnn搞定&…...
LLM - 开源视觉多模态 LLaVA-CoT(o1) 深度推理模型 测试与源码 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144304351 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 LLaVA-…...
qtcanpool 知 10:包管理雏形
文章目录 前言痛点转机雏形实践后语 前言 曾听闻:C/Qt 没有包管理器,开发起来太不方便。这是一个有过 node.js 开发经验的人对 Qt 的吐槽。 确实,像 python、golang、node.js 这些编程语言都有包管理器,给用户带来了极佳的开发体…...
[保姆式教程]使用目标检测模型YOLO11 OBB进行旋转目标检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)
之前写了一个基于YOLOv8做旋转目标检测(OBB)的文章,内容写得不够好,内容也有些杂乱无序。现如今YOLO已经更新到11了,数据集也集齐了无人机和卫星的农业大棚,所以这次就写一个基于YOLO11 OBB的农业大棚旋转检…...
MySQL 权限管理分配详解
MySQL 权限管理分配详解 MySQL权限系统的工作原理权限表的存取用户通过权限认证、进行权限分配的流程账号管理我们常用的授权all privileges到底有哪些权限呢?以及带来的安全隐患有哪些?创建账户的时候最好分配指定的权限,这样子安全也高管理…...
【期末速成】《微机原理与接口技术》知识点总结
文章目录 前言第一、二章 接口技术概述1. 接口的定义*2. 接口功能特点*3. 接口的分类*4. 接口中的传输信息及其组成5. 接口的编址与译码*6. CPU 与外设之间的数据传送方式* 第三章 总线1. 总线(BUS)的定义*2. 总线的标准3. 采用标准总线的优点*4. 总线的…...
华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数
华为交换机WEB操作 使用的是真机S5735,目前主流的版本都适用(V1R5~V2R1的就不在列了,版本太老了,界面完全不一样,这里调试线接的console口,电脑的网络接在ETH口) 「模拟器、工具合集」复制整段内…...
【Elasticsearch】初始化默认字段及分词
1、添加分词插件 1)在线安装 执行命令 需要指定相同的版本 bin/elasticsearch-plugin.bat install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.24 2)离线安装 将安装包解压到 /plugins 目录下 安装包可以从对应的资源处下载 启动成…...