Hibernate 和多线程逻辑
Hibernate and multiThread Logic
我正在处理 java 独立项目。我需要在多线程应用程序中使用休眠,但我不知道如何正确设置它。
每个线程处理与其他线程相同的进程。
当我以非异步方式 运行 时一切正常,但是当我使用线程调用相同的东西时,休眠就不能正常工作。
任何人都可以向我解释在多线程中使用 Hibernate 的正确方法是什么 Java 独立应用程序?
Hibernate 实用程序
public class HibernateUtil {
private static final Session session;
static {
try {
SessionFactory sessionFactory;
Properties properties = new Properties();
properties.load(new FileInputStream("middleware.properties"));
Configuration cfg = new Configuration().configure();
cfg.addProperties(properties);
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
} catch (IOException | HibernateException he) {
JOptionPane.showMessageDialog(null, DataBaseMessage.CONNECTION_ERROR.getMessage(), DataBaseMessage.CONNECTION_ERROR.getTitle(),JOptionPane.ERROR_MESSAGE);
throw new ExceptionInInitializerError(he);
}
}
public static Session getSession() {
return session;
}
这里出现错误
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
public synchronized List<TbHistoDespachos> ExractDespachoAndNotify(String data, String nombreConexion) {
List<TbHistoDespachos> despachos = new ArrayList<>();
String nombreConexionUpp = nombreConexion.toUpperCase();
try {
Document doc = convertStringToDocument(data);
if (!doc.getRootElement().getChild("reply").getChild("readTagIDs")
.getChildren().isEmpty()) {
for (Element element : doc.getRootElement().getChild("reply").
getChild("readTagIDs").getChild("returnValue")
.getChildren()) {
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
if (despacho != null) {
if(evaluateDespacho(nombreConexionUpp, despacho)){
despachos.add(despacho);
}
}
}
}
} catch (JDOMException | IOException ex) {
JOptionPane.showMessageDialog(null, FilesMessageWarnings.NOTIFICATION_SAP_WARNING.
getMessage().replace("&nombreConexion", nombreConexion).replace("&tagID", ""),
FilesMessageWarnings.NOTIFICATION_SAP_WARNING.getTitle(), JOptionPane.WARNING_MESSAGE);
}
return despachos;
}
这是 DAO
public class Dao {
private static Session sesion;
public static TbHistoDespachos findDespachoByTagId(String tagId) {
TbHistoDespachos despacho = null;
try {
startTransmission();
despacho = (TbHistoDespachos)sesion.createQuery("FROM TbHistoDespachos WHERE TAG_ID =:tagId")
.setParameter("tagId", tagId)
.uniqueResult();
stopTransmission();
} catch (HibernateException he) {
System.out.println("error: " + he.getMessage());
JOptionPane.showMessageDialog(null, DataBaseMessage.QUERY_ERROR.getMessage(),
DataBaseMessage.QUERY_ERROR.getTitle(), JOptionPane.ERROR_MESSAGE);
}
return despacho;
}
private static void startTransmission() {
sesion = HibernateUtil.getSession();
sesion.getTransaction().begin();
}
private static void stopTransmission() {
sesion.getTransaction().commit();
sesion.getSessionFactory().getCurrentSession().close();
sesion.clear();
}
有什么想法吗?
问题源于 static Session
个变量。 SessionFactory
是线程安全的,一般来说,每个数据库只需要一个(静态)实例。另一方面,Session
不是线程安全的,通常是动态创建的(使用 SessionFactory
)和 discarted/closed。
要解决您眼前的问题,请从您的 Dao 中删除 static Session sesion
变量以及 'inline' findDespachoByTagId
方法中的 startTransmission
和 stopTransmission
方法.这将确保每个调用 findDespachoByTagId
的线程都创建并使用自己的会话实例。分析当前问题,想象两个线程同时调用findDespachoByTagId
。现在静态会话变量将被startTransmission
方法赋值两次。这意味着一个会话实例在创建后几乎立即丢失,而另一个会话实例同时被两个线程使用。不是什么好事。
但也存在其他问题:没有 finally
块保证事务关闭和数据库连接被释放(通过关闭会话)。此外,您可能希望使用数据库池,因为 Hibernate 提供的数据库池不适合生产。我建议你看看 HibHik: I created this project to show a minimal stand-alone Java application using Hibernate with a database pool (HikariCP) that uses the recommended patterns and practices (mostly shown in TestDbCrud.java)。在你的应用程序中使用相关部分,而不是编写多线程单元测试来验证你的数据库层(DAO)是否正常工作,即使在出现故障的情况下(例如,当数据库突然不再可用时,因为网络电缆是拔掉插头)。
我正在处理 java 独立项目。我需要在多线程应用程序中使用休眠,但我不知道如何正确设置它。
每个线程处理与其他线程相同的进程。
当我以非异步方式 运行 时一切正常,但是当我使用线程调用相同的东西时,休眠就不能正常工作。
任何人都可以向我解释在多线程中使用 Hibernate 的正确方法是什么 Java 独立应用程序?
Hibernate 实用程序
public class HibernateUtil {
private static final Session session;
static {
try {
SessionFactory sessionFactory;
Properties properties = new Properties();
properties.load(new FileInputStream("middleware.properties"));
Configuration cfg = new Configuration().configure();
cfg.addProperties(properties);
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
} catch (IOException | HibernateException he) {
JOptionPane.showMessageDialog(null, DataBaseMessage.CONNECTION_ERROR.getMessage(), DataBaseMessage.CONNECTION_ERROR.getTitle(),JOptionPane.ERROR_MESSAGE);
throw new ExceptionInInitializerError(he);
}
}
public static Session getSession() {
return session;
}
这里出现错误
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
public synchronized List<TbHistoDespachos> ExractDespachoAndNotify(String data, String nombreConexion) {
List<TbHistoDespachos> despachos = new ArrayList<>();
String nombreConexionUpp = nombreConexion.toUpperCase();
try {
Document doc = convertStringToDocument(data);
if (!doc.getRootElement().getChild("reply").getChild("readTagIDs")
.getChildren().isEmpty()) {
for (Element element : doc.getRootElement().getChild("reply").
getChild("readTagIDs").getChild("returnValue")
.getChildren()) {
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
if (despacho != null) {
if(evaluateDespacho(nombreConexionUpp, despacho)){
despachos.add(despacho);
}
}
}
}
} catch (JDOMException | IOException ex) {
JOptionPane.showMessageDialog(null, FilesMessageWarnings.NOTIFICATION_SAP_WARNING.
getMessage().replace("&nombreConexion", nombreConexion).replace("&tagID", ""),
FilesMessageWarnings.NOTIFICATION_SAP_WARNING.getTitle(), JOptionPane.WARNING_MESSAGE);
}
return despachos;
}
这是 DAO
public class Dao {
private static Session sesion;
public static TbHistoDespachos findDespachoByTagId(String tagId) {
TbHistoDespachos despacho = null;
try {
startTransmission();
despacho = (TbHistoDespachos)sesion.createQuery("FROM TbHistoDespachos WHERE TAG_ID =:tagId")
.setParameter("tagId", tagId)
.uniqueResult();
stopTransmission();
} catch (HibernateException he) {
System.out.println("error: " + he.getMessage());
JOptionPane.showMessageDialog(null, DataBaseMessage.QUERY_ERROR.getMessage(),
DataBaseMessage.QUERY_ERROR.getTitle(), JOptionPane.ERROR_MESSAGE);
}
return despacho;
}
private static void startTransmission() {
sesion = HibernateUtil.getSession();
sesion.getTransaction().begin();
}
private static void stopTransmission() {
sesion.getTransaction().commit();
sesion.getSessionFactory().getCurrentSession().close();
sesion.clear();
}
有什么想法吗?
问题源于 static Session
个变量。 SessionFactory
是线程安全的,一般来说,每个数据库只需要一个(静态)实例。另一方面,Session
不是线程安全的,通常是动态创建的(使用 SessionFactory
)和 discarted/closed。
要解决您眼前的问题,请从您的 Dao 中删除 static Session sesion
变量以及 'inline' findDespachoByTagId
方法中的 startTransmission
和 stopTransmission
方法.这将确保每个调用 findDespachoByTagId
的线程都创建并使用自己的会话实例。分析当前问题,想象两个线程同时调用findDespachoByTagId
。现在静态会话变量将被startTransmission
方法赋值两次。这意味着一个会话实例在创建后几乎立即丢失,而另一个会话实例同时被两个线程使用。不是什么好事。
但也存在其他问题:没有 finally
块保证事务关闭和数据库连接被释放(通过关闭会话)。此外,您可能希望使用数据库池,因为 Hibernate 提供的数据库池不适合生产。我建议你看看 HibHik: I created this project to show a minimal stand-alone Java application using Hibernate with a database pool (HikariCP) that uses the recommended patterns and practices (mostly shown in TestDbCrud.java)。在你的应用程序中使用相关部分,而不是编写多线程单元测试来验证你的数据库层(DAO)是否正常工作,即使在出现故障的情况下(例如,当数据库突然不再可用时,因为网络电缆是拔掉插头)。