1)在 Hibernate 中存在一个单个 SessionFactory 对象每个应用程序。
SessionFactory的内部状态是不可变的, 所以它是线程安全的。多个线程可以同时访问它以获取 Session 实例。
下面的代码描述了通过实用程序类获取 SessionFactory 实例的标准方法。
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
/**
* Hibernate Utility class with a method to get Session Factory object.
*/
public class HibernateUtil {
private static final SessionFactory sessionFactory;//Once created, its properties cannot be changed
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml) config file.
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
2)休眠Session是java应用层和hibernate之间的接口。这是用于执行数据库操作的核心接口。
会话的生命周期受逻辑事务的开始和结束的限制。
Hibernate Session 对象不是线程安全的,每个线程都应该获取自己的会话实例,并在工作完成后关闭它。
这并不意味着实现者是线程安全的。相反,每个线程/事务应该从 SessionFactory 获取自己的实例。
A typical transaction should use the following idiom:
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
如果会话抛出异常,则必须回滚事务并丢弃会话。异常发生后Session的内部状态可能与数据库不一致。
2.1)下面列出了两种广泛用于获取 Hibernate Session 对象的方法。
-
开放会话//用这个来多线程环境
-
获取当前会话//用这个来单线程环境
Hibernate会话工厂getCurrentSession() 方法返回绑定到上下文的会话。但要使其工作,我们需要在 hibernate 配置文件中对其进行配置。由于这个会话对象属于hibernate上下文,所以我们不需要关闭它。一旦 SessionFactory 关闭,该会话对象也将关闭。
<property name="hibernate.current_session_context_class">thread</property>
Hibernate会话工厂打开会话()方法总是打开一个新会话。我们应该close一旦我们完成了所有的数据库操作,这个会话对象。
我们应该在多线程环境中为每个请求打开一个新会话。
2.2) 还有一种使用 openStatelessSession() 创建 Hibernate Session 对象的方法,它为您提供了一个 hibernate Stateless Session。
它是一个面向命令的 API,用于对数据库执行批量操作。
无状态会话不实现一级缓存,也不与任何二级缓存交互,也不实现事务性后写或自动脏检查,也不将操作级联到关联的实例。无状态会话会忽略集合。通过无状态会话执行的操作绕过 Hibernate 的事件模型和拦截器。由于缺乏一级缓存,无状态会话容易受到数据别名效应的影响。
对于某些类型的事务,无状态会话的执行速度可能比有状态会话稍快。(例如:批处理/批量更新)
StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWARD_ONLY);
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
session.update(customer);
}
tx.commit();
session.close();
在此代码示例中,查询返回的 Customer 实例立即分离。它们从不与任何持久性上下文相关联。
StatelessSession接口定义的insert()、update()和delete()操作被认为是直接的数据库行级操作。它们分别导致立即执行 SQL INSERT、UPDATE 或 DELETE。
无状态会话不是线程安全的,使用无状态会话时可能发生的异常是“org.hibernate.AssertionFailure:可能对会话进行非线程安全访问”
3)您的学生记录项目是一个多线程应用程序,因此在使用 hibernate 时需要小心。尝试通过打开新会话、使用事务、提交和回滚以及在需要时关闭会话来使用最佳编程实践。
我个人在我们的项目中使用了 hibernate,我们有数百万用户通过 hibernate 作为后端 API 访问数据库。我们在多线程环境中从未遇到过此类问题,因为我们使用了 hibernate 的最佳编程实践。即使数据库发生任何异常,整个事务也会回滚。
因此,与 JDBC 相比,可以以更高的成功率实现数据库事务的 ACID 属性(原子性、一致性、隔离性、持久性)。