从Java的类型转换看MySQL和Oracle中的隐式转换(二)

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: 说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过MySQL和Oracle的数据类型转换情况,可以参见MySQL和Oracle中的隐式转换 http://blog.itpub.net/23718752/viewspace-1787973/ 不过当时写完之后,有个读者随口问了一句为什么,为什么呢?似乎自己还是一知半解,说是规则,无规矩不成方圆,倒也无可非议,不过我觉得还是要再看看,看看还能有哪些收获,接下来的内容我就不能保证正确性了,希望大家明辨,也希望提出意见,毕竟就是希望把问题搞明白而已。
说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过MySQL和Oracle的数据类型转换情况,可以参见MySQL和Oracle中的隐式转换 http://blog.itpub.net/23718752/viewspace-1787973/
不过当时写完之后,有个读者随口问了一句为什么,为什么呢?似乎自己还是一知半解,说是规则,无规矩不成方圆,倒也无可非议,不过我觉得还是要再看看,看看还能有哪些收获,接下来的内容我就不能保证正确性了,希望大家明辨,也希望提出意见,毕竟就是希望把问题搞明白而已。

首先开发语言中就有数据类型的隐式转换,这一点在java中尤为明显,毕竟一个承载了太多使命的语言如此庞大,又是强类型语言,数据类型的转换就是一个尤为重要的部分了。Java中的数据类型转换主要有下面的规则。
//转换规则:从存储范围小的类型到存储范围大的类型。
//具体规则为:byte→short(char)→int→long→float→double
自己也嘚瑟了一下,写了个简单的小程序以示明证,这个程序不能说明我会java.
public class Test {
public static void main(String args[]){
/*1*/    System.out.println("aa");
/*2*/    System.out.println('a');
/*3*/    byte a=10;
/*4*/      System.out.println(a);
/*5*/      char b='b';
/*6*/      int c=b;
/*7*/      System.out.println(b);
/*8*/      System.out.println(c);
    }
}
这个程序的输出为
aa
a
10
b
98

这样写的目的就是,
第1行,第2行中的单引号,双引号需要做的事情就是标示它是一个变量值,两者的效果在这个时候是一致的。
第3行初始化了一个byte变量,然后输出,这个时候还是byte
但是第5行声明了一个char型变量,然后在第6行中做了类型的隐式转换,在第7行中输出为字符b,但是在第8行输出为
通过这个简单的例子可以发现确实数据类型做了隐式转换,而且单引号,双引号在这个例子中的作用是一致的,就是标示变量。
因为在Java中查看数据类型的转换代价还是相对要困难一些,我们可以在数据库中来类比。
首先还是重复之前的测试,准备一批的数据。创建一个表,然后插入一些值。
create table test (id1 number,id2 varchar2(10));
 begin                   
    for i in 1..100 loop
    insert into test values(i,chr(39)||i||chr(39));
    end loop;
    commit;
    end;
    /
create index ind1_test on n1.test(id1);
create index ind2_test on n1.test(id2);
然后收集统计信息。
exec dbms_stats.gather_table_stats('TEST','TEST',CASCADE=>TRUE);
这个时候查看执行计划
explain plan for select *from test where id1='2';
SQL>   select *from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2759464289
-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     1 |    20 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST      |     1 |    20 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND1_TEST |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
-------------------------------------------------------------
   2 - access("ID1"=2)
通过这个确实可以看到谓词信息的部分     2 - access("ID1"=2) 已经自动做了转换,这个时候一个触发了一个索引扫描。
但是这个过程还是看不出有数据类型转换的痕迹,我们做一个看似有问题的例子,来触发一下。尽管id1位int型,但是使用字符型来触发。
SQL>    explain plan for select *from test where id1='A';
Explained.
SQL>   select *from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2759464289
-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     1 |    20 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST      |     1 |    20 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IND1_TEST |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------
   2 - access("ID1"=TO_NUMBER('A'))
可以看到谓词信息已经发生了变化。    2 - access("ID1"=TO_NUMBER('A'))从这个地方我们可以看到确实触发了一个to_number的操作。
而优化器在这个时候虽然触发了,但是在sql运行的时候,就会报出错误,这个时候可以看到Oracle还是蛮严谨的。
SQL> select *from test where id1='A';
select *from test where id1='A'
                            *
ERROR at line 1:
ORA-01722: invalid number
而如果使用双引号,生成执行计划都会抛错。
SQL> explain plan for select *from test where id1="A";
explain plan for select *from test where id1="A"
                                             *
ERROR at line 1:
ORA-00904: "A": invalid identifier
可见单引号和双引号在Oracle代表的含义还是有很大差别。

