Java Hibernate连接payroll库报LogicalConnection已关闭异常
问题描述
在Eclipse开发环境中使用Java语言,基于Hibernate 5.5.3.Final框架开发数据库操作功能,预期连接本地payroll数据库操作student表,已导入JDBC驱动及其他所需Jar依赖包,程序运行时抛出异常无法完成操作。
报错信息
Jul 14, 2022 2:34:10 PM org.hibernate.Version logVersion INFO: HHH000412: Hibernate ORM core version 5.5.3.Final Jul 14, 2022 2:34:11 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations {5.1.2.Final} Jul 14, 2022 2:34:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!) Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. Jul 14, 2022 2:34:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001005: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost/payroll] Jul 14, 2022 2:34:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001001: Connection properties: {user=root, password=****} Jul 14, 2022 2:34:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001003: Autocommit mode: false Jul 14, 2022 2:34:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init> INFO: HHH000115: Hibernate connection pool size: 3 (min=1) Jul 14, 2022 2:34:11 PM org.hibernate.dialect.Dialect <init> INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect Jul 14, 2022 2:34:11 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@304b9f1a] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Hibernate: select student0_.id as id1_0_, student0_.email as email2_0_, student0_.first_name as first_na3_0_, student0_.last_name as last_nam4_0_ from student student0_ Hibernate: select student0_.id as id1_0_0_, student0_.email as email2_0_0_, student0_.first_name as first_na3_0_0_, student0_.last_name as last_nam4_0_0_ from student student0_ where student0_.id=? Exception in thread "main" java.lang.IllegalStateException: org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl@5eb97ced is closed at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.errorIfClosed(AbstractLogicalConnectionImplementor.java:37) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:137) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:276) at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:121) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:304) at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:142) at models.Student.get(Student.java:131) at Driver.main(Driver.java:24)
相关代码
Driver主类(Driver.java)
import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.*; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import models.Student; public class Driver { public static void main(String[] args) { Student stu =new Student(); List<Student> students=stu.readAll(); for(Student s: students) { System.out.println(s.getFirstName()); } Student s1=stu.get(4); System.out.println(s1.getFirstName()); } public static Session getCurrentSessionFromConfig() { Configuration config = new Configuration(); config.configure(); SessionFactory sessionFactory = config.buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); return session; } public static Session getCurrentSessionX() { Map<String, String> settings = new HashMap<>(); settings.put("connection.driver_class", "com.mysql.jdbc.Driver"); settings.put("dialect", "org.hibernate.dialect.MySQL8Dialect"); settings.put("hibernate.connection.url", "jdbc:mysql://localhost/hibernate_examples"); settings.put("hibernate.connection.username", "root"); settings.put("hibernate.connection.password", ""); settings.put("hibernate.current_session_context_class", "thread"); settings.put("hibernate.show_sql", "true"); settings.put("hibernate.format_sql", "true"); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(settings).build(); MetadataSources metadataSources = new MetadataSources(serviceRegistry); Metadata metadata = metadataSources.buildMetadata(); SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build(); Session session = sessionFactory.getCurrentSession(); return session; } }
Hibernate配置文件(hibernate.cfg.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost/payroll</property> <property name="dialect">org.hibernate.dialect.MySQL8Dialect</property> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.pool_size">3</property> <property name="current_session_context_class">thread</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="hbm2ddl.auto">update</property> <mapping class="models.Student" /> </session-factory> </hibernate-configuration>
SessionFactoryBuilder会话工厂类
package factories; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import models.Student; public class SessionFactoryBuilder { private static SessionFactory sessionFactory = null; public static SessionFactory getSessionFactory () { if(sessionFactory==null) { try { Configuration cfg = new Configuration(); cfg.configure("hibernate.cfg.xml"); sessionFactory = cfg.buildSessionFactory(); }catch(RuntimeException e) {System.out.println(e.toString());} } return sessionFactory; } public static void closeSessionFactory () { if(sessionFactory!=null) { sessionFactory.close(); } } }
Student实体类
package models; import java.util.ArrayList; import java.util.List; import javax.persistence.*; import org.hibernate.Session; import org.hibernate.Transaction; import factories.SessionFactoryBuilder; @Entity @Table(name="student") public class Student { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") int id; @Column(name="first_name") String firstName; @Column(name="last_name") String lastName; @Column(name="email") String email; public Student() { super(); } public Student(int id, String firstName, String lastName, String email) { super(); this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public void create() { Session session =SessionFactoryBuilder.getSessionFactory().getCurrentSession(); Transaction transaction= session.beginTransaction(); session.save(this); transaction.commit(); session.close(); } public List<Student> readAll(){ List<Student> studentList=new ArrayList<>(); Session session =SessionFactoryBuilder.getSessionFactory().getCurrentSession(); Transaction transaction= session.beginTransaction(); studentList=(List<Student>) session.createQuery("From Student").getResultList(); transaction.commit(); session.close(); return studentList; } public void delete(int id) { Session session =SessionFactoryBuilder.getSessionFactory() .getCurrentSession(); Transaction transaction= session.beginTransaction(); Student student = session.get(Student.class, id); if (student != null) { session.delete(student); System.out.println("student deleted"); } transaction.commit(); session.close(); } public void update() { Session session =SessionFactoryBuilder.getSessionFactory() .getCurrentSession(); Transaction transaction= session.beginTransaction(); session.update(this); transaction.commit(); session.close(); } public Student get(int id) { Student stu=null; Transaction transaction=null; try(Session session =SessionFactoryBuilder.getSessionFactory() .getCurrentSession()){ transaction= session.beginTransaction(); stu=(Student) session.get(Student.class, id); session.delete(stu); transaction.commit(); }catch(Exception e) { if(transaction!=null) { transaction.rollback(); } e.printStackTrace(); } return stu; } }
故障根因
- 核心异常触发逻辑:配置了
current_session_context_class=thread时,getCurrentSession()获取的是线程绑定的Session,事务提交/回滚后框架会自动关闭该Session。代码中多处手动调用session.close(),且get()方法使用try-with-resources语法自动关闭Session,导致异常触发回滚逻辑时,连接已经被释放,抛出Connection is closed错误。 - JDBC配置过时:使用MySQL 8.x版本时,配置的旧驱动类
com.mysql.jdbc.Driver已被弃用,且连接URL缺少时区参数,存在连接兼容风险。 - 方法逻辑错误:
get()方法预期功能是按ID查询学生,内部却写了session.delete(stu)的删除逻辑,会误删表数据。 - 异常处理缺陷:
SessionFactoryBuilder初始化时捕获RuntimeException仅打印字符串,不抛出异常,初始化失败时会返回null实例,触发后续空指针问题。
修复方案
- 修正Hibernate配置:将驱动类改为
com.mysql.cj.jdbc.Driver,连接URL修改为jdbc:mysql://localhost/payroll?serverTimezone=Asia/Shanghai&useSSL=false,补充时区配置、禁用测试环境不必要的SSL校验。 - 规范Session生命周期:删除所有CRUD方法中手动调用的
session.close()代码,线程绑定的Session由框架自动管理回收,不需要手动关闭。 - 修正
get()方法逻辑:移除try-with-resources自动关闭语法,删除内部的删除数据逻辑,调整后参考代码如下:
public Student get(int id) { Student stu=null; Transaction transaction=null; Session session = SessionFactoryBuilder.getSessionFactory().getCurrentSession(); try { transaction= session.beginTransaction(); stu=(Student) session.get(Student.class, id); transaction.commit(); }catch(Exception e) { if(transaction!=null && transaction.isActive()) { transaction.rollback(); } e.printStackTrace(); } return stu; }
- 优化SessionFactory异常处理:初始化失败时打印完整异常栈后抛出错误,避免返回null实例。
内容的提问来源于stack exchange,提问作者Apple
相关产品推荐
相关产品推荐

