在Spring中集成Hibernate
声明Hibernate的Seccion工厂
SessionFactory主要负责Hibernate Seccion的打开、关闭以及管理。
在Spring中,我们要通过Spring的某一个Hibernate Seccion工厂bean来获取Hibernate SessionFactory。从3.1版本开始,Spring提供了三个Seccion工厂bean供我们选择:
- org.springframework.orm.hibernate4.LocalSessionFactoryBean;
- org.springframework.orm.hibernate3.LocalSessionFactoryBean;
- org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
这些Seccion工厂bean都是Spring FactoryBean接口的实现,它们会产生一个Hibernate SessionFactory,它能够装配进任何SessionFactory类型的属性中。这样的话。就能在应用的Spring上下文中,与其他的bean一起配置Hibernate Seccion工厂。
至于选择使用哪一个Seccion工厂,这取决于使用哪个版本的Hibernate以及你使用XML还是使用注解来定义对象-数据库之间的映射关系。这里我使用的是Hibernate4.1.4版本,所以我使用org.springframework.orm.hibernate4.LocalSessionFactoryBean。配置如下:
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource)
{
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan(new String[] {"entity"});
Properties properties = new Properties();
properties.setProperty("dialect", "org.hibernate.dialect.H2Dialect");
sessionFactory.setHibernateProperties(properties);
return sessionFactory;
}
其它版本的配置等用到再补上。
构建不依赖于Spring的Hibernate代码
@Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
private Session getSession() {
return sessionFactory.getCurrentSession();
//return sessionFactory.openSession();
}
openSession()与getCurrentSession()的区别:
openSession: 当调用SessionFactory的openSession方法时,它总是创建一个新的session给你。不会绑定到当前的线程中去,并且需要手动区关闭。
getCurrentSession: 采用getCurrentSession()创建的Session会绑定到当前的线程中去(返回的都是同一个Session),在commit或rollback后会自动关闭。
这里我们使用getCurrentSession(),但是getCurrentSession()方法必须配置事务管理,配置如下:
RootConfig.java
@Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory)
{
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
//价于XML配置如下
// <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
//<property name="sessionFactory" ref="sessionFactory"></property>
// </bean>
WebConfig.java
@EnableTransactionManagement //开启事务支持
//作用等价于<tx:annotation-driven />
并且在server层使用事务
@Transactional
在Spring中集成JPA
在Spring中使用JPA的第一步是要在Spring应用上下文中配置实体管理器工厂。
配置实体管理器工厂
基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:
- 应用程序管理类型:当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在Java EE容器中的独立应用程序。
- 容器管理类型:实体管理器由Java EE创建和管理。应用程序根本不与实体管理器打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于Java EE容器,在这种情况下会希望在persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。
以上两种实体管理器实现了同一个EntityManager接口。关键区别在于EntityManager的创建和管理方式。 应用程序管理类型的EntityManager是由EntityManagerFactory创建的,而后者时通过PersistenceProvider的createEntityManagerFactory()方法得到的。
不管你希望使用哪种EntityManagerFactory,Spring都会负责管理EntityManager。
这两种实体管理器工厂分别由对应的Spring工厂Bean创建:
- LocalEntityManagerFactoryBean:生成应用程序管理类型的EntityManagerFactory;
- LocalContainerEntityManagerFactoryBean:生成容器管理类型的EntityManagerFactory;
这里我只配置容器管理类型的EntityManagerFactory。
使用容器管理类型的JPA
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource,JpaVendorAdapter adapter)
{
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean =
new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(adapter);
entityManagerFactoryBean.setPackagesToScan("entity");//扫描实体类包
return entityManagerFactoryBean;
}
JpaVendorAdapter属性用于指明所使用的是哪一个厂商的JPA实现。Spring提供了多个JPA厂商适配器:
- EclipseLinkJpaVendorAdapter
- HIbernateJpaVendorAdapter
- OpenJpaVendorAdapter
- TopLinkJpaVendorAdapter(在Spring3.1中,已经被废弃了)
我们使用Hibernate作为JPA实现。
@Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setGenerateDdl(false);//一些其他属性自行设置
return adapter;
}
声明JPA事务管理
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactoryBean)
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean);
return transactionManager;
}
编写基于JPA的Repository
testDao .java
package test.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import entity.Admin;
@Repository
public class testDao {
@PersistenceUnit
private EntityManagerFactory factory;//@PersistenceUnit会将EntityManagerFactory 注入到testDao中
public Admin find(int id) {
Admin admin = factory.createEntityManager().find(Admin.class, id);
return admin;
}
...
}
但是每个方法都会调用createEntityManager()。而且每次调用Repository方法时,都会创建一个新的EntityManager。
如下展示了借助@PersistenceContext注解注入EntityManager:
package test.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import entity.Admin;
@Repository
public class testDao {
@PersistenceContext
private EntityManager em;
public Admin getAdmin(int id) {
Admin admin = em.find(Admin.class, id);
return admin;
}
...
}
在这个Repository中,直接设置了EntityManager,就没有必要再通过EntityManagerFactory创建EntityManager了。但是你可能会担心EntityManager会有线程安全性的问题,因为EntityManager并不是线程安全的。
@PersistenceContext并不会真正注入EntityManager。它没有将真正的EntityManager设置给Repository,而是给了它一个EntityManager的代理。真正的EntityManager是与当前事务相关联的那一个,如果不存在这样的EntityManager话,就会创建一个新的。这样的话,我们就能始终以线程安全的方式使用实体管理器。
另外,@PersistenceUnit与@PersistenceContext并不是Spring的注解,它们是由JPA规范提供的。为了让Spring理解这些注解,并注入EntityManagerFactory或EntityManager,我们必须要配置Spring的PersistenceAnnotationBeanPostProcessor。如果你已经使用了< context:annotation-config >或< context:component-scan > 那么就不用担心了,因为这些配置元素会自动注册PersistenceAnnotationBeanPostProcessor bean。否则,我们需要显示地注册这个Bean。
@Bean
public PersistenceAnnotationBeanPostProcessor processor()
{
return new PersistenceAnnotationBeanPostProcessor();
}
以上只是学习Spring实战所写的笔记,如有错误,请指正。谢谢