Java连接mysql常遇时间问题

文章讲述了在Java开发中遇到的时区转换问题,特别是在与MySQL数据库交互时,如何通过设置`serverTimezone`参数避免8小时的时差误差。此外,讨论了在数据库表中利用`CURRENT_TIMESTAMP`自动管理创建时间和修改时间的方法,以及如何在JavaPojo类中使用LocalDateTime处理数据库的时间戳,简化日期格式转换的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 时区转换问题

相信大多数人都遇见过数据库时间提取到Java对象之后,发生时间不一致的问题

连接数据库的时候若不设置,就会引发时区转换的问题,其原因是因为:
咱们所在时区为东八区,而默认时区为0区,差距八个小时,所以每次在与数据库交互时就会发生八小时的误差,
若要解决此问题,就要在连接数据库时设置配置:

jdbc:mysql://localhost:3306/friend?useSSL=false&serverTimezone=Asia/Shanghai

黄色字体便是设置的时区,设置之后在与mysql交互的时候就不会发生时区的问题了。

2.数据库字段创建时间和修改时间

很多的数据库表都需要有创建时间和修改时间,此时就会引发许多问题

如果是在Java类中自己设置时间过于麻烦,此时便可以在数据库建表的时候设置

 create_time   timestamp default CURRENT_TIMESTAMP not null comment '创建时间',
 update_time   timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '修改时间',

创建表的时候进行以上的设置便能在插入字段和修改字段的时候,数据库自动修改时间

3.数据库时间转换问题

数据库的timestamp时间为时间戳,如果转换到Java里面就会遇见一些问题

若是Java字段直接用date数据接收的话也可以,但是和前端交互的时候就会有格式问题,date的格式直接发送给前端的话,用户看的话不是特别方便,如果每次发送给前端都要转换就显得有些麻烦
此时可以在pojo类中设置为localdatetime类型,修改一下set代码,便可成功接收.

private LocalDateTime createTime;

public void setCreateTime(Date createTime){
        LocalDateTime localDateTime = createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        this.createTime = localDateTime;
    }
