MySQL字段类型和Java实体类型的转换问题

您所在的位置:网站首页 数据库double类型的字段怎么配置 MySQL字段类型和Java实体类型的转换问题

MySQL字段类型和Java实体类型的转换问题

2023-12-24 13:18| 来源: 网络整理| 查看: 265

1. MySQL的字段类型和Java类型的对应关系

MySQL Connector/J( MySQL官方JDBC驱动程序)在处理MySQL数据类型和Java数据类型之间的转换方面非常灵活。

通常,任何MySQL数据类型都可以转换为java.lang.String。 可以将字符串和任何数字类型转换为任何Java数字类型,尽管可能会发生舍入、溢出或精度损失。

从Connector/J 3.1.0开始,JDBC驱动程序会发出警告或引发JDBC规范所要求的DataTruncation异常(数据截断异常),除非通过使用jdbcCompliantTruncation属性并将其设置为false来将连接配置为不这样做。

MySQL和Java类型之间始终保证有效的转换

MySQL类型可转换的Java类型char, varchar, blob, text, enum, setjava.lang.String , java.io.InputStream, java.io.Reader,java.sql.Blob,java.sql.Clobfloat, real, double, precision, numeric, decimal , tinyint, smallint, mediumint, integer, bigintjava.lang.String , java.lang.Short, java.lang.Integer,java.lang.Long,java.lang.Double, java.math.BigDecimaldate, time, datetime, timestampjava.lang.String ,java.sql.Date, java.sql.Timestamp

注意 如果选择的Java数字数据类型的精度或容量低于要转换的MySQL数据类型,则可能会发生舍入、溢出或精度损失。

案例 image-20220719000520264

2. 二者的对应关系(仅仅是推荐) MySQL类型对应Java类型用途tinyint如果配置属性 tinyInt1isBit 设置为 true (默认)并且存储大小为1,则为 java.lang.Boolean,否则是 java.lang.Integer。intjava.lang.Integer, 如果是 unsigned 则是 java.lang.Longintegerjava.lang.Integer, 如果是 unsigned 则是 java.lang.Longbigintjava.lang.Long, 如果是 unsigned 则是 java.math.BigIntegerdoublejava.lang.Doublefloatjava.lang.Floatdecimaljava.math.BigDecimal金额numericJavacharjava.lang.String (除非列的字符集是BINARY,否则返回byte[]。)varcharjava.lang.String (除非列的字符集是BINARY,否则返回byte[]。)datejava.sql.Date日期timejava.sql.Time时间 HH:MM:SStimestampjava.sql.Timestamp时间戳 YYYY-MM-DD HH:MM:SSdatetimejava.sql.TimestampYYYY-MM-DD HH:MM:SSblobbyte[]textjava.lang.Stringlongtextjava.lang.Stringenumjava.lang.String

表格中的对应关系仅仅是推荐的,具体如何映射可以根据业务需求进行变更 ,并不是定死就这样,如:Mysql中字段类型是Decimal类型,在满足业务需求的情况下,可以在Java类型中可以使用Double在对应的数据接收。

3. Sql中decimal、float、double类型的区别与用法 3.1 三者的区别介绍

float:浮点型,含字节数为4,32bit,数值范围为-3.4E383.4E38(7个有效位) double:双精度实型,含字节数为8,64bit数值范围-1.7E3081.7E308(15个有效位) decimal:数字型,128bit,不存在精度损失,常用于银行帐目计算。(28个有效位)

3.2 decimal的详细介绍 定义

decimal(a,b)

参数说明 a 指定指定小数点左边和右边可以存储的十进制数字的最大个数,最大精度38。 b 指定小数点右边可以存储的十进制数字的最大个数。小数位数必须是从 0 到 a之间的值。默认小数位数是 0。 3.3 对比案例 float f = 345.98756f; --结果显示为345.9876,只显示7个有效位,对最后一位数四舍五入。 double d=345.975423578631442d; --结果显示为345.975423578631,只显示15个有效位,对最后一位四舍五入。 --注:float和double的相乘操作,数字溢出不会报错,会有精度的损失。 decimal dd=345.545454879..--可以支持28位,对最后一位四舍五入。 --:当对decimal类型进行操作时,数值会因溢出而报错。 4. Mybatis中JdbcType的作用

