杰瑞科技汇

MySQL数据类型与Java如何对应?

  1. 核心类型映射表:最常用、最直接的对应关系。
  2. 详细说明与注意事项:对关键类型进行深入解释,特别是容易出错的地方。
  3. ORM 框架(如 MyBatis, JPA)的映射:现代开发中,我们通常使用框架,它们提供了更灵活的映射方式。
  4. 总结与最佳实践

核心类型映射表

这是一个快速参考表,涵盖了最常用的场景。

MySQL数据类型与Java如何对应?-图1
(图片来源网络,侵删)
MySQL 数据类型 Java 数据类型 (JDBC) Java 数据类型 (JPA / MyBatis) 备注
数值类型
TINYINT java.lang.Byte Byte, Integer TINYINT(1) 常用作布尔值,对应 java.lang.Boolean
SMALLINT java.lang.Short Short, Integer
INT, INTEGER java.lang.Integer Integer 最常用的整数类型
BIGINT java.lang.Long Long 用于主键、自增ID、时间戳等大数
FLOAT java.lang.Float Float 单精度浮点数,注意精度问题
DOUBLE java.lang.Double Double 双精度浮点数,比 FLOAT 精度高
DECIMAL java.math.BigDecimal BigDecimal 用于精确计算,如货币、财务数据。强烈推荐
字符串类型
CHAR java.lang.String String 定长字符串
VARCHAR java.lang.String String 变长字符串,最常用的文本类型
TEXT java.lang.String String, Lob 大文本,JPA 中常用 @Lob 注解,类型为 Stringbyte[]
日期时间类型
DATE java.sql.Date java.time.LocalDate 仅存储日期(年-月-日)
TIME java.sql.Time java.time.LocalTime 仅存储时间(时:分:秒)
DATETIME java.sql.Timestamp java.time.LocalDateTime 存储日期和时间(年-月-日 时:分:秒)
TIMESTAMP java.sql.Timestamp java.time.Instant, java.time.LocalDateTime 存储日期和时间,且受时区影响。TIMESTAMP 范围较小,但会自动转换时区
二进制类型
BLOB byte[] byte[], @Lob 二进制大对象,如图片、文件等,JPA 中用 @Lob 注解
BIT java.lang.Booleanbyte[] Boolean BIT(1) 对应 Boolean,多位 BIT 对应 byte[]

详细说明与注意事项

数值类型

  • TINYINT 和布尔值
    • 在 MySQL 中,TINYINT(1) 经常被用作布尔值,0 代表 false,非 0 代表 true
    • 在 Java 中,最自然的映射是 java.lang.Boolean,JPA 的 @Column(columnDefinition = "TINYINT(1)") 可以很好地处理这一点。
  • DECIMAL vs FLOAT/DOUBLE
    • 这是最常见也最容易出错的映射点。
    • FLOATDOUBLE 是浮点数,遵循 IEEE 754 标准,在计算机中是以二进制存储的,因此无法精确表示某些十进制小数。1 + 0.2 在浮点数计算中可能不等于 3
    • DECIMAL 是定点数,它以字符串形式存储数值,可以精确表示小数。所有涉及金钱、财务、科学计算等对精度要求高的场景,都必须使用 DECIMAL,并在 Java 中映射为 java.math.BigDecimal
    • 注意:在 JDBC 中,从 DECIMAL 读取数据时,使用 getBigDecimal() 方法,如果错误地使用 getDouble(),会丢失精度。

字符串类型

  • CHAR vs VARCHAR
    • CHAR 是定长,如果存入的字符串长度不足,会用空格补齐。VARCHAR 是变长,只存实际字符。
    • 在 Java 中,两者都映射为 String,区别在于 MySQL 端的处理逻辑,Java 代码无需区分。

