1.spring提供的DAO支持
spring提供了一系列抽象类,这些抽象类将被作为应用中DAO实现类的父类。通过继承这些抽象类,spring简化了DAO的开发步骤,能以一致的方式使用数据库访问技术。
spring提供了一致的异常抽象,将原有的checked异常转换包装成Runtime异常,因而,编码时无须捕获各种技术中特定的异常。spring DAO体系中的异常,都继承DataAccessException,而DataAccessException异常时Runtime的,无须显示捕获。
2.管理Hibernate的SessionFactory
当通过Hibernate进行持久层访问时,必须先获得SessionFactory对象,它是单个数据库映射关系编译后的内存镜像。在大部分情况下,一个Java EE应用对应一个数据库,即对应一个SessionFactory对象。
spring的IoC容器不仅能以声明式的方式配置SessionFactory实例,也可充分利用IoC容器的作用,为SessionFactory注入数据源引用。
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destory-method="close"
p:driverClass="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost/"
p:user="root"
p:password="0408"
p:maxPoolSize="40"
p:minPoolSize="2"
p:initialPoolSize="2"
p:maxIdleTime="30"
/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="dataSource">
<!-- annotatedClasses用来列出全部持久化类-->
<property name="annotatedClasses">
<list>
<value>com.hyq.domain.Book</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!-- 指定Hibernate的连接方言-->
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQL5InnoDBDialect
</prop>
<!--是否根据Hibernate映射创建数据表-->
<prop key="hibernate.hbm2ddl.auto">
update
</prop>
</props>
</property>
</bean>
一旦在spring的IoC容器中配置了SessionFactory Bean,它就将随应用的启动而加载,并可以充分利用IoC容器的功能,将SessionFacotry Bean注入任何Bean中,比如DAO组件。一旦DAO组件获得了SessionFactory Bean的引用,它就可以完成实际的数据库访问。
3.实现DAO组件的基类
spring推荐调用SessionFactory的getCurrentSession()方法来获取Hibernate Session,剩下的持久化操作与直接使用Hibernate持久化操作的代码基本相同。
public interface BaseDao<T>{
//根据ID加载实体
T get(Class<T> entityClazz,Serializable id);
//保存实体
Serializable save(T entity);
//更新实体
void update(T entity);
//删除实体
void delete(T entity);
//根据ID删除实体
void delete(Class<T> entityClazz,Serializable id);
//获取实体总数
long findCount(Class<T> entityClazz);
}
public class BaseDaoHibernate4<T> implements BaseDao<T>{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
@SuppressWarnings("unchecked")
public T get(Class<T> entityClazz,Seializable id){
return (T)getSessionFactory().getCurrentSession().get(entityClazz,id);
}
public Serializable save(T entity){
return getSessionFactory().getCurrentSession().save(entity);
}
public void update(T entity){
getSessionFactory.getCurrentSession().saveOrUpdate(entity);
}
public void delete(T entity){
getSessionFactory.getCurrentSession().delete(entity);
}
public void delete(Class<T> entityClazz,Serializable id){
getSessionFactory.getCurrentSession().createQuery("delete" + entityClazz.getSimpleName() + "en where en.id= ?0").setParameter("0",id).executeUpdate();
}
public List<T> findAll(Class<T> entityClazz){
return find("select en from" + entityClazz.getSimpleName() + "en");
}
public long findCount(Class<T> entityClazz){
List<?> l = find("select count(*) from" + entityClazz.getSimpleName());
if(l != null && l.size() == 1){
return (Long)l.get(0);
}
return 0;
}
//根据HQL语句查询实体
@SuppressWarnings("unchecked")
protected List<T> find(String hql){
return (List<T>)getSessionFactory().getCurrentSession().createQuery(hql).list();
}
@SuppressWarnings("unchecked")
protected List<T> find(String hql,Object... params){
Query query = getSessionFactory().getCurrentSession().createQuery(hql);
for(int i = 0,len = params.length;i < len;i++){
query.setParameter(i + "",params[i]);
}
return (List<T>)query.list();
/**
*使用HQL语句进行分页查询操作
*@param hql 需要查询的HQL语句
*@param pageNo 查询第pageNo页的记录
*@param pageSize 每页需要显示的记录数
*@return 当前的所有记录
*/
@SuppressWarnings("unchecked")
protected List<T> findByPage(String hql,int pageNo,int pageSize){
return getSessionFactory().getCurrentSession().createQuery(hql).setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
}
}
/**
* 使用HQL语句进行分页查询操作
* @param hql 需要查询的HQL语句
* @param params 如果hql带占位符参数,params用于传入占位符参数
* @param pageNo 查询第pageNo页的记录
* @param pageSize 每页需要显示的记录数
* @return 当前页的所有记录
*/
@SuppressWarnings("unchecked")
protected List<T> findByPage(String hql,int pageNo,int pageSize,Object... params){
Query query = getSessionFactory().getCurrentSession().createQuery(hql);
for(int i = 0,len = params.length;i < len;i++){
query.setParameter(i + "",params[i]);
}
return query.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
}
}
4.实现DAO组件
public interface BookDao extends BaseDao<Book>{
}
public class BookDaoHibernate4 extends BaseDaoHibernate4<Book> implements BookDao{
}
虽然该接口暂时没有包含任何方法,但程序还是要定义一个这样的接口,因为每个DAO组件出了包含那些通用的CURD方法之外,还可能需要定义一些业务相关的查询方法,这些方法就只能定义在各自的DAO组件内。
5.使用IoC容器组装各种组件
从用户角度来看,用户发出HTTP请求,当MVC框架的控制器组件拦截到用户请求时,将调用系统的业务逻辑组件,业务逻辑组件则调用系统的DAO组件,而DAO组件则依赖于SessionFactory和DataSource等底层组件来实现数据库的访问。
从系统实现角度来看,IoC容器先创建SessionFacotry和DataSource等底层组件,然后将这些底层组件注入给DAO组件,提供一个完整的DAO组件,并将此DAO组件注入给业务逻辑组件,从而提供一个完整的业务逻辑组件,而业务逻辑组件又被注入给控制器组件,控制器组件负责拦截用户请求,并将处理结果呈现给用户—这一系列的衔接,都由spring的IoC容器提供。
当用户发送一个注册请求之后,该请求将被struts2核心控制器拦截->核心控制器调用Action->Action调用业务逻辑组件->业务逻辑组件调用DAO组件->DAO组件调用SessionFactory、Hibernate服务等,当整个过程完成之后,核心控制器就得到了请求被处理的结果,从而根据该结果选择合适的视图资源来生成相应—这就完成了一个请求/相应的全过程。
6.使用声明式事务
spring的事务机制非常优秀,它允许程序员在开发过程中无须理会任何事务逻辑,等到应用开发完成后使用声明式事务来进行统一的事务管理。只需要在配置文件中增加事务控制片段,业务逻辑组件方法就会具有事务性;而且spring的声明式事务支持在不同的事务策略之间可以自由切换。
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionMangaer" p:sessionFactory-ref="sessionFactory"/>
<!--配置事务增强处理Bean,指定事务管理器-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="myPointcut" expression="bean(bookService)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>