program using hibernate does not terminate

前端 未结 13 837
孤街浪徒
孤街浪徒 2020-12-25 10:14

I created a program using Hibernate.

The program reaches the main function end, nevertheless the program is running.

I wonder if it happens when Sessio

相关标签:
13条回答
  • 2020-12-25 10:47

    I am using hibenate 5.2.12 with sqlite 3.20.1, managing the connection manually. In my case the problem was that not only the entity manager had to be closed but also the entity manager factory.

    With these attributes:

    EntityManager entityManager;
    EntityTransaction entityTransaction;
    

    This snippet is used when opening the DB and starting a transaction:

    EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, map);
    entityManager = emf.createEntityManager(map);
    entityTransaction = entityManager.getTransaction();
    entityTransaction.begin();
    

    This snipped is used to commit the transaction and close the DB:

    entityTransaction.commit();
    if ( entityManager.isOpen() ) {
        entityManager.close();
    }
    EntityManagerFactory emf = entityManager.getEntityManagerFactory();
    if ( emf.isOpen() ) {
        emf.close();
    }
    

    Now with emf.close(); my application terminates as is should be.

    0 讨论(0)
  • 2020-12-25 10:48

    I have just had the same problem. I was using Hibernate 4.1.1 and everything was working fine. Today I upgraded to Hibernate 4.3.1 and suddenly my application didn't terminate anymore. I investigated a little further and noticed that version 4.1.1 didn't have any problem with an open EntityManagerFactory. That's why my application always terminated. That's not the case with version 4.3.1 anymore. So I checked my application and made sure that the EntityManagerFactory was closed at the end (indeed I was not really closing it). Problem solved to me. Are you really sure there's nothing left open in your application? Hope this helps.

    Marcos

    0 讨论(0)
  • 2020-12-25 10:48

    My answer is for Hibernate 4.3+ version, and I use it in my way.

    A example of Spring Annotation configured with Hibernate:

    //Using AutoCloseable 1.7 feature here to close context and 
    //suppress warning Resource leak: 'context' is never closed
    //Creating AutoClosebale AbstractApplicationContext Object context
    try (AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class)) {
    
        SnacksMenu snacks = context.getBean(SnacksMenu.class);
        System.out.println(snacks.toString());
    
        //Creating AutoClosebale SessionFactory Object factory
        try (SessionFactory factory = getStandardServiceEnabledSessionFactory()){
    
            //Creating AutoClosebale Session Object session
            try (Session session = factory.openSession()) {
    
                SessionCounter.analysisSession(session);
                System.out.println("1: Opened Sessions under factory : " + SessionCounter.getOpenSessionsCount());
    
                Transaction transaction = session.beginTransaction();
    
                session.persist(snacks);
                transaction.commit();
    
                System.out.println(session.isConnected());
            }//Session Object session resource auto closed
    
        }//SessionFactory Object factory resource auto closed
    
        System.out.println("2: Opened Sessions under factory : " + SessionCounter.getOpenSessionsCount());
    
    }//AbstractApplicationContext Object context resource auto closed
    
    0 讨论(0)
  • 2020-12-25 10:50

    I met this problem also today, and I found the solution is, in the end of your main method (or thread), you should close your Session Factory, like:

    sessionFactory.close();
    

    And then, your program will terminate normally.

    If You use JavaFX 8 in main method add:

    @Override
    public void stop() throws Exception {
        sessionFactory.close();
    }
    

    This method will close session factory and destroy thread on program exit.

    0 讨论(0)
  • 2020-12-25 10:54

    We have multiple connections to database.

    class ConnectionProviderFactory implements DataBaseConnectionProvider {
    
    private EnumMap<SystemInstance, Properties> connectionsConfigs = new EnumMap<>(SystemInstance.class);
    private Map<SystemInstance, EntityManager> entityManagers = new HashMap<>();
    private Map<SystemInstance, ConnectionPerSystemInstance> connections = new HashMap<>();
    
    
    @Getter
    private static class ConnectionPerSystemInstance {
    
        private String uuid = UUID.randomUUID().toString();
    
        private final SessionFactory sessionFactory;
        private final SystemInstance systemInstance;
    
        private ConnectionPerSystemInstance(final SessionFactory sessionFactory, SystemInstance systemInstance){
            this.sessionFactory = sessionFactory;
            this.systemInstance = systemInstance;
        }
    
        static ConnectionPerSystemInstance createConnection(Properties properties, SystemInstance systemInstance) {
            StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
            registryBuilder.applySettings(toMap(properties));
            StandardServiceRegistry registry = registryBuilder.build();
            MetadataSources sources = new MetadataSources(registry);
            Metadata metadata = sources.getMetadataBuilder().build();
            SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
            return new ConnectionPerSystemInstance(sessionFactory, systemInstance);
        }
    
        private static Map<String, String> toMap(Properties properties) {
            Map<String, String> map = new HashMap<>();
            for (String name : properties.stringPropertyNames()) {
                map.put(name, properties.getProperty(name));
            }
            return map;
        }
    
        EntityManager getEntityManager() {
            if(sessionFactory == null) {
                throw new IllegalStateException("Connection not initialized!");
            }
            return sessionFactory.createEntityManager();
        }
    
        void close() {
            if(sessionFactory == null) {
                throw new IllegalStateException("Connection not initialized!");
            }
            sessionFactory.close();
        }
    
        @Override
        public boolean equals(final Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            final ConnectionPerSystemInstance that = (ConnectionPerSystemInstance) o;
    
            return uuid.equals(that.uuid);
        }
    
        @Override
        public int hashCode() {
            return uuid.hashCode();
        }
    }
    
    @PostConstruct
    private void init() {
        String testQuery = "select sysdate from dual";
    
        EntityManager e1TEST = connect(SystemInstance.TEST);
    
        EntityManager e1PROD = connect(SystemInstance.PROD);
    
        log.info("" + e1TEST.createNativeQuery(testQuery).getSingleResult());
        log.info("" + e1PROD.createNativeQuery(testQuery).getSingleResult());
    }
    
    @PreDestroy
    private void clean() {
        entityManagers.forEach((key, value) -> value.close());
        connections.forEach((systemInstance, connectionPerSystemInstance) -> {
            connectionPerSystemInstance.close();
        });
    }
    
    @Override
    public EntityManager connect(final SystemInstance systemInstance) {
    
        if (Optional.ofNullable(entityManagers.get(systemInstance)).isPresent()) {
            entityManagers.get(systemInstance);
        }
    
        Properties properties = loadConnectionProperties(systemInstance);
        ConnectionPerSystemInstance connection = ConnectionPerSystemInstance.createConnection(properties, systemInstance);
        connections.put(systemInstance, connection);
        entityManagers.put(systemInstance, connection.getEntityManager());
    
        return entityManagers.get(systemInstance);
    }
    
    @Override
    public void closeAllConnection() {
        clean();
    }
    
    private Properties loadConnectionProperties(SystemInstance systemInstance) {
    
        if (Optional.ofNullable(connectionsConfigs.get(systemInstance)).isPresent()) {
            return connectionsConfigs.get(systemInstance);
        }
    
        return tryLoadConnectionProperties(systemInstance);
    }
    
    private Properties tryLoadConnectionProperties(final SystemInstance systemInstance) {
        final String nameOfPropertyFile = getNameOfPropertyFile(systemInstance);
        ClassPathResource classPathResource = new ClassPathResource(nameOfPropertyFile);
        Properties properties = new Properties();
        try {
            properties.load(classPathResource.getInputStream());
            addAdditionalConnectionSettings(properties);
            connectionsConfigs.put(systemInstance, properties);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());                                                                             //TODO chanfe exception
        }
        return properties;
    }
    
    private String getNameOfPropertyFile(SystemInstance systemInstance) {
        if (systemInstance == SystemInstance.TEST)
            return "db/db-test.properties";
        if (systemInstance == SystemInstance.PROD)
            return "db/db-prod.properties";
        throw new IllegalArgumentException("Incorrect configuration");
    }
    
    private void addAdditionalConnectionSettings(Properties properties) {
        properties.putIfAbsent("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
        properties.putIfAbsent("hibernate.c3p0.timeout", "0");
    }
    

    }

    In this example we have multiple databases so we can easily close all connections.

    0 讨论(0)
  • 2020-12-25 10:55

    Ensure the same SessionFactory instance you are dealing with through out the program. i.e. The program must terminate if you are closing the same SessionFactory that you built and opened the Session in the program. The source code in the question part doesn't guaranty this and hence the trouble.

    Please have a look at the following simple and straight forward solution,

    //your class definition
    public static void main(String args[]) {
            SessionFactory sessionFactory = getSessionFactory();
            Session session = sessionFactory.openSession();
            session.beginTransaction().begin();
            session.save(yourEntity);
            session.beginTransaction().commit();
            session.close();
            sessionFactory.close();
    }
    
    public static SessionFactory getSessionFactory() {
            Configuration cfg = new Configuration();
            cfg.configure("com/srees/hibernate.cfg.xml");
            SessionFactory sessionFactory = cfg.buildSessionFactory();
            return sessionFactory;
        }
    //your class def ends here
    
    0 讨论(0)
提交回复
热议问题