我们来看看在MySQL中的表现。
还是创建一个简单的表,插入一些数据。
> create table test (id1 int,id2 varchar(10));
> insert into test values(1,'1');
> insert into test values(2,'2');
> insert into test values(3,'3');
> commit;
> create index idx_id1 on test(id1);
> create index idx_id2 on test(id2);
这个时候生成执行计划,可以发现走了索引
> explain select * from test where id1='1';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
而如果查看id1为varchar的类型时,也走了索引。
> explain select * from test where id1='a';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
差别更大的就是如果使用id1='a',也能够正常执行,只是没有任何匹配的记录。
> select * from test where id1='a';
Empty set (0.00 sec)
而如果由单引号改为双引号,也能够正常运行。
> select * from test where id1="a";
Empty set (0.00 sec)
而且双引号的情况下,生成执行计划也没有问题。
> explain select * from test where id1="a";
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
可以看出在MySQL中这个时候的范围似乎更宽,在MySQL中不光用单引号,双引号,而且还经常会看到·这种符号。
这种在MySQL中可以灵活声明一些变化个,举个不太恰当的例子,比如我们创建一个表,一个字段为int,类型为int直接按照下面的方式来写,肯定抛错。
> create table test1(int int);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'int int)' at line 1
crea' at line 1
可以加上·,就可以识别了。
> create table test1(`int` int);
Query OK, 0 rows affected (0.00 sec)
这个对比的跨度有点大,但是通过一些小把戏似乎还是能够看出在这些类型的转换中,优化器这边的触发情况。再接再厉,继续探究。
相关实践学习
自建数据库迁移到云数据库
本场景将引导您将网站的自建数据库平滑迁移至云数据库RDS。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
8月前
|
安全 Java 编译器
Java类型提升与类型转换详解
本文详解Java中的类型提升与类型转换机制,涵盖类型提升规则、自动类型转换(隐式转换)和强制类型转换(显式转换)的使用场景与注意事项。内容包括类型提升在表达式运算中的作用、自动转换的类型兼容性规则,以及强制转换可能引发的数据丢失和运行时错误。同时提供多个代码示例,帮助理解byte、short、char等类型在运算时的自动提升行为,以及浮点数和整型之间的转换技巧。最后总结了类型转换的最佳实践,如避免不必要的转换、使用显式转换提高可读性、金融计算中使用BigDecimal等,帮助开发者写出更安全、高效的Java代码。
441 0
|
11月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
7月前
|
SQL Java 关系型数据库
Java连接MySQL数据库环境设置指南
请注意,在实际部署时应该避免将敏感信息(如用户名和密码)硬编码在源码文件里面;应该使用配置文件或者环境变量等更为安全可靠地方式管理这些信息。此外,在处理大量数据时考虑使用PreparedStatement而不是Statement可以提高性能并防止SQL注入攻击;同时也要注意正确处理异常情况,并且确保所有打开过得资源都被正确关闭释放掉以防止内存泄漏等问题发生。
316 13
|
存储 Java 关系型数据库
java调用mysql存储过程
在 Java 中调用 MySQL 存储过程主要借助 JDBC(Java Database Connectivity)。其核心原理是通过 JDBC 与 MySQL 建立连接,调用存储过程并处理结果。具体步骤包括:加载 JDBC 驱动、建立数据库连接、创建 CallableStatement 对象、设置存储过程参数并执行调用。此过程实现了 Java 程序与 MySQL 数据库的高效交互。
|
9月前
|
人工智能 Java 关系型数据库
Java的时间处理与Mysql的时间查询
本文总结了Java中时间与日历的常用操作,包括时间的转换、格式化、日期加减及比较,并介绍了MySQL中按天、周、月、季度和年进行时间范围查询的方法,适用于日常开发中的时间处理需求。
167 0
|
12月前
|
Oracle 关系型数据库 MySQL
Oracle linux 8 二进制安装 MySQL 8.4企业版
Oracle linux 8 二进制安装 MySQL 8.4企业版
518 1
|
SQL Oracle 关系型数据库
MySQL 和 Oracle 的区别?
本文对比了Oracle和MySQL数据库的多个方面。Oracle适用于大型数据库,支持高并发和大访问量,市场占有率为40%,安装占用空间较大,约3G;而MySQL适合中小型应用,是开源免费的,安装仅需152M。两者在主键生成、字符串处理、SQL语句、事务处理等方面存在差异。Oracle功能更为强大,尤其在企业级应用中表现突出,而MySQL则以简单易用见长。
1443 7
MySQL 和 Oracle 的区别?
|
Oracle 关系型数据库 MySQL
使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试
这篇文章是作者尚雷关于使用崖山YMP迁移Oracle/MySQL至YashanDB 23.2的验证测试分享。介绍了YMP的产品信息,包括架构、版本支持等,还详细阐述了外置库部署、YMP部署、访问YMP、数据源管理、任务管理(创建任务、迁移配置、离线迁移、校验初始化、一致性校验)及MySQL迁移的全过程。
|
SQL Oracle 关系型数据库
Oracle转Mysql总结
参考文档 从Oracle转到Mysql前需了解的50件事 MySQL与Oracle 差异比较之一 数据类型 MySQL与Oracle 差异比较之二 基本语法 MySQL与Oracle 差异比较之三 函数 MySQL与Oracle 差异比较之四 条件循环...
2052 0
|
SQL Oracle 关系型数据库
oracle转mysql总结(转)
ares-sdk初始开发测试使用的是oracle数据库,由于宁波通商的特殊需要,必须把数据库环境从oracle转向mysql。 现对转换过程中出现的问题及经验总结如下: 主键生成策略 创建一个专门记录序列的表sequence,记录有当前序列号,序列的间隔如+1 创建记录当前序列的表 DROP...
2244 0

热门文章

最新文章

推荐镜像

更多