<think>我们正在处理一个Tomcat中与MySQL连接清理线程相关的异问题。用户到了“Web应用程序[ROOT]似乎启动了一个名为[mysql-cj-abandoned-connection-cleanup]的线程,但未能停止它”的警告,并且可能伴随有“非法访问”异。这通发生在Web应用程序停止时,未能正确注销JDBC驱动或清理相关线程,导致内存泄漏。 根据引用[1],用户已经尝试了一些解决方案,但未找到类`com.mysql.cj.jdbc.AbandonedConnectionCleanupThread`,说明用户使用的可能是较新版本的MySQL Connector/J(例如8.x版本),其中这个类的路径或机制可能已经改变。 解决方案通需要确保在Web应用程序关闭时,正确关闭所有数据库连接并注销驱动,同时停止由MySQL驱动启动的清理线程。 以下是针对该问题的解决方案步骤: 1. **确保使用正确版本的MySQL驱动**:如果使用的是MySQL Connector/J 8.x,则`AbandonedConnectionCleanupThread`类位于`com.mysql.cj.jdbc.AbandonedConnectionCleanupThread`。但是,在较新的驱动版本中,可能已经改变了清理机制。 2. **在web.xml中注册监听器**:在Web应用程序的部署描述符(web.xml)中注册一个ServletContextListener,用于在应用程序关闭时手动停止清理线程。以下是一个示例: ```xml <listener> <listener-class>com.example.MyContextListener</listener-class> </listener> ``` 然后创建对应的监听器类`com.example.MyContextListener`: ```java import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Enumeration; public class MyContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { // 初始化操作 } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { // 注销所有JDBC驱动 Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); } catch (SQLException e) { e.printStackTrace(); } } // 停止MySQL的AbandonedConnectionCleanupThread try { AbandonedConnectionCleanupThread.checkedShutdown(); } catch (Exception e) { e.printStackTrace(); } } } ``` 注意:如果类路径中没有`AbandonedConnectionCleanupThread`,可能是因为MySQL驱动版本不同。在MySQL Connector/J 8.0.22及以上版本,`AbandonedConnectionCleanupThread`类已被移除,因此上述代码可能会报错。 3. **针对MySQL Connector/J 8.0.22及以上版本**:从8.0.22版本开始,MySQL驱动移除了`AbandonedConnectionCleanupThread`,改为使用`java.lang.ref.Cleaner`机制。因此,不再需要手动停止该线程。但是,仍然需要确保正确注销驱动。如果使用较高版本,只需注销驱动即可: ```java public class MyContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { // 注销所有JDBC驱动 Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); } catch (SQLException e) { e.printStackTrace(); } } } } ``` 4. **使用连接池的情况**:如果使用了连接池(如HikariCP、Tomcat JDBC等),则需要在监听器中关闭连接池。因为连接池会管理连接,在关闭时应该释放所有连接并关闭连接池。 例如,使用HikariCP时: ```java public class MyContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // 初始化连接池 HikariConfig config = new HikariConfig(); // 配置连接池 HikariDataSource ds = new HikariDataSource(config); sce.getServletContext().setAttribute("dataSource", ds); } @Override public void contextDestroyed(ServletContextEvent sce) { HikariDataSource ds = (HikariDataSource) sce.getServletContext().getAttribute("dataSource"); if (ds != null) { ds.close(); } // 然后注销驱动(同上) } } ``` 5. **检查Tomcat版本和配置**:有时,Tomcat本身可能无法正确卸载Web应用程序,导致线程残留。可以尝试在Tomcat的`context.xml`中添加以下配置: ```xml <Context reloadable="true" unloadDelay="5000"> ``` `unloadDelay`属性设置了在停止应用程序后等待其卸载的时间(毫秒),给清理线程足够的时间来停止。 6. **更新MySQL驱动**:如果问题仍然存在,建议更新到最新版本的MySQL Connector/J,因为新版本可能已经修复了相关的问题。 7. **检查日志**:查看Tomcat的日志(catalina.out或localhost.log)以获取更详细的错误信息,有助于定位问题。 8. **替代方案**:如果上述方法都不起作用,可以尝试在应用程序启动时设置系统属性,禁止MySQL驱动创建清理线程(不推荐,仅作为最后手段): ```java System.setProperty("com.mysql.cj.disableAbandonedConnectionCleanup", "true"); ``` 但请注意,这可能会导致废弃的连接无法被回收,从而可能引起其他问题。 总结:解决该问题的关键在于在Web应用程序关闭时,正确关闭数据库连接、注销驱动并停止由驱动创建的线程。具体方法取决于使用的MySQL驱动版本和连接池。 如果用户使用的是较新的MySQL驱动(8.0.22+),则无需处理`AbandonedConnectionCleanupThread`,只需注销驱动即可。如果使用连接池,则要确保关闭连接池。 注意:在编写监听器时,务必确保在关闭连接池和注销驱动时捕获异,避免导致整个关闭过程中断。 如果用户按照上述步骤操作后仍然存在问题,建议提供更详细的错误日志以便进一步分析。 §§相关问题§§ 1. 如何确定MySQL Connector/J的版本? 2. 在Spring Boot项目中如何正确关闭数据库连接? 3. Tomcat中如何配置多个数据源并确保它们正确关闭? 4. 使用连接池时,如何避免内存泄漏?</think>### Tomcat中MySQL连接清理线程引发的Web应用程序非法访问异解决方案 #### 问题分析 当Tomcat关闭时出现"mysql-cj-abandoned-connection-cleanup线程未停止"的警告,并伴随"非法访问"异,通由以下原因导致: 1. **驱动未正确注销**:MySQL JDBC驱动在应用停止时未注销 2. **清理线程未终止**:MySQL的`AbandonedConnectionCleanupThread`未正确关闭 3. **类加载器问题**:Tomcat的类加载机制导致线程残留 4. **连接池未关闭**:数据库连接池未在应用停止时正确关闭[^1] #### 解决方案(针对MySQL Connector/J 8.x+) ##### 1. 注册ServletContextListener 在`web.xml`中添加: ```xml <listener> <listener-class>com.example.DbCleanupListener</listener-class> </listener> ``` 创建监听器类: ```java import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Enumeration; public class DbCleanupListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { // 注销所有JDBC驱动 Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); } catch (SQLException e) { e.printStackTrace(); } } // 停止MySQL清理线程(适用于8.0.22以下版本) try { AbandonedConnectionCleanupThread.checkedShutdown(); } catch (Exception e) { System.err.println("MySQL清理线程关闭失败: " + e.getMessage()); } // 强制清理线程(备用方案) Thread[] threads = new Thread[Thread.activeCount()]; Thread.enumerate(threads); for (Thread thread : threads) { if (thread.getName().contains("mysql-cj-abandoned-connection-cleanup")) { synchronized(thread) { thread.interrupt(); } } } } } ``` ##### 2. 针对MySQL 8.0.22+的优化 新版驱动移除了`AbandonedConnectionCleanupThread`,改用`java.lang.ref.Cleaner`机制: ```java // 在contextDestroyed中添加 System.gc(); // 触发Cleaner机制 ``` ##### 3. 连接池配置优化(如使用HikariCP) ```java @Override public void contextDestroyed(ServletContextEvent sce) { HikariDataSource dataSource = (HikariDataSource) sce.getServletContext() .getAttribute("dataSource"); if (dataSource != null && !dataSource.isClosed()) { dataSource.close(); // 关键:显式关闭连接池 } // ...其他清理逻辑 } ``` ##### 4. Tomcat配置调整 在`context.xml`中添加: ```xml <Context unloadDelay="5000"> <!-- 延长卸载等待时间 --> <JarScanner scanClassPath="false"/> <!-- 减少类加载冲突 --> </Context> ``` ##### 5. 驱动兼容性处理 在应用启动时添加(仅限极端情况): ```java System.setProperty("com.mysql.cj.disableAbandonedConnectionCleanup", "true"); ``` #### 验证步骤 1. 部署修复后的应用 2. 正停止Tomcat服务 3. 检查`catalina.out`日志: - 应不再出现`mysql-cj-abandoned-connection-cleanup`警告 - 确认输出`Driver deregistered`成功消息 4. 使用JConsole监控线程终止情况 > **重要提示**:MySQL Connector/J 8.0.22+版本已重构连接清理机制[^1],若仍问题建议升级驱动至最新版(当前8.0.33+),同时确保连接池配置了`testOnBorrow`和`removeAbandonedTimeout`参数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱发博客的嗯哼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值