个人疑问的由来:今天在学习公司项目代码的时候惊奇的发现Mybatis中的映射类型和Java中的映射类型不一致,Mysql中设置的字段类型是Decimal类型,但是在Java中实体对应属性的数据类型缺选择使用的是Double作为对应,并且在查看代码的时候发现属性映射中有使用到JdbcType这个字段,一开始怀疑是JdbcType的作用,查阅了资料有了以下的答案

对于如下一条insert语句(这里只是做测试,实际中肯定不会这么写),如果我们的age传的空,那么对于mysql数据库可以正常插入,对于oracle数据库,会报错“无效的列类型”。

也就是说对于mysql数据库的插入来说,jdbcType是没用的,oracle数据库是有用的(值为null时有用)。

insert into test(id, name, age) values (7, #{name,jdbcType=VARCHAR},#{age})

我没有测试更新的情况,但是我猜测结论应该是一样的。**对于查询操作,在mybatis配置时也可以指定jdbcType,这里的jdbcType至少在我测试时也没发现有什么作用(mysql, oracle都是),**当然可能只是我没发现,不代表没有作用,不作为编码建议。

4.1 问题产生

insert操作时jdbcType的作用测试这里只分析insert操作时,为什么mysql和oracle表现会不同。

我们用如下代码来进行测试。

mybatis mapper中的sql如下,因为oracle自增主键比较麻烦,这里为了方便写死了id,仅测试用。

insert into t_user(id, name, age) values (7, #{name,jdbcType=VARCHAR}, #{age})

java测试代码如下,这里就不贴全部代码了,用过mybatis应该都能看懂。

User user = new User(); user.setName("zzj"); user.setAge(null); mapper.testJdbcType(user);

然后我们分别连接mysql和oracle

查看执行结果

mysql可以正常插入 但是oracle数据库会报如下错误(Error setting null for parameter #2 with JdbcType OTHER . java.sql.SQLException: 无效的列类型) img 4.2 原因分析

mybatis中的增删改查基本都是用PreparedStatement来实现的,PreparedStatement有个setNull方法 ,方法签名如下:

void setNull(int parameterIndex, int sqlType) throws SQLException;

当我们要插入的值是null时,mybatis就会调用PreparedStatement的setNull来设置对应的参数。

我们跟踪下mybatis执行过程,可以发现是在org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters这个方法中进行sql的参数设置。我们断点执行到这个方法,如下图 img

从上图可以发现,由于我们age参数没有设置jdbcType,JdbcType jdbcType = parameterMapping.getJdbcType(); ——> 这一行代码获取到的jdbcType为null,这时就会进入到if里,把jdbcType赋值为默认值,默认值是JdbcType.OTHER。 然后接着执行第87行typeHandler.setParameter(ps, i + 1, value, jdbcType); ——> 这一行就是对sql中的第二个参数进行设置,继续向下调试会发现 ——> 最终会调用PreparedStatement的setNull方法去设置null值,由于java.sql.PreparedStatement是个接口,具体怎么setNull,是由不同的数据库驱动程序去实现的。

我们先来看mysql的setNull方法,如下图。 img

可以看到,尽管第2个参数为sqlType,但是mysql实现中并没有用到这个参数,所以jdbcType的值对mysql是没有什么用的。

我们再来看oracle是如何实现setNull的

如下图,由于下载不到源码,所以oracle的代码看起来没那么直观,不过对于分析完全够用了。

img

img

从上图可以看出,oracle的setNull会调用setNullCritical,而setNullCritical中又会用jdbcType这个参数调用getInternalType ——> 这个方法内部是一长串的switch case判断,可以发现对于找不到的jdbcType,这个方法会抛出异常,这个异常就是上面我们做测试时的异常来源。 而我们知道,上面mybatis把jdbcType默认设置成了JdbcType.OTHER,这个值oracle是不支持的,所以报错了。 4.3 总结

有了上面的分析,我们就知道mybatis在插入数据时是怎么使用jdbcType的了,由此也可得出结论,对于插入操作,如果某个字段值为null,jdbcType的设置对mysql数据库没什么用,对oracle数据库有用。

资料来源

MySQL字段类型与Java实体类类型对应转换关系

mybatis jdbcType的作用,无效的列类型错误解决办法

mybatis jdbcType的作用,无效的列类型错误解决办法



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3