Spring整合Hibernate
DataSource
标准化的取得连接的方式
spring连接池
dbcp配置
Hibernate使用Annotation的方式
简单整合
- 1. 先在spring容器里面初始化一个SessionFactory
- 2. 注入需要的连接信息
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="annotatedClasses"> <list> <value>com.bjsxt.model.User</value>
<value>com.bjsxt.model.Log</value>
</list>
</property>
<property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean>
sessionFactory的class并不是hibernate自己的,而是使用的Spring的AnnotationSessionFactoryBean
它里面有很多的属性:
他需要注入的信息有:(也就是这个类中含有的set方法)
1. dataSource 数据源
2. annotateClasses
它需要注入的信息是一个集合,表示哪些实体类上加了注解,需要用到hibernate
3. hibernateProperties
这是一个Properties类型的对象,表示Hibernate的一些属性,比如Hibernate方言等。
上面的例子中是用的注入 annotateClasses这个属性,但是如果类非常多,这个就非常不方便了
我们可以注入 packagesToScan这个属性
<property name="packagesToScan"> <list> <value>com.bjabc.model</value> </list> </property>
然后再在需要的实体类上加上Hibernate需要的注解即可,比如@Entity之类的
这种方式是Annotation的方式,不需要hibernate的配置文件
如果使用xml方式 class="org.springframework.orm.hibernate3.annotation.SessionFactoryBean
而且还有加入一个name = mappingResources value=....hbm.xml的子属性,表示hibernate的配置文件
事务管理
首先要搞清事务的开始和结束
有两种管理方式
- Annotation
- XML
先说说Annotation
首先要在spring的bean.xml中引入annotation驱动
然后把sessionFactory交给事务的txManager管理
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driven transaction-manager="txManager"/>
接下来就是配置需要添加事务管理的类了
比如是加在管理层上
@Transactional(readOnly = true) public class UserServiceImpl implements UserService { public Foo getFoo(String name) { // do something } @Transactional(propagation = Propagation.REQUIRED) public void add(User user) { userDAO.save(user);
} }
那么对于DAO层
public class UserDAOimpl implements UserDAO { private SessionFactory sessionFactory; public void save(User user) { session s = sessionFactory.getCurrentSession(); s.save(user); } }
这里必须要getCurrentSession,就是说这个时候连接已经创建了,不可以再重新create了。
类或者方法上上只需要加入@Transactional 就可以了
但是有很多属性
最要的属性必须要加上的 (不加也一样,默认就是)
propagation = Propagation.REQUIRED
其他的
readOnly = false
表示建立一个readOnly的连接,对于不需要增删改只需要查的动作
有两个好处, 1。 提高性能, 2,防止意外的修改操作
roolBackFor
默认下都是对于runtimeException
XML方式
也就是spring 的AOP方式
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="getUser" read-only="true" /> <tx:method name="add*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
定义一个切面,表示事务,并且加入到相应方法
<aop:config> <aop:pointcut id="bussinessService" expression="execution(public * com.bjsxt.service..*.*(..))" /> <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" /> </aop:config>
然后在类上就不用加那些标记了
实际开发过程中,用的xml方法比较多
因为不用在每个方法上加标记
HibernateTemplate
里面有一种设计模式:Template Method 模板方法
把对sessionFactory的管理交给hibernateTempate
spring的容器里
<bean id="sessionFactory"> ... </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean>
看一下HibernateTempate这个类的源码,可以看到里面有几个属性,需要注入
比如有一个setSessionFactory()方法
而这个类也已经把sessionFactory里的很多方法都封装好了
比如load()方法,save()方法等。
所以在程序里直接调用这些方法就行了
那么在UserDAOimpl里面
就不需要像以前那样有一个sessionFactory对象了
只需要有一个HibernateTemplate对象就可以了,然后通过注入获得这个对象
然后调用这个对象的save()方法等等。
那么它内部的原理是什么呢?
可以看一下 hibernateTemplate.save方法的源码
这个方法的实现过程可以这么理解
所谓模板方法,其实就是说我们之前用sessionFactory在各个DAO中建立连接和断开连接的操作都是一样的,所以每个DAO的开始和结束都差不多i,所以我们定义一个方法,他的开始和结束一样,然后再在中间插入我们自定义的操作就行了。
hibernate可以封装jdbc,jdo,orm等很多中间层的产品
但是有两个相同的封装过程
1. 提供特定的Template
2. 所有的异常会封装从成DataAcessExceptin
这是一个runtime异常,会回滚
callback 回调/钩子