我为Spring应用程序配置了Hibernate。我有一个名为hibernateUtil.java
的文件,它为Hibernate创建一个新会话。问题是我何时应该调用getSession
方法?有没有更好的方法呢?
hibernate.cfg.xml中
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/mydb
</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">12</property>
<!-- SQL dialect -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<mapping class="com.myproject.model.business" />
</session-factory>
</hibernate-configuration>
HibernateUtil.java
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
private static SessionFactory sessionFactory;
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
e.printStackTrace();
}
return sessionFactory;
}
static {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
}
我也发现了tutorial,但我不确定它是否可靠。它建议使用Spring bean配置文件进行Hibernate配置。
答案 0 :(得分:1)
如果您的应用程序是使用java servlet的Web应用程序,则可以添加一个servlet请求筛选器,您可以在其中启动会话甚至事务。然后可以使用相同的类来提交事务和刷新/关闭会话。 例如(没有错误处理):
import javax.servlet.*;
public class HibernateSessionRequestFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Session session=HibernateUtil.getSession();
session.beginTransaction();
// Call the next filter (continue request processing)
chain.doFilter(request, response);
session.flush();
session.getTransaction().commit();
}
答案 1 :(得分:1)
通常会创建一个通用dao实现,并让所有其他daos扩展这个泛型dao。(请注意,这不是那么冗长,只是为了引用):
public interface GenericDAO<T, ID extends Serializable> {
T save(T entity);
void delete(T entity);
}
示例实施:
public class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, ID> {
private Class<T> persistentClass;
public GenericHibernateDAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession()
{
return sessionFactory.getCurrentSession();
}
@Override
public T save(T entity)
{
getSession().save(entity);
return entity;
}
@Override
public void delete(T entity) {
getSession().delete(entity);
}
}
所以,例如你创建你的Dao就像:
public class SampleHibernateDao extends
GenericHibernateDAO<DomainObj, DomainObjId> implements SampleDAO {
@Override
public List<Object> findAnything(String find)
throws HibernateException {
Query query = getSession()
.createQuery(....)
}
}
我想你会得到一个大致的想法。
另外,使用spring配置sessionfactory,如:
<!-- DB settings -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xxxx" />
<property name="username" value="root" />
<property name="password" value="root" />
<property name="validationQuery" value="SELECT 1" />
<property name="testOnBorrow" value="true" />
</bean>
<!-- Hibernate Settings -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.xxx.xxx" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.xx.xxx.xxx.Domain</value>
</list>
</property>
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager" />
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
答案 2 :(得分:0)
不确定什么是rebuildSessionFactory()方法。 SessionFactory是Hibernates单个数据存储区的概念,并且是线程安全的,因此许多线程可以同时访问它并为单个数据库请求编译映射的会话和不可变缓存。 SessionFactory通常只在启动时构建一次
Sessions是一个Hibernate结构,用于调解与数据库的连接。 会话在创建时会打开一个数据库连接,并保持该连接直到会话关闭。 Hibernate从数据库加载的每个对象都与会话相关联,允许Hibernate自动持久化已修改的对象,并允许Hibernate实现延迟加载等功能。
public class HibernateUtil {
public static final ThreadLocal local = new ThreadLocal();
public static Session currentSession() throws HibernateException {
Session session = (Session) local.get();
//open a new session if this thread has no session
if(session == null) {
session = sessionFactory.openSession();
local.set(session);
}
return session;
}
}
另请检查Detached,Persistent和Transient对象之间的区别。不确定为什么要在Controller中打开hibernate会话。
答案 3 :(得分:0)
您应该在何时(以及在哪里)获得交易时获得会话。这个想法是你需要一个交易会话。并且会话不是线程安全的,每个线程或事务都应该获得自己的实例。
话虽如此,如果您在spring webapp中使用容器管理持久性,Spring或JPA注释可以为您注入。
以下代码来自https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html
典型的交易应使用以下习语:
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();
}
答案 4 :(得分:0)
我设法删除了HibernateUtil并使用Spring来管理我的hibernate会话,遵循M. Deinum的评论和tutorial。
将以下内容添加到project-servler.xml文件中,同时添加所需的依赖项。
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDao" class="net.codejava.spring.dao.UserDAOImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
在我添加上面的行之后,它遇到了一个依赖注入错误,提到了here。