日期时间类型

  • 这是另一个极易出错的领域,主要涉及 java.util.Datejava.sql.Datejava.sql.Timestamp 和 Java 8 的新时间 API。
  • *JDBC 旧 API (`java.sql.`)**:
    • java.sql.Date: 对应 MySQL 的 DATE,它只包含日期信息,没有时间部分。new java.sql.Date(date.getTime()) 可以从 java.util.Date 转换。
    • java.sql.Time: 对应 MySQL 的 TIME,只包含时间信息。
    • java.sql.Timestamp: 对应 MySQL 的 DATETIMETIMESTAMP,它同时包含日期和时间信息,精度到纳秒。在 JDBC 中,处理 DATETIMETIMESTAMP 通常使用 getTimestamp()setTimestamp()
  • *Java 8 新时间 API (`java.time.`)强烈推荐使用**
    • LocalDate: 对应 java.sql.Date 和 MySQL 的 DATE,表示一个不可变的日期。
    • LocalTime: 对应 java.sql.Time 和 MySQL 的 TIME,表示一个不可变的时间。
    • LocalDateTime: 对应 java.sql.Timestamp 和 MySQL 的 DATETIME,表示一个不可变的日期和时间。
    • Instant: 对应 MySQL 的 TIMESTAMP,它表示一个时间线上的瞬时点,不与时区关联,非常适合存储和传输时间戳。
  • 时区问题
    • DATETIME 不存储时区信息,它存储的是“本地时间”。
    • TIMESTAMP 会存储 UTC 时间,并在读取和写入时根据服务器的时区进行转换。
    • 最佳实践:如果应用需要支持全球用户,建议所有数据库字段都使用 TIMESTAMP,或者在应用层面统一使用 UTC 时间,然后在展示时再转换为用户所在时区的时间。

ORM 框架的映射

在现代开发中,我们很少直接使用 JDBC,而是使用 ORM(对象关系映射)框架,如 JPA(Hibernate 实现)或 MyBatis。

JPA (Java Persistence API)

JPA 通过注解来定义 Java 对象与数据库表的映射关系。

示例:一个用户实体类

import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDate;
@Entity // 声明这是一个JPA实体
@Table(name = "t_user") // 对应数据库中的 t_user 表
public class User {
    @Id // 声明这是主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
    private Long id;
    @Column(nullable = false, length = 50) // 对应 VARCHAR(50)
    private String username;
    @Column(columnDefinition = "TINYINT(1)") // 显式指定列类型
    private Boolean isActive;
    @Column(name = "balance", precision = 10, scale = 2) // 对应 DECIMAL(10, 2)
    private BigDecimal balance;
    @Column(name = "birth_date") // 对应 DATE
    private LocalDate birthDate;
    @Column(name = "created_at") // 对应 DATETIME
    private LocalDateTime createdAt;
    // Getters and Setters...
}
  • @Entity: 标记类为实体。
  • @Table: 指定对应的数据库表。
  • @Id: 标记主键。
  • @GeneratedValue: 定义主键生成策略。
  • @Column: 用于详细配置列属性,如 name(列名)、nullable(是否可为空)、length(字符串长度)、precisionscale(用于 DECIMAL)、columnDefinition(直接指定SQL列定义)。

MyBatis

MyBatis 的映射更灵活,通常在 XML 文件或注解中定义。

MySQL数据类型与Java如何对应?-图2
(图片来源网络,侵删)

示例:Mapper XML

<mapper namespace="com.example.mapper.UserMapper">
    <resultMap id="userResultMap" type="com.example.model.User">
        <id property="id" column="id" />
        <result property="username" column="username" jdbcType="VARCHAR" />
        <result property="isActive" column="is_active" jdbcType="BIT" />
        <result property="balance" column="balance" jdbcType="DECIMAL" />
        <result property="birthDate" column="birth_date" jdbcType="DATE" />
        <result property="createdAt" column="created_at" jdbcType="TIMESTAMP" />
    </resultMap>
    <select id="selectById" resultMap="userResultMap">
        SELECT id, username, is_active, balance, birth_date, created_at
        FROM t_user
        WHERE id = #{id}
    </select>
</mapper>
  • MyBatis 使用 resultMap 来明确指定 Java 对象的属性如何与数据库的列对应。
  • jdbcType 是可选的,但显式指定可以避免一些类型不匹配的问题,特别是在使用 语法时。

总结与最佳实践

  1. 优先使用 Java 8 的时间 APILocalDate, LocalTime, LocalDateTimejava.sql.Datejava.sql.Timestamp 更现代、更易用,线程也更安全。
  2. 财务数据必须用 BigDecimal:对于所有货币和精确计算,MySQL 使用 DECIMAL,Java 使用 java.math.BigDecimal,避免使用 floatdouble
  3. 主键使用 BIGINT:即使当前数据量不大,也建议使用 BIGINT 作为自增主键,以应对未来业务增长,避免 INT 溢出。
  4. 利用 ORM 框架:使用 JPA 或 MyBatis 可以大大简化数据类型映射的工作,提高开发效率和代码可维护性,在定义实体时,明确注解列的类型和约束。
  5. 注意时区:如果你的应用是面向全球用户的,请统一使用 UTC 时间进行存储和计算,并在前端或业务逻辑层进行时区转换。
  6. 保持一致性:在一个项目中,尽量保持数据类型映射的规范和一致性,约定所有日期时间字段都使用 TIMESTAMP 并映射为 LocalDateTime
MySQL数据类型与Java如何对应?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