作为一名 Java 开发者,你是否曾在调试时遇到过这样的报错:Data truncation: Out of range value for column 'age' at row 1?或者在查询数据时发现日期时间总是差 8 小时?又或者 Decimal 类型的数值在 Java 中计算时莫名丢失了精度?
这些问题的根源,往往在于MySQL 字段类型与 Java 字段类型的映射关系处理不当。看似简单的 “类型对应”,实则藏着无数细节陷阱。无论是刚入行的新手还是资深开发者,稍有疏忽就可能踩坑,轻则导致数据异常,重则引发生产事故。
本文将从基础到进阶,全面解析 MySQL 与 Java 的字段类型对应关系,结合 10 + 实战案例拆解常见问题,并附赠 ORM 框架(MyBatis/JPA)的映射技巧,帮你彻底搞定类型映射难题。
一、为什么类型对应如此重要?
在 Java 开发中,数据库交互是绕不开的环节。当我们用 JDBC 或 ORM 框架(如 MyBatis、JPA)操作 MySQL 时,数据会经历 “MySQL 字段→Java 对象” 或 “Java 对象→MySQL 字段” 的转换过程。这个过程中,类型映射的准确性直接决定了数据的完整性和正确性。
举个简单的例子:如果 MySQL 字段是BIGINT(范围 - 9223372036854775808~9223372036854775807),而 Java 中用Integer(范围 - 2147483648~2147483647)接收,当数据库中存储的数值超过 2147483647 时,就会出现数据溢出,导致查询结果异常。
再比如,MySQL 的DATETIME类型与 Java 的LocalDateTime映射时,如果忽略时区配置,可能会出现 “数据库存的是 2023-10-01 12:00,Java 查出来却是 2023-10-01 04:00” 的时区偏移问题。
据统计,在数据库相关的生产事故中,类型映射不当导致的问题占比超过 35%。因此,掌握 MySQL 与 Java 的类型对应规则,是每个 Java 开发者的必备技能。
二、基础类型对应:从数值到字符串的完美映射
MySQL 的字段类型可分为数值型、字符串型、日期时间型三大类,这三类也是日常开发中最常用的。我们先从基础类型入手,逐个解析其对应的 Java 类型及注意事项。
2.1 数值型:精度与范围的平衡术
MySQL 的数值型字段分为整数和小数两大类,不同类型的存储范围和精度差异很大,对应的 Java 类型也需精准匹配。
2.1.1 整数类型(TINYINT 到 BIGINT)
MySQL 的整数类型按存储范围从小到大分为:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,且支持UNSIGNED(无符号)属性。对应的 Java 类型需根据其范围选择,避免溢出。
MySQL 类型 |
存储范围(有符号) |
存储范围(无符号) |
推荐 Java 类型 |
不推荐类型(原因) |
TINYINT |
-128 ~ 127 |
0 ~ 255 |
byte |
int(浪费空间) |
TINYINT UNSIGNED |
无(本身为无符号) |
0 ~ 255 |
short |
byte(范围不足) |
SMALLINT |
-32768 ~ 32767 |
0 ~ 65535 |
short |
int(浪费空间) |
SMALLINT UNSIGNED |
无 |
0 ~ 65535 |
int |
short(范围不足) |
MEDIUMINT |
-8388608 ~ 8388607 |
0 ~ 16777215 |
int |
short(范围不足) |
INT |
-2147483648 ~ 2147483647 |
0 ~ 4294967295 |
int |
long(浪费空间) |
INT UNSIGNED |
无 |
0 ~ 4294967295 |
long |
int(范围不足,会溢出) |
BIGINT |
-9223372036854775808 ~ 9223372036854775807 |
0 ~ 18446744073709551615 |
long |
int(范围严重不足) |
BIGINT UNSIGNED |
无 |
0 ~ 18446744073709551615 |
BigInteger |
long(范围不足,会溢出) |
实战案例:INT UNSIGNED 的溢出陷阱
假设 MySQL 表中有一个字段user_id定义为INT UNSIGNED,用于存储用户 ID(最大可存 4294967295)。如果 Java 实体类中用Integer接收:
// 错误示例
public class User {
private Integer userId; // 对应MySQL的INT UNSIGNED
// 其他字段...
}
当user_id的值超过 2147483647 时(比如 3000000000),查询时会直接抛出异常:
java.sql.SQLException: Out of range value for column 'user_id'
正确做法:用long接收INT UNSIGNED类型:
// 正确示例
public class User {
private Long userId; // 对应MySQL的INT UNSIGNED
// 其他字段...
}
2.1.2 小数类型(FLOAT、DOUBLE、DECIMAL)
小数类型的核心问题是精度。MySQL 的FLOAT和DOUBLE是浮点型,存在精度丢失风险;DECIMAL是定点型,可精确存储小数,适合金额等敏感场景。
MySQL 类型 |
精度特点 |
推荐 Java 类型 |
适用场景 |
FLOAT |
单精度,约 7 位有效数字 |
float |
非精确计算(如温度、重量) |
DOUBLE |
双精度,约 15 位有效数字 |
double |
较高精度但非精确场景 |
DECIMAL(M,D) |
精确存储,M 为总位数,D 为小数位 |
java.math.BigDecimal |
金额、汇率等精确计算场景 |
实战案例:精度丢失的血泪教训
假设用DOUBLE存储订单金额,MySQL 字段定义为amount DOUBLE(10,2),Java 用double接收:
// 实体类
public class Order {
private double amount; // 对应DOUBLE(10,2)
}
// 插入数据:amount=9.99
orderMapper.insert(new Order(9.99));
// 查询后计算:9.99 * 3 = ?
Order order = orderMapper.selectById(1);
double result = order.getAmount() * 3;
System.out.println(result); // 实际输出:29.969999999999996(而非30.0)
这是因为DOUBLE是浮点型,无法精确表示所有小数。正确做法:用DECIMAL+BigDecimal:
-- 数据库字段修改为DECIMAL
ALTER TABLE `order` MODIFY COLUMN `amount` DECIMAL(10,2) NOT NULL;
// 实体类修改为BigDecimal
public class Order {
private BigDecimal amount; // 对应DECIMAL(10,2)
}
// 计算时用BigDecimal的方法
BigDecimal result = order.getAmount().multiply(new BigDecimal("3"));
System.out.println(result); // 输出:29.97(精确)
2.2 字符串型:长度与存储的选择
MySQL 的字符串类型主要有CHAR、VARCHAR、TEXT三大类,它们的存储方式和适用场景不同,对应的 Java 类型虽以String为主,但映射时需注意长度和存储限制。
2.2.1 CHAR 与 VARCHAR:固定长度 vs 可变长度
MySQL 类型 |
存储特点 |
推荐 Java 类型 |
适用场景 |
CHAR(M) |
固定长度,M 为 1~255,不足补空格 |
String |
长度固定的字符串(如手机号、邮编) |
VARCHAR(M) |
可变长度,M 为 1~65535,按实际长度存储 |
String |
长度不固定的字符串(如用户名、地址) |
注意事项:
- VARCHAR的实际存储长度受 MySQL 行大小限制(默认行最大 65535 字节),如果字段长度超过这个限制,建议用TEXT。
- Java 中String可以接收任意长度的字符串,但需注意 ORM 框架的长度校验(如 JPA 的@Column(length=20)会限制输入长度)。
实战案例:VARCHAR 长度溢出
如果 MySQL 字段定义为username VARCHAR(10),Java 实体类用String接收,但插入超过 10 个字符的字符串:
user.setUsername("abcdefghijk"); // 11个字符
userMapper.insert(user);
会抛出截断异常:
java.sql.SQLException: Data truncation: Data too long for column 'username' at row 1
解决方法:要么缩短输入字符串,要么修改字段长度(如VARCHAR(20))。
2.2.2 TEXT 类型:大文本的存储
当字符串长度超过 65535 字节时,需用TEXT类型。TEXT分TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT,对应不同的存储上限。
MySQL 类型 |
存储上限 |
推荐 Java 类型 |
适用场景 |
TINYTEXT |
255 字节 |
String |
短文本(如备注) |
TEXT |
65535 字节 |
String |
中等文本(如文章摘要) |
MEDIUMTEXT |
16777215 字节 |
String |
长文本(如文章内容) |
LONGTEXT |
4294967295 字节 |
String |
超大文本(如日志、备份) |
注意事项:
- TEXT类型不能设置默认值,也不适合作为索引(索引效率低)。
- MyBatis 中查询TEXT类型时,需确保 ResultMap 正确映射(默认会映射为 String,无需额外配置)。
2.3 日期时间型:时区与格式的坑
日期时间类型是最容易出问题的部分,尤其是时区处理。MySQL 的日期时间类型主要有DATE、TIME、DATETIME、TIMESTAMP,对应的 Java 类型需根据场景选择。
2.3.1 类型对应关系
MySQL 类型 |
存储内容 |
时区特性 |
推荐 Java 类型(JDK8+) |
不推荐类型(原因) |
DATE |
日期(年 - 月 - 日) |
无时区 |
java.time.LocalDate |
java.sql.Date(API 过时) |
TIME |
时间(时:分: 秒) |
无时区 |
java.time.LocalTime |
java.sql.Time(API 过时) |
DATETIME |
日期 + 时间(年 - 月 - 日 时:分: 秒) |
无时区(存储原样) |
java.time.LocalDateTime |
java.util.Date(含时区信息,易混淆) |
TIMESTAMP |
日期 + 时间 |
受时区影响(存储 UTC 时间) |
java.time.Instant |
java.sql.Timestamp(线程不安全) |
关键区别:
- DATETIME存储的是 “字符串形式的日期时间”,插入时是什么值,查询时就是什么值,不随时区变化。
- TIMESTAMP存储的是 “UTC 时间戳”,插入时会转换为 UTC 存储,查询时根据当前时区转换为本地时间。
2.3.2 时区问题实战解析
假设 MySQL 服务器时区是UTC,应用服务器时区是Asia/Shanghai(UTC+8)。
场景 1:用DATETIME存储
插入数据时,应用服务器的时间是2023-10-01 12:00:00(北京时间),直接存入DATETIME字段:
INSERT INTO log (operate_time) VALUES ('2023-10-01 12:00:00');
查询时,无论应用服务器时区如何,返回的都是2023-10-01 12:00:00。
场景 2:用TIMESTAMP存储
同样插入2023-10-01 12:00:00(北京时间),MySQL 会转换为 UTC 时间2023-10-01 04:00:00存储。
当应用服务器用Asia/Shanghai时区查询时,会转换为2023-10-01 12:00:00(正确);如果应用服务器时区错误(如UTC),查询结果会是2023-10-01 04:00:00(错误)。
正确映射方式:
- 若用DATETIME,Java 用LocalDateTime接收,无需考虑时区(存储和显示一致)。
- 若用TIMESTAMP,Java 用Instant接收(UTC 时间),再转换为本地时间:
// 实体类
public class Log {
private Instant operateTime; // 对应TIMESTAMP
}
// 查询后转换为北京时间
Log log = logMapper.selectById(1);
LocalDateTime beijingTime = LocalDateTime.ofInstant(
log.getOperateTime(),
ZoneId.of("Asia/Shanghai")
);
三、特殊类型对应:枚举、JSON 与二进制
除了基础类型,MySQL 还有一些特殊类型(如枚举、JSON、二进制),这些类型的映射需要额外处理,尤其是在 ORM 框架中。
3.1 枚举类型(ENUM)
MySQL 的ENUM类型用于存储预定义的枚举值,比如性别(男 / 女)、订单状态(待支付 / 已支付 / 已取消)。
映射规则:
- 推荐:Java 用enum类型对应,清晰且类型安全。
- 不推荐:用String或Integer(易出错,比如传入未定义的枚举值)。
实战案例:ENUM 与 Java 枚举的映射
- 定义 MySQL 表:
CREATE TABLE `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`gender` ENUM('MALE', 'FEMALE', 'UNKNOWN') NOT NULL COMMENT '性别'
);
- 定义 Java 枚举:
public enum Gender {
MALE, FEMALE, UNKNOWN
}
- 实体类映射:
public class User {
private Integer id;
private Gender gender; // 对应ENUM类型
// getter/setter
}
- MyBatis 映射(无需额外配置,默认支持枚举名称映射):
<resultMap id="userMap" type="com.example.User">
<id column="id" property="id"/>
<result column="gender" property="gender"/> <!-- 自动映射为Gender枚举 -->
</resultMap>
- JPA 映射(需用@Enumerated指定映射方式):
import javax.persistence.Enumerated;
import javax.persistence.EnumType;
public class User {
@Enumerated(EnumType.STRING) // 按枚举名称映射(推荐)
private Gender gender;
}
注意:如果@Enumerated用EnumType.ORDINAL,会按枚举的索引(0,1,2)映射,一旦枚举顺序修改,数据会错乱,因此强烈推荐EnumType.STRING。
3.2 JSON 类型(MySQL 5.7+)
MySQL 5.7 及以上支持JSON类型,用于存储 JSON 格式的数据(如用户的扩展信息、商品规格)。Java 中通常有两种映射方式:
映射方式 |
适用场景 |
实现方式 |
字符串映射 |
简单 JSON,无需解析 |
用String接收,直接存储 JSON 字符串 |
对象映射 |
复杂 JSON,需要解析为 Java 对象 |
用自定义类 + TypeHandler(MyBatis)或 Converter(JPA) |
实战案例:JSON 与 Java 对象的映射(MyBatis)
- 定义 MySQL 表:
CREATE TABLE `product` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`spec` JSON NOT NULL COMMENT '商品规格(JSON格式)'
);
- 定义 JSON 对应的 Java 类:
public class ProductSpec {
private String color; // 颜色
private String size; // 尺寸
private Integer weight; // 重量(g)
// getter/setter/toString
}
- 定义 TypeHandler 处理 JSON 与对象的转换:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
private static final ObjectMapper mapper = new ObjectMapper();
private final Class<T> type;
public JsonTypeHandler(Class<T> type) {
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
try {
ps.setString(i, mapper.writeValueAsString(parameter));
} catch (JsonProcessingException e) {
throw new SQLException("Failed to convert object to JSON", e);
}
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
if (json == null) return null;
try {
- 在 MyBatis 中使用 TypeHandler:
<resultMap id="productMap" type="com.example.Product">
<id column="id" property="id"/>
<result column="spec" property="spec" typeHandler="com.example.JsonTypeHandler"/>
</resultMap>
<insert id="insertProduct" parameterType="com.example.Product">
INSERT INTO product (spec)
VALUES (#{spec, typeHandler=com.example.JsonTypeHandler})
</insert>
- 测试代码:
Product product = new Product();
ProductSpec spec = new ProductSpec();
spec.setColor("RED");
spec.setSize("L");
spec.setWeight(500);
product.setSpec(spec);
productMapper.insertProduct(product); // 插入成功
Product saved = productMapper.selectById(1);
System.out.println(saved.getSpec().getColor()); // 输出:RED
3.3 二进制类型(BLOB、BIT)
二进制类型用于存储图片、文件等二进制数据,或位信息(如权限标志)。
MySQL 类型 |
用途 |
推荐 Java 类型 |
TINYBLOB |
小二进制数据(255 字节) |
byte[] |
BLOB |
二进制数据(65535 字节) |
byte[] |
MEDIUMBLOB |
中二进制数据(16MB) |
byte[] |
LONGBLOB |
大二进制数据(4GB) |
byte[] |
BIT(M) |
位数据(M 为 1~64) |
boolean(M=1 时)、long(M>1 时) |
实战案例:BIT 类型的映射
MySQL 字段is_vip BIT(1)用于表示是否为 VIP(1 = 是,0 = 否),Java 用boolean接收:
public class User {
private Boolean isVip; // 对应BIT(1)
}
MyBatis 查询时会自动将BIT(1)转换为boolean(1→true,0→false)。
如果BIT(3)表示三个权限位(如101表示权限 1 和 3),Java 用long接收:
public class UserPermission {
private Long permissions; // 对应BIT(3),存储位数值(如5对应101)
}
通过位运算解析权限:
long permissions = userPermission.getPermissions();
boolean hasPermission1 = (permissions & 1) != 0; // 第1位
boolean hasPermission2 = (permissions & 2) != 0; // 第2位(10)
boolean hasPermission3 = (permissions & 4) != 0; // 第3位(100)
四、ORM 框架中的类型映射技巧
日常开发中,我们很少直接用 JDBC 操作数据库,而是通过 ORM 框架(如 MyBatis、JPA)。这些框架对类型映射有默认规则,也支持自定义转换,掌握这些技巧能避免很多坑。
4.1 MyBatis 的类型映射
MyBatis 通过TypeHandler处理类型转换,内置了大部分类型的处理器,对于特殊类型需自定义(如 JSON、枚举的特殊映射)。
4.1.1 全局配置 TypeHandler
如果某个类型在项目中频繁使用(如 JSON),可在mybatis-config.xml中配置全局 TypeHandler:
<typeHandlers>
<typeHandler handler="com.example.JsonTypeHandler" javaType="com.example.ProductSpec"/>
</typeHandlers>
配置后,使用时无需每次指定typeHandler。
4.1.2 枚举的自定义映射
如果 MySQL 的 ENUM 值与 Java 枚举名称不一致(如 MySQL 是'男',Java 是MALE),可自定义 TypeHandler:
switch (parameter) {
case MALE: ps.setString(i, "男"); break;
case FEMALE: ps.setString(i, "女"); break;
default: ps.setString(i, "未知");
}
}
@Override
public Gender getNullableResult(ResultSet rs, String columnName) throws SQLException {
// MySQL字符串→Java枚举
String gender = rs.getString(columnName);
switch (gender) {
case "男": return Gender.MALE;
case "女": return Gender.FEMALE;
default: return Gender.UNKNOWN;
}
}
// 其他方法省略
}
4.2 JPA 的类型映射
JPA(如 Hibernate)有更强大的自动映射能力,通过注解可轻松实现复杂类型转换。
4.2.1 日期时间的时区配置
JPA 默认会根据 JVM 时区转换日期,若需指定时区,可在application.properties中配置:
# Spring Data JPA配置
spring.jpa.properties.hibernate.jdbc.time_zone=Asia/Shanghai
4.2.2 自定义属性转换器(Converter)
对于 JSON 类型,JPA 可通过@Converter自定义转换:
import javax.persistence.Converter;
import javax.persistence.AttributeConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
@Converter(autoApply = true) // 自动应用到所有ProductSpec类型
public class ProductSpecConverter implements AttributeConverter<ProductSpec, String> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(ProductSpec attribute) {
try {
return mapper.writeValueAsString(attribute);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to convert to JSON", e);
}
}
@Override
public ProductSpec convertToEntityAttribute(String dbData) {
try {
return mapper.readValue(dbData, ProductSpec.class);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to convert from JSON", e);
}
}
}
实体类中直接使用:
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer id;
private ProductSpec spec; // 自动使用ProductSpecConverter转换
// getter/setter
}
五、常见问题与避坑指南
即使掌握了基础映射规则,实际开发中仍可能遇到各种问题。这里总结了 5 个高频问题及解决方案。
5.1 问题 1:整数类型溢出
现象:查询或插入时抛出Out of range异常。
原因:Java 类型的范围小于 MySQL 字段类型的范围(如用int接收BIGINT)。
解决方案:
- 参考 2.1.1 的类型对应表,确保 Java 类型范围覆盖 MySQL 类型。
- 无符号类型(UNSIGNED)需用更大的 Java 类型(如INT UNSIGNED→long)。
5.2 问题 2:日期时间差 8 小时
现象:查询的日期时间比数据库中存储的少 8 小时。
原因:
- MySQL 时区与应用服务器时区不一致(如 MySQL 是 UTC,应用是北京时间)。
- TIMESTAMP类型会随时区转换,而DATETIME不会。
解决方案:
- 统一 MySQL 和应用服务器的时区(推荐设为 UTC 或 Asia/Shanghai)。
- 用LocalDateTime接收DATETIME,用Instant接收TIMESTAMP并显式指定时区转换。
5.3 问题 3:Decimal 精度丢失
现象:数值计算结果与预期不符(如 9.99*3=29.969999...)。
原因:用double接收DECIMAL类型,浮点运算导致精度丢失。
解决方案:
- 强制用BigDecimal接收DECIMAL类型。
- 计算时使用BigDecimal的add、multiply等方法,避免转换为double。
5.4 问题 4:字符串截断
现象:插入时抛出Data truncation异常。
原因:输入字符串长度超过 MySQL 字段定义的长度(如VARCHAR(10)插入 11 个字符)。
解决方案:
- 前端限制输入长度,与数据库字段长度保持一致。
- 后端用@Size(JPA)或自定义校验注解校验长度。
- 必要时修改数据库字段长度(如VARCHAR(20))。
5.5 问题 5:枚举值不匹配
现象:插入时抛出Data truncation: Incorrect enum value异常。
原因:Java 枚举值不在 MySQLENUM定义的范围内。
解决方案:
- 确保 Java 枚举与 MySQLENUM的取值完全一致。
- 新增枚举值时,先修改数据库ENUM定义,再更新 Java 枚举。
六、实战案例:完整用户表的类型映射
为了让你更直观地理解类型映射,我们设计一个完整的用户表,包含多种类型的字段,并实现 Java 实体类与 ORM 映射。
6.1 数据库表设计
CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`age` TINYINT UNSIGNED NOT NULL COMMENT '年龄(0-255)',
`height` DECIMAL(5,2) COMMENT '身高(米,如1.75)',
`register_time` DATETIME NOT NULL COMMENT '注册时间',
`last_login_time` TIMESTAMP NULL COMMENT '最后登录时间',
`gender` ENUM('MALE', 'FEMALE', 'UNKNOWN') NOT NULL COMMENT '性别',
`preferences` JSON COMMENT '偏好设置(JSON格式)',
`is_vip` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否VIP',
`avatar` MEDIUMBLOB COMMENT '头像(二进制)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
6.2 Java 实体类
import org.hibernate.annotations.Type;
public class User {
private Long id; // BIGINT→Long
private String username; // VARCHAR(50)→String
private Short age; // TINYINT UNSIGNED→Short
private BigDecimal height; // DECIMAL(5,2)→BigDecimal
private LocalDateTime registerTime; // DATETIME→LocalDateTime
private Instant lastLoginTime; // TIMESTAMP→Instant
private Gender gender; // ENUM→Gender枚举
private Map<String, Object> preferences; // JSON→Map(或自定义类)
private Boolean isVip; // BIT(1)→Boolean
private byte[] avatar; // MEDIUMBLOB→byte[]
// getter/setter
}
// 性别枚举
public enum Gender {
MALE, FEMALE, UNKNOWN
}
6.3 MyBatis 映射文件
<mapper namespace="com.example.UserMapper">
<resultMap id="userMap" type="com.example.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="age" property="age"/>
<result column="height" property="height"/>
<result column="register_time" property="registerTime"/>
<result column="last_login_time" property="lastLoginTime"/>
<result column="gender" property="gender"/>
<result column="preferences" property="preferences" typeHandler="com.example.JsonTypeHandler"/>
<result column="is_vip" property="isVip"/>
<result column="avatar" property="avatar"/>
</resultMap>
<insert id="insertUser" parameterType="com.example.User">
INSERT INTO `user` (
username, age, height, register_time, last_login_time,
gender, preferences, is_vip, avatar
6.4 测试代码
public void t
@Test
estUserMapping() {
// 创建用户
User user = new User();
user.setUsername("张三");
user.setAge((short) 28);
user.setHeight(new BigDecimal("1.75"));
user.setRegisterTime(LocalDateTime.now());
user.setLastLoginTime(Instant.now());
user.setGender(Gender.MALE);
Map<String, Object> preferences = new HashMap<>();
preferences.put("language", "zh-CN");
preferences.put("theme", "dark");
user.setPreferences(preferences);
user.setIsVip(true);
user.setAvatar(new byte[]{0x89, 0x50, 0x4E, 0x47}); // 示例图片二进制数据
七、总结
MySQL 字段类型与 Java 字段类型的对应,看似是基础知识点,实则贯穿整个开发流程,影响着系统的稳定性和数据的准确性。本文从基础类型到特殊类型,从手动映射到 ORM 框架自动映射,全方位解析了类型对应的规则和技巧,并通过实战案例拆解了常见问题。
核心要点总结:
- 数值类型:根据范围选择 Java 类型,DECIMAL必须用BigDecimal。
- 字符串类型:VARCHAR和TEXT都用String,注意长度限制。
- 日期时间:DATETIME→LocalDateTime,TIMESTAMP→Instant,重视时区问题。
- 特殊类型:ENUM用 Java 枚举,JSON用自定义对象 + 转换器,二进制用byte[]。
- ORM 框架:MyBatis 用TypeHandler,JPA 用@Converter,简化复杂类型映射。
掌握这些知识,你就能轻松避开类型映射的各种 “坑”,写出更健壮的代码。如果觉得本文对你有帮助,欢迎点赞收藏,也欢迎在评论区分享你的类型映射经验!