我有一個 Java 應用程式,它有一個用 Swing 制作的 GUI,并且可以互換使用兩個資料庫。兩個資料庫之一是 mongoDB,另一個是 MySQL。使用命令列選項選擇要使用的資料庫。對于 MySQL 資料庫,我也使用 Hibernate 和 JPA。我的代碼如下所示:
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
switch (databaseType) {
case "mysql":
EntityManagerFactory emf;
EntityManager entityManager;
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
LOGGER.log(Level.ERROR, "MySQL Exception", e);
}
break;
case "mongo":
// mongo stuff, no EntityManagerFactory here
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
//...
try {
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
return null;
}
如果mysql我正在創建一個EntityManagerFactory和一個EntityManager. 這里entityManager創建的作為引數傳遞給存盤庫的建構式,并在應用程式的整個生命周期中使用。我想知道關閉entityManager和工廠的最佳做法是什么。在檔案中搜索我發現了這個:
關閉 EntityManagerFactory 不應掉以輕心。長期保持工廠開工比反復創建和關閉新工廠要好得多。因此,大多數應用程式永遠不會關閉工廠,或者僅在應用程式退出時關閉它。
所以我想知道,在應用程式關閉時關閉工廠和物體管理器與不關閉它有什么區別?同樣在我的情況下,我宣告emf并entityManager在mysql案例內部,因為mongodb. 為了在應用程式關閉時關閉它們,我應該怎么做?我發現了一些關于Runtime.getRuntime().addShutdownHook(). 我嘗試像下面的代碼一樣使用它,但它似乎不起作用。
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
Thread closeHook = new Thread(() -> {
if (emf != null) {
entityManager.close();
emf.close();
LOGGER.log(Level.INFO, "Close entity manager and entity manager factory");
}
});
Runtime.getRuntime().addShutdownHook(closeHook);
// other stuff
} catch (Exception e) {
LOGGER.log(Level.ERROR, "MySQL Exception", e);
}
uj5u.com熱心網友回復:
簡短的回答,是的,它應該被關閉。原因可以在這個答案中找到:
JVM 將在終止時釋放所有活動資源;但是,這并不能確保另一端也會釋放資源,因此明確關閉資源符合每個程式員的最大利益。
所以在我的例子中,EntityManager 和 factory 在應用程式關閉時確實是關閉的,但這并不能確保它們在另一端得到正確處理。我沒有在我的問題中提到它,但事實上同樣的事情也適用于 Mongo 客戶端(見這個答案):
如果您在沒有先重新啟動應用程式服務器的情況下重新部署 Web 應用程式,則必須確保在關閉 Web 應用程式時關閉 MongoClient。
關于實作,我制作了一個我呼叫的介面DBInitializer。我在方法中實體化了一個型別MongoInitializer或MySQLInitializer(都實作DBInitializer)的物件main。請參閱代碼以獲得更清晰的資訊。
DBInitializer:
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
MySQL初始化程式:
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
@Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
@Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
MongoInitializer:
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
@Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
@Override
public void closeDbConnection() {
client.close();
}
}
應用程式:
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}
uj5u.com熱心網友回復:
在應用程式關閉時關閉工廠和物體管理器與不關閉它有什么區別?
潛在的資源泄漏(例如未關閉的連接池)與缺乏。還:
我嘗試像下面的代碼一樣使用它,但它似乎不起作用。
為什么不使用try-with-resources陳述句?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/428673.html
