DAO開發
注:
(1)以下兩者都需在Spring XML配置文件中,註冊Bean(實現類)來依賴注入SessionFactory.
(2.1)Spring 中進行事務管理的通常方式是利用AOP(面向切片編程)的方式,爲普通java類封裝事務控制,它是通過動態代理實現的,由於接口是
延遲實例化的, spring在這段時間內通過攔截器,加載事務切片。原理就是這樣,具體細節請參考jdk中有關動態代理的文檔。本文主要講解
如何在spring中進行事務控制。
(2.2)動態代理的一個重要特徵是,它是針對接口的,所以我們的DAO要通過動態代理來讓spring接管事務,就必須在DAO前面抽象出一個接口. 當然
如果沒有這樣的接口,那麼spring會使用CGLIB來解決問題,但這不是spring推薦的方式.
(一)直接使用Hibernate API (不推薦使用)
public class DaoImp implate Dao{
private SessionFactory sessionFactory;
private static String hql = "from User u where u.username=? ";
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory=sessionFactory;
}
public boolean isValidUser(String username) {
try{
List userList = sessionFactory.getCurrentSession().creatQuery(hql).setParameter(0,username).list();
if (userList.size() > 0) {
return true;
} catch (HibernateException ex){
throw converHibernaterAccessException(ex);
}
}
}
優點:與Spring框架完全分離
缺點:(1)無法使用Spring框架封裝所提供的額外功能.如,直接使用Hibernate API 需用try...catch()處理HibernateException異常.
(2)需在實現類中加入setSessionFactory(SessionFactory sessionFactory)屬性,接收依賴注入的SessionFactory.
(二)繼承 Spring 的 HibernateDaoSupport 使用 HibernateTemplate (不推薦使用getSession())
public class DaoImp extend HibernateDaoSupport implates Dao{
//private SessionFactory sessionFactory;
private static String hql = "from User u where u.username=? ";
//public void setSessionFactory(SessionFactory sessionFactory){
// this.sessionFactory=sessionFactory;
//}
public boolean isValidUser(String username) {
// try{
// List userList = sessionFactory.getCurrentSession().creatQuery(hql).setParameter(0,username).list();
List userList = getHibernateTemplate().find(hql,username);
if (userList.size() > 0) {
return true;
// } catch (HibernateException ex){
// throw converHibernaterAccessException(ex);
// }
}
public boolean isValidUser(String username,String password) throw DataAccessException {
Session session = getSession(); //不推薦使用,用完後需手動關閉
String[] userlist=new String[2];
userlist[0]=username;
userlist[1]=password;
try{
List userList = session.find(hql,userlist); //Hibernate語句;
session.close();
if (userList.size() > 0) {
return true;
} catch (HibernateException ex){
throw converHibernaterAccessException(ex);
}
}
}
特點:對HibernateTemplate沒有提供的功能,可以直接調用HibernateDaoSuppor對象的getSession()方法(極其不推薦使用)得到Session對象實例用try{ Hibernate API }catch (HibernateException ex )操作.
(三)對 HibernateTemplate 沒有提供的功能, 還可以用HibernateCallback 回調的方法管理數據庫. (極其推薦)
/**
* 使用 hql 語句進行操作
* @param hql HSQL 查詢語句
* @param offset 開始取數據的下標
* @param length 讀取數據記錄數
* @return List 結果集
*/
public List getListForPage ( final String hql , final int offset , final int length ) {
List list = getHibernateTemplate().executeFind ( new HibernateCallback ( ) {
public Object doInHibernate ( Session session ) throws HibernateException, SQLException {
Query query = session.createQuery ( hql ) ;
query.setFirstResult ( offset ) ;
query.setMaxResults ( length ) ;
List list = query.list ( ) ;
return list ;
}
}) ;
return list ;
}
spring+hibernate架構中Dao訪問數據庫的幾種方法
在spring+hibernate的架構中,訪問數據庫有幾種方法,按spring依賴注入來區分有3種,在這之前先再來了解一下spring的依賴注入,spring主要的兩大核心就是IOC(控制反轉)和AOP(面向切面編程),控制反轉就是控制轉移,從以往由Bean去控制要調用的接口或其他資源轉移給容器,由容器來尋找並實例化要調用的接口,也可以解釋成依賴注入,即在spring配置文件中把要調用的接口、設置、構造子配置給Bean。這邊是以依賴注入來區分爲sessionFactory、hibernateTemplate、jdbcTemplate,本質上劃分只有hibernateTemplate和jdbcTemplate這兩種。1、注入sessionFactory
在spring配置文件中,對Dao注入sessionFactory,即:
<bean id="classDao" class="cn.jmu.data.dao.impl.ClassImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
這邊sessionFactory依賴注入的不是給Dao層中的類,而是給HibernateDaoSupport,見spring源文件org/springframework/orm/hibernate3/support/HibernateDaoSupport.java裏面,就有sessionFactory的set、get操作:public final void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory);//通過sessionFactory來生成hibernateTemplate
}public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
}所以在Dao層中類繼承HibernateDaoSupport,即可通過this.getHibernateTemplate()來對數據庫進行操作,
更新數據:this.getHibernateTemplate().update(bo);
查詢數據:this.getHibernateTemplate().find(bo);
添加數據:this.getHibernateTemplate().save(bo) ;
刪除數據:this.getHibernateTemplate().delete(bo);
從上面可以看出spring+hibernate的強大威力,存取數據不用像以往jdbc那樣,要寫一大串try,catch語句,還要連接數據庫,用完再關閉數據庫連接,而用一條語句就可以搞定。
這裏sessionFactory由spring自動自動連接、關閉,當然你也可以手動來連接、關閉,如下面採用的方法:
Session session=this.getHibernateTemplate().getSessionFactory().openSession();
Transaction tx=session.beginTransaction();
/*--------------查詢數據------------------------*/
String str="hql";
Query query=session.createQuery(str);
List list=query.list();
/*--------------刪除數據------------------------*/
session.load(bo,ID);
session.delete(bo);
/*--------------添加數據------------------------*/
session.save(bo);
/*--------------修改數據-----------------------*/
session.load(bo,ID);
session.update(bo);
/*--------------end---------------------------*/
tx.commit();
session.close();
初學Hebernate的人對這些代碼應該很熟悉,沒有spring提供hibernateTemplate,在單單的Hibernate中就得用這種方面去訪問存取數據了。
2、注入hibernateTemplate
這種方法本質跟上面注入sessionFactory一樣,只不過再進行一層包裝,這樣最大的好處就是Dao中的類就不用再繼承HibernateDaoSupport(在java中是單繼承的,這唯一一次的繼承就被HibernateDaoSupport剝奪去就豈不可惜?)不過在這之前要先要配置好hibernateTemplate,即:
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
再對要用到hibernateTemplate的Dao進行注入依賴,即:
<bean id="ClassDao" class="cn.jmu.data.dao.impl.ClassImpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
在Dao層的類就要添加hibernateTemplate對象,來對應配置文件中所注入的依賴:
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
hibernateTemplate對數據的增刪查給就跟上面的一樣,即:
更新數據:hibernateTemplate().update(bo);
查詢數據:hibernateTemplate().find(bo);
添加數據:hibernateTemplate().save(bo) ;
刪除數據:hibernateTemplate().delete(bo);
3、注入jdbcTemplate如果對以前的jdbc的SQL還念念不忘,又對Hibernate的HQL沒有好感的話,就可以採用jdbcTemplate來增刪查改數據庫了。在某些情況下采用jdbcTemplate還比較方便,甚至還能提高查詢效率。在這之前也要像注入hibernateTemplate那樣,先配置好jdbcTemplate,<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>如果jdbcTemplate和hibernateTemplate配置時都指向同一個dataSource,那就可以共用同一個事務了。再對要用到jdbcTemplate的Dao進行注入依賴,即:<bean id="classDao" class="cn.jmu.data.dao.impl.ClassImpl">
<property name="jdbctemplate">
<ref bean="jdbcTemplate" />
</property>
</bean>在Dao層的類就要添加jdbctemplate對象,來對應配置文件中所注入的依賴:protected JdbcTemplate jdbctemplate;public JdbcTemplate getJdbctemplate() {
return jdbctemplate;
}public void setJdbctemplate(JdbcTemplate jdbctemplate) {
this.jdbctemplate = jdbctemplate;
}現在就可以通過jdbctemplate存取數據了:查詢數據:
/*------------查詢單列-------------------*/
String SQL= "select name from table";
List list= jdbctemplate.queryForList(SQL);
/*------------查詢多列------------------*/
Hashtable hash = new Hashtable();
jdbctemplate.query(SQL,
new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
hash.put(rs.getString(1),rs.getString(2));
}
});
/*----------查詢後填充到vo裏面-----------*/
String SQL="select * from table where id=?";
String[] obj = new String[1];
obj[0] = N;
VO vo= new VO(); //這邊暫用VO來表示,VO的本質不是這樣的
List list = jdbcTemplate.query(SQL,obj,vo);
VO要實現RowMapper接口中的mapRow方法,把結果集填充到bo裏面:class VO implements RowMapper{
public Object mapRow(ResultSet rs, int index) throws SQLException {
Bo bo = new Bo();
bo.setProperty(rs.getString(1));
bo.setProperty(rs.getString(2));
bo.setProperty(rs.getString(3));
return bo;
}
}/*----------------更新數據------------------*/
String SQL="update table set name=?";
String[] obj=new String[1];
obj[1]="new name";
jdbcTemplate.update(SQL,obj);
/*----------------刪除數據------------------*/
String SQL="delete from table where id='"+ID+"'";
jdbcTemplate.execute(SQL);
/*----------------添加數據------------------*/
String SQL="insert into table (property1,property2) values ('"+property1+"','"+property1+"')";
jdbcTemplate.execute(SQL);