我使用Hibernate创建了一个程序。
程序到达主函数端,但程序正在运行。
我想知道在使用Hibernate Version 4.x配置SessionFactory
时是否会发生这种情况。
配置错误的方法是什么?
manual1_1_first_hibernate_apps.java
public static void main(String[] args) {
args[0] ="list";
if (args.length <= 0) {
System.err.println("argement was not given");
return;
}
manual1_1_first_hibernate_apps mgr = new manual1_1_first_hibernate_apps();
if (args[0].equals("store")) {
mgr.createAndStoreEvent("My Event", new Date());
}
else if (args[0].equals("list")) {
mgr.<Event>listEvents().stream()
.map(e -> "Event: " + e.getTitle() + " Time: " + e.getDate())
.forEach(System.out::println);
}
Util.getSessionFactory().close();
}
private <T> List<T> listEvents() {
Session session = Util.getSessionFactory().getCurrentSession();
session.beginTransaction();
List<T> events = Util.autoCast(session.createQuery("from Event").list());
session.getTransaction().commit();
return events;
}
Util.java
private static final SessionFactory sessionFactory;
/**
* build a SessionFactory
*/
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
// hibernate version lower than 4.x are as follows
// # it successful termination. but buildSessionFactory method is deprecated.
// sessionFactory = new Configuration().configure().buildSessionFactory();
// version 4.3 and later
// # it does not terminate. I manually terminated.
Configuration configuration = new Configuration().configure();
StandardServiceRegistry serviceRegistry =
new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* @return built SessionFactory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
程序终止时使用以下控制台日志片段并使用buildSessionFactory方法。
2 08, 2014 8:42:25 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH000030: Cleaning up connection pool [jdbc:derby:D:\Java\jdk1.7.0_03(x86)\db\bin\testdb]
但如果不使用弃用的buildSessionFactory方法并终止(程序正在运行),则不会出现上述两行。
环境:
Hibernate 4.3.1 DERBY JRE 1.8 IntelliJ IDEA 13
答案 0 :(得分:46)
我今天也遇到了这个问题,我发现解决方案是,在你的主方法(或线程)的最后,你应该关闭你的Session Factory,如:
sessionFactory.close();
然后,您的程序将正常终止。
如果在main方法中使用JavaFX 8,请添加:
@Override
public void stop() throws Exception {
sessionFactory.close();
}
此方法将关闭会话工厂并在程序退出时销毁线程。
答案 1 :(得分:13)
我今天遇到了同样的问题,但我找到了另一个类似的解决方案:
我在代码末尾插入了以下行:
StandardServiceRegistryBuilder.destroy(serviceRegistry);
和Ta-dah!该计划结束。
答案 2 :(得分:7)
4.3.4.Final中的相同问题。
现在添加以下代码后,问题就消失了。
public class Service {
private SessionFactory factory;
private ServiceRegistry serviceRegistry;
public void initialize() throws Exception{
Configuration configuration = new Configuration();
configuration.configure("com/jeecourse/config/hibernate.cfg.xml");
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
configuration.getProperties()).build();
factory = configuration.buildSessionFactory(serviceRegistry);
}
public void close() throws Exception{
if(serviceRegistry!= null) {
StandardServiceRegistryBuilder.destroy(serviceRegistry);
}
}
.....
答案 3 :(得分:5)
我在Util.getSessionFactory()。close()调用后看到了线程转储,名为“pool-2-thread-1”状态的线程是TIMED_WAITING(停放)。
以下代码段转储
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.0-b69 mixed mode):
"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x00000000020b9000 nid=0x3684 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"pool-2-thread-1" #15 prio=5 os_prio=0 tid=0x000000001bc27000 nid=0x3f0 waiting on condition [0x000000001ce6f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000080be30a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
"derby.rawStoreDaemon" #14 daemon prio=5 os_prio=0 tid=0x000000001b059000 nid=0xa3c in Object.wait() [0x000000001ba1f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000805f6190> (a org.apache.derby.impl.services.daemon.BasicDaemon)
at org.apache.derby.impl.services.daemon.BasicDaemon.rest(Unknown Source)
- locked <0x00000000805f6190> (a org.apache.derby.impl.services.daemon.BasicDaemon)
at org.apache.derby.impl.services.daemon.BasicDaemon.run(Unknown Source)
at java.lang.Thread.run(Thread.java:744)
"Timer-0" #13 daemon prio=5 os_prio=0 tid=0x000000001b08e800 nid=0x2160 in Object.wait() [0x000000001b6af000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000080608118> (a java.util.TaskQueue)
at java.lang.Object.wait(Object.java:502)
at java.util.TimerThread.mainLoop(Timer.java:526)
- locked <0x0000000080608118> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505)
我认为原因是由buildSessionFactory方法创建的名为“pool-2-thread-1”的线程。
作为比较两个buildSessionFactory方法的结果,我注意到ServiceRegistry资源尚未发布。
程序通过发布成功终止。
以下代码,我补充说。
Util.java
configuration.setSessionFactoryObserver(
new SessionFactoryObserver() {
@Override
public void sessionFactoryCreated(SessionFactory factory) {}
@Override
public void sessionFactoryClosed(SessionFactory factory) {
((StandardServiceRegistryImpl) serviceRegistry).destroy();
}
}
);
感谢。
答案 4 :(得分:4)
似乎Hibernate 4.3.1引入了一个bug。我在我的应用程序中创建了连接:
EntityManagerFactory connection = Persistence.createEntityManagerFactory(...)
但即使createEntityManagerFactory
方法因异常而失败,服务注册表仍保持打开状态。但是,正如您从上面的代码中看到的那样,我无法终止我的应用程序,因为由于方法没有成功,因此未分配变量connection
(它是 null ),所以我无法调用会破坏服务注册表的connection.close()
。看起来这确实是一个错误,因为如何在不诉诸黑客的情况下释放资源,比如使用JPA应用程序中的特定Hibernate API?
答案 5 :(得分:4)
我今天也遇到了这个问题,我发现解决方案如下:
sessionFactory.close();
如果你有,会有效
<property name="connection.pool_size">1</property>
答案 6 :(得分:2)
我正在使用hibenate 5.2.12和sqlite 3.20.1,手动管理连接。就我而言,问题是不仅要关闭实体经理,还要关闭实体经理工厂。
具有以下属性:
EntityManager entityManager;
EntityTransaction entityTransaction;
打开数据库并开始交易时使用此代码段:
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, map);
entityManager = emf.createEntityManager(map);
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
此剪切用于提交事务并关闭数据库:
entityTransaction.commit();
if ( entityManager.isOpen() ) {
entityManager.close();
}
EntityManagerFactory emf = entityManager.getEntityManagerFactory();
if ( emf.isOpen() ) {
emf.close();
}
现在使用emf.close();
我的应用程序应该终止。
答案 7 :(得分:1)
我刚遇到同样的问题。我使用的是Hibernate 4.1.1,一切正常。今天我升级到Hibernate 4.3.1,突然我的应用程序不再终止了。我进一步调查了一下,注意到版本4.1.1对开放的EntityManagerFactory没有任何问题。这就是我的应用程序总是终止的原因。 4.3.1版本不再是这种情况了。所以我检查了我的应用程序并确保EntityManagerFactory最后关闭(事实上我并没有真正关闭它)。问题解决了我。你真的确定你的申请中没有任何东西可以打开吗?希望这会有所帮助。
马科斯
答案 8 :(得分:0)
我有同样的问题,解决方案很简单,你必须将此属性添加到配置文件
<property name="hibernate.c3p0.timeout">0</property>
答案 9 :(得分:0)
我的答案是Hibernate 4.3+版本,我以我的方式使用它。
使用Hibernate配置的Spring Annotation示例:
//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
答案 10 :(得分:0)
我们有多个数据库连接。
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");
}
}
在此示例中,我们有多个数据库,因此我们可以轻松关闭所有连接。
答案 11 :(得分:0)
我遇到了同样的问题,原因是我们需要正确关闭资源。 尝试在finally块中关闭资源
try{
Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
sessionFactory = cfg.buildSessionFactory();;
session = sessionFactory.openSession();
transaction = session.beginTransaction();
session.save(person);
transaction.commit();
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
}finally{
if(session.isOpen()){
System.out.println("Closing session");
session.close();
}
if(!sessionFactory.isClosed()){
System.out.println("Closing SessionFactory");
sessionFactory.close();
}
}
答案 12 :(得分:0)
确保在整个程序中使用相同的SessionFactory实例。即,如果您要关闭在程序中构建并打开会话的同一SessionFactory,则该程序必须终止。问题部分中的源代码不能保证这一点,因此会带来麻烦。
请查看以下简单明了的解决方案,
//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