LocalDateTime + mybatis plus的异常

之前的项目中用的mybatis plus非常好,然后新项目中也用了,但是新项目结构比较特殊。一个工程是gradle项目,一个是maven项目,公用一个common包,然后就出现了一个小问题,原来自定义的有时间字段拦截器,统一把时间更新为UTC时间,结果发现新的有问题,更新的时间变成了UTC-8.

经过debug和打印日志,发现是因为

        <!-- mybatis-JSR310标准类型(即java8新加的日期类型)转换,防止LocalDateTime等转换失败。
    高版本的mybatis里也带了对应的转换类,但没有具体实现,而是把实现交给了第三方的JDBC连接池。
    springboot默认自带的HikariPool连接池没有很好的实现,所以会报错,只能把该依赖包加在mybatis相关依赖之前,
    这样就可以把mybatis中的转换累给替换掉 -->
<!--        20250219 mybatis 版本升级之后,默认支持localdatetime类型了,-->
<!--        如果还是用这个版本,会变成timestap,造成时区转换有问题,所以就应该-->
<!--        取消这个-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-typehandlers-jsr310</artifactId>
            <version>1.0.2</version>
        </dependency>

这个造成的,虽然都用了这个common包,但是应该是其中maven的覆盖没有生效,然后gradle的生效了。

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;

/**
 * @since 3.4.5
 * @author Tomas Rohovsky
 */
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType)
          throws SQLException {
    ps.setObject(i, parameter);
  }

就是这个设置的地方造成的,可以看到mybatis从3.4.5版本就支持localdatetime字段了。而原来的是这样的

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;

/**
 * @author Tomas Rohovsky
 */
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType)
          throws SQLException {
    ps.setTimestamp(i, Timestamp.valueOf(parameter));
  }

可以发现区别,一个是把LocalDateTime 转换为Timestamp,一个是转换为Object,因为我原来设置的就是LocalDateTime ,转换为Timestamp带上时间戳,然后数据库连接又是characterEncoding=utf8&allowMultiQueries=true&serverTimezone=UTC
造成变成了UTC-8,因为我转换为LocalDateTime 时,已经减去8了。

所以,高版本的mybatis记得要把这个第三方包给去掉,低版本的时候要加上。

### MyBatisMyBatis Plus 面试题对比及解答 #### 1. **MyBatisMyBatis Plus 的定义** MyBatis 是一款优秀的持久层框架,它支持定制化 SQL 查询、存储过程以及高级映射等功能。而 MyBatis Plus 是基于 MyBatis 进行扩展的一款增强版框架,提供了更多便捷的功能,如代码生成器、CRUD 操作封装、分页插件等[^1]。 --- #### 2. **MyBatis 主要特性** - 支持动态 SQL 构建。 - 提供强大的 XML 映射文件功能。 - 自定义 Mapper 接口实现复杂业务需求。 - 内置一级缓存和二级缓存机制以提升性能[^2]。 --- #### 3. **MyBatis Plus 主要特性** - 自动生成代码工具,快速搭建基础模块。 - 简化 CRUD 操作,无需编写繁琐的 Mapper 方法。 - 提供内置分页插件,方便处理大数据量查询。 - 支持乐观锁机制,解决并发更新问题。 - 注解驱动开发模式,减少 XML 文件配置工作量[^1]。 --- #### 4. **MyBatis 一级缓存 vs 二级缓存** - **一级缓存**:存在于 `SqlSession` 层级,属于单线程私有缓存。一旦关闭当前 `SqlSession` 或提交事务,缓存即失效。不同 `SqlSession` 间不共享数据。 - **二级缓存**:作用于 `Mapper` 层级,同一命名空间内的多个 `SqlSession` 可共享缓存内容。需手动开启并通过 `<cache/>` 标签或注解形式激活。 --- #### 5. **MyBatis Plus 表名识别原理** 如果未显式指定表名,MyBatis Plus 默认会在与实体类名称一致的表中执行查询操作。例如,对于名为 `User` 的实体类,默认会尝试访问 `user` 表。若实际表名与实体类名不符,则可通过 `@TableName` 注解明确指定目标表名[^3]。 ```java @TableName("custom_user_table") public class User { private Long id; private String name; // Getter and Setter methods... } ``` --- #### 6. **@TableField 注解的作用** `@TableField` 注解主要用于描述字段的相关属性,适用于以下场景: - 当数据库字段名与 Java 实体类字段名不一致时,通过此注解进行映射关系说明。 - 控制是否忽略某个字段(如设置 `exist=false`),使其不在 SQL 中参与增删改查操作。 - 定义特殊行为,例如时间戳自动填充等附加功能[^3]。 ```java @TableField(value = "create_time", fill = FieldFill.INSERT) private LocalDateTime createTime; ``` --- #### 7. **资源释放的重要性** 在使用 MyBatisMyBatis Plus 开发应用时,务必确保及时关闭 `ResultSet`、`Statement` 和 `Connection` 对象,以免因长时间占用系统资源而导致内存泄漏或其他异常状况发生[^3]。 --- #### 8. **MyBatisMyBatis Plus 的区别总结** | 特性 | MyBatis | MyBatis Plus | |--------------------------|----------------------------------|-------------------------------| | 数据库交互灵活性 | 更加自由可控 | 提供更高层次抽象 | | CRUD 操作 | 需手写 SQL | 内置通用方法 | | 分页功能 | 需借助第三方插件 | 内置分页插件 | | 性能优化手段 | 支持一/二级缓存 | 继承原有缓存能力并新增特性 | --- ### 示例代码展示 以下是基于 MyBatis Plus 的简单 CURD 示例: ```java // 创建 ServiceImpl 类继承 BaseServiceImpl @Service public class UserService extends ServiceImpl<UserMapper, User> implements IUserService {} // 测试用例 @Test void testCrudOperations() { // 插入记录 User user = new User(); user.setName("John Doe"); userService.save(user); // 更新记录 user.setName("Jane Doe"); userService.updateById(user); // 删除记录 userService.removeById(user.getId()); // 查询记录 List<User> users = userService.list(new QueryWrapper<User>().like("name", "Doe")); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值