1. 程式人生 > >spring+mybatis通用dao層、service層的一些個人理解與實現

spring+mybatis通用dao層、service層的一些個人理解與實現

1、現在的絕大多數web應用,通常都以action、service、dao三層去組織程式碼,這樣劃分結構很清晰,分工明確

2、一般情況下,我們會把事務控制在service層。

3、action和dao層,會使用一些框架技術。比如action層可能選擇有springmvc、struts等,dao層有hibernate、mybatis等選擇,所以action的dao有可能遂根據情況變化,而service層關注業務邏輯,業務程式碼都是自己完成的,程式碼對自己是透明的。

基於1,我們的每個業務,可能都需要這三層程式碼,也就是因為一個很簡單的業務,我們會寫dao層及實現,service層及實現,action層,這樣會造成很多的類。所以最好做到dao層必須通用,service層絕大部分通用,這樣就會減少大量的類。

基於2,我們應把業務邏輯寫在service層,這樣才能控制住事務。例如我們的一個業務:刪除A記錄,插入B記錄(需要在一個事務裡進行),如果我們把這個業務邏輯寫在了action層,我們再action層呼叫刪除A的service,然後再呼叫插入B的service,如果說插入B失敗了,那我們刪除A這個操作將不能回滾,因為事務控制在了service層,這樣寫已不是一個事務。刪除A操作的service已經完成,事務已經提交了,插入B的操作在另外的事務裡執行。根據需要,業務邏輯儘量放在service層。通過配置spring事務控制的傳播行為,在service層可以達到大部分的業務事務要求,而不需另加一層。

基於3,我們更應該把與業務相關的程式碼移至service層,如果service層的事務不容易控制了,可以增加額外的support層(個人理解,其實還是業務邏輯層)協助控制事務。這主要發生在我們把整個業務邏輯放在了service的一個方法,而這個方法以及呼叫的方法的事務配置為required(或其他),但業務的部分操作需要在不同的事務中進行,我們不想寫另外的方法,也不想去更改事務配置,所以引入support層(或許你說可以把這種邏輯向action層移動,在action層處理,但記住我們的前提,action的框架是會變的,我們想盡量做到更改action層時,更簡單。而且從分工來說,action層應該只關注檢視邏輯,個人自掃門前雪,休管他人瓦上霜)。support層當然不是隻為處理這種事務問題的,我把它定義為業務處理時需要的一些輔助層,可以協助處理業務,比如剛才說的事務問題,還有可以提供工具類支援等。 

對於dao層,應該只關注資料庫連線執行結果封裝這些事。

我們的通用,是基於以上的分析結論進行,下面貼上程式碼:

通用dao層:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.dao;  
  2. import java.io.Serializable;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import com.wls.websvn.support.Page;  
  6. publicinterface CommonDao {  
  7.     /** 
  8.      *  
  9.      * 增加一個實體 
  10.      * @param pojo 
  11.      * @return 影響的行數 0失敗,1成功 
  12.      */
  13.     public <T extends Serializable> int save(T pojo);  
  14.     /** 
  15.      *  
  16.      * 通過id刪除實體 
  17.      *  
  18.      * @param clazz 
  19.      * @param id 
  20.      * @return 
  21.      */
  22.     public <T extends Serializable> int deleteById(Class<T> clazz,  
  23.             Serializable id);  
  24.     /** 
  25.      *  
  26.      * 通過主鍵獲取實體 
  27.      *  
  28.      * @param clazz 
  29.      * @param id 
  30.      * @return 
  31.      */
  32.     public <T extends Serializable> T getById(Class<T> clazz, Serializable id);  
  33.     /** 
  34.      *  
  35.      * 查詢所有實體 
  36.      *  
  37.      * @param clazz 
  38.      * @return 
  39.      */
  40.     public <T extends Serializable> List<T> listAll(Class<T> clazz);  
  41.     /** 
  42.      *  
  43.      * 分頁查詢 
  44.      *  
  45.      * @param clazz 
  46.      * @param p 
  47.      * @return 
  48.      */
  49.     public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,Page<T> p,String[]attrs,Object[]values);  
  50.     /** 
  51.      *  
  52.      * 分頁查詢時,用來統計總條數 
  53.      *  
  54.      * @param clazz 
  55.      * @param attrs 
  56.      * @param values 
  57.      * @return 
  58.      */
  59.     public <T extends Serializable> int pageCount(Class<T> clazz,String[]attrs,Object[]values);  
  60.     /** 
  61.      *  
  62.      * 統計總條數 
  63.      *  
  64.      * @param clazz 
  65.      * @return 
  66.      */
  67.     public <T extends Serializable> int countAll(Class<T> clazz);  
  68.     /** 
  69.      *  
  70.      * 指定查詢使用的命名sql,查詢結果封裝成map 
  71.      *  
  72.      * @param statment 
  73.      * @param paraMap 
  74.      * @return 
  75.      */
  76.     List<Map<String,Object>>  selectMap(String statment, Map<String, Object> paraMap);  
  77. }  

dao層實現:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.dao.mybatis;  
  2. import java.io.Serializable;  
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6. import javax.annotation.Resource;  
  7. import org.apache.commons.lang.StringUtils;  
  8. import org.apache.ibatis.session.SqlSessionFactory;  
  9. import org.springframework.stereotype.Repository;  
  10. import com.wls.websvn.dao.CommonDao;  
  11. import com.wls.websvn.support.Page;  
  12. @Repository("commonDao")  
  13. publicclass CommonDaoImpl implements CommonDao {  
  14.     @Resource(name = "sqlSessionFactory")  
  15.     protected SqlSessionFactory sqlSessionFactory;  
  16.     protected <T> String getStatement(Class<T> clazz, String prefix) {  
  17.         String entityName = clazz.getSimpleName();  
  18.         if (entityName.endsWith("Model")) {  
  19.             entityName = entityName.substring(0, entityName.length() - 5);  
  20.         }  
  21.         entityName = prefix + entityName;  
  22.         return entityName;  
  23.     }  
  24.     @Override
  25.     public <T extends Serializable> int save(T pojo) {  
  26.         String statement = getStatement(pojo.getClass(), "insert");  
  27.         return sqlSessionFactory.openSession().insert(statement, pojo);  
  28.     }  
  29.     @Override
  30.     public <T extends Serializable> int deleteById(Class<T> clazz,  
  31.             Serializable id) {  
  32.         String statement = getStatement(clazz, "idDelete");  
  33.         return sqlSessionFactory.openSession().update(statement, id);  
  34.     }  
  35.     @Override
  36.     public <T extends Serializable> T getById(Class<T> clazz, Serializable id) {  
  37.         String statement = getStatement(clazz, "idGet");  
  38.         return sqlSessionFactory.openSession().selectOne(statement, id);  
  39.     }  
  40.     @Override
  41.     public <T extends Serializable> List<T> listAll(Class<T> clazz) {  
  42.         String statement = getStatement(clazz, "list");  
  43.         return sqlSessionFactory.openSession().selectList(statement);  
  44.     }  
  45.     /** 
  46.      *  
  47.      * 組裝排序串 
  48.      *  
  49.      * @param sort 
  50.      * @param order  最好將order定義成列舉型別,傳遞一個列舉陣列 
  51.      * @return 
  52.      */
  53.     private String genOrderStr(String sort, String order) {  
  54.         String orderBy = "";  
  55.         if (StringUtils.isNotBlank(sort)) {  
  56.             if (StringUtils.isNotBlank(order)) {  
  57.                 StringBuilder sb = new StringBuilder(" ");  
  58.                 String[] aSort = sort.split(",");  
  59.                 String[] aOrder = order.split(",");  
  60.                 for (int i = 0; i < aSort.length; i++) {  
  61.                     sb.append(aSort[i]).append(" ");  
  62.                     if (i < aOrder.length) {  
  63.                         sb.append(aOrder[i]).append(",");  
  64.                     } else {  
  65.                         sb.append("ASC").append(",");  
  66.                     }  
  67.                 }  
  68.                 // 刪除最後一個,
  69.                 sb.deleteCharAt(sb.length() - 1);  
  70.                 orderBy = sb.toString();  
  71.             } else {  
  72.                 orderBy = " order by " + sort;  
  73.             }  
  74.         }  
  75.         return orderBy;  
  76.     }  
  77.     @Override
  78.     public <T extends Serializable> int pageCount(Class<T> clazz,  
  79.             String[] attrs, Object[] values) {  
  80.         Map<String, Object> paraMap = new HashMap<String, Object>();  
  81.         if (values != null && attrs != null) {  
  82.             for (int i = 0; i < values.length; i++) {  
  83.                 if (i < attrs.length) {  
  84.                     paraMap.put(attrs[i], values[i]);  
  85.                 }  
  86.             }  
  87.         }  
  88.         String statement = getStatement(clazz, "pageCount");  
  89.         Object o = sqlSessionFactory.openSession().selectOne(statement,paraMap);  
  90.         return Integer.parseInt(o.toString());  
  91.     }  
  92.     @Override
  93.     public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,  
  94.             Page<T> p, String[] attrs, Object[] values) {  
  95.         int startNum = p.getStartIndex();  
  96.         int pageSize = p.getPageSize();  
  97.         String orderBy = genOrderStr(p.getSort(), p.getOrder());  
  98.         Map<String, Object> paraMap = new HashMap<String, Object>();  
  99.         if (values != null && attrs != null) {  
  100.             for (int i = 0; i < values.length; i++) {  
  101.                 if (i < attrs.length) {  
  102.                     paraMap.put(attrs[i], values[i]);  
  103.                 }  
  104.             }  
  105.         }  
  106.         String statement = getStatement(clazz, "page");  
  107.         p.setTotal(pageCount(clazz, attrs, values));  
  108.         paraMap.put("startNum", startNum);  
  109.         paraMap.put("pageSize", pageSize);  
  110.         paraMap.put("endNum", startNum + pageSize);  
  111.         paraMap.put("orderBy", orderBy);  
  112.         List<T> list = sqlSessionFactory.openSession().selectList(statement,  
  113.                 paraMap);  
  114.         p.setData(list);  
  115.         return p;  
  116.     }  
  117.     @Override
  118.     public <T extends Serializable> int countAll(Class<T> clazz) {  
  119.         String statement = getStatement(clazz, "count");  
  120.         Object o = sqlSessionFactory.openSession().selectOne(statement);  
  121.         return Integer.parseInt(o.toString());  
  122.     }  
  123.     @Override
  124.     public List<Map<String, Object>> selectMap(String statement,  
  125.             Map<String, Object> paraMap) {  
  126.         return sqlSessionFactory.openSession().selectList(statement, paraMap);  
  127.     }  
  128. }  
support: [java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.support;  
  2. import java.util.List;  
  3. publicclass Page<T> {  
  4.     /** 
  5.      * 頁碼 
  6.      */
  7.     privateint page = 1;  
  8.     /** 
  9.      * 每頁條數 
  10.      */
  11.     privateint pageSize = 10;  
  12.     /** 
  13.      * 總記錄數 
  14.      */
  15.     privatelong total;  
  16.     /** 
  17.      * 排序列 
  18.      */
  19.     private String sort;  
  20.     /** 
  21.      * 升降序 
  22.      */
  23.     private String order;  
  24.     /** 
  25.      * 單頁資料 
  26.      */
  27.     private List<T> data;  
  28.     public Page() {  
  29.         this.page = 1;  
  30.         this.pageSize = 10;  
  31.     }  
  32.     public Page(int page, int pageSize) {  
  33.         this.page = page;  
  34.         this.pageSize = pageSize;  
  35.     }  
  36.     /** 
  37.      * 獲取page值 
  38.      * @return int page. 
  39.      */
  40.     publicint getPage() {  
  41.         return page;  
  42.     }  
  43.     /** 
  44.      * 設定page值 
  45.      * @param page The page to set. 
  46.      */
  47.     publicvoid setPage(int page) {  
  48.         this.page = page;  
  49.     }  
  50.     /** 
  51.      * 獲取pageSize值 
  52.      * @return int pageSize. 
  53.      */
  54.     publicint getPageSize() {  
  55.         return pageSize;  
  56.     }  
  57.     /** 
  58.      * 設定pageSize值 
  59.      * @param pageSize The pageSize to set. 
  60.      */
  61.     publicvoid setPageSize(int pageSize) {  
  62.         this.pageSize = pageSize;  
  63.     }  
  64.     /** 
  65.      * 獲取data值 
  66.      * @return List<T> data. 
  67.      */
  68.     public List<T> getData() {  
  69.         return data;  
  70.     }  
  71.     /** 
  72.      * 設定data值 
  73.      * @param data The data to set. 
  74.      */
  75.     publicvoid setData(List<T> data) {  
  76.         this.data = data;  
  77.     }  
  78.     /** 
  79.      * 獲取total值 
  80.      * @return long total. 
  81.      */
  82.     publiclong getTotal() {  
  83.         return total;  
  84.     }  
  85.     /** 
  86.      * 設定total值 
  87.      * @param total The total to set. 
  88.      */
  89.     publicvoid setTotal(long total) {  
  90.         this.total = total;  
  91.     }  
  92.     public String getSort() {  
  93.         return sort;  
  94.     }  
  95.     publicvoid setSort(String sort) {  
  96.         this.sort = sort;  
  97.     }  
  98.     /** 
  99.      * @return the order 
  100.      */
  101.     public String getOrder() {  
  102.         return order;  
  103.     }  
  104.     /** 
  105.      * @param order the order to set 
  106.      */
  107.     publicvoid setOrder(String order) {  
  108.         this.order = order;  
  109.     }  
  110.     /** 
  111.      *  
  112.      * 獲取分頁開始的位置 
  113.      *  
  114.      * @return 
  115.      */
  116.     publicint getStartIndex() {  
  117.         if(page<1){  
  118.             return0;  
  119.         }  
  120.         return (page - 1) * pageSize;  
  121.     }  
  122. }  
service層: [java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.service;  
  2. import java.io.Serializable;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import com.wls.websvn.support.Page;  
  6. publicinterface CommonService {  
  7.     /** 
  8.      *  
  9.      * 增加一個實體 
  10.      * @param pojo 
  11.      * @return 影響的行數 0失敗,1成功 
  12.      */
  13.     public <T extends Serializable> int save(T pojo);  
  14.     /** 
  15.      *  
  16.      * 通過id刪除實體 
  17.      *  
  18.      * @param clazz 
  19.      * @param id 
  20.      * @return 
  21.      */
  22.     public <T extends Serializable> int deleteById(Class<T> clazz,  
  23.             Serializable id);  
  24.     /** 
  25.      *  
  26.      * 通過主鍵獲取實體 
  27.      *  
  28.      * @param clazz 
  29.      * @param id 
  30.      * @return 
  31.      */
  32.     public <T extends Serializable> T getById(Class<T> clazz, Serializable id);  
  33.     /** 
  34.      *  
  35.      * 查詢所有實體 
  36.      *  
  37.      * @param clazz 
  38.      * @return 
  39.      */
  40.     public <T extends Serializable> List<T> listAll(Class<T> clazz);  
  41.     /** 
  42.      *  
  43.      * 分頁查詢 
  44.      *  
  45.      * @param clazz 
  46.      * @param p 
  47.      * @return 
  48.      */
  49.     public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,Page<T> p,String[]attrs,Object[]values);  
  50.     /** 
  51.      *  
  52.      * 分頁查詢時,用來統計總條數 
  53.      *  
  54.      * @param clazz 
  55.      * @param attrs 
  56.      * @param values 
  57.      * @return 
  58.      */
  59.     public <T extends Serializable> int pageCount(Class<T> clazz,String[]attrs,Object[]values);  
  60.     /** 
  61.      *  
  62.      * 統計總條數 
  63.      *  
  64.      * @param clazz 
  65.      * @return 
  66.      */
  67.     public <T extends Serializable> int countAll(Class<T> clazz);  
  68.     /** 
  69.      *  
  70.      * 指定查詢使用的命名sql,查詢結果封裝成map 
  71.      *  
  72.      * @param statment 
  73.      * @param paraMap 
  74.      * @return 
  75.      */
  76.     List<Map<String,Object>>  selectMap(String statment, Map<String, Object> paraMap);  
  77. }  
service層實現: [java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.service.impl;  
  2. import java.io.Serializable;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import javax.annotation.Resource;  
  6. import org.springframework.stereotype.Service;  
  7. import com.wls.websvn.dao.CommonDao;  
  8. import com.wls.websvn.service.CommonService;  
  9. import com.wls.websvn.support.Page;  
  10. /** 
  11.  *  
  12.  * @author weilisky 
  13.  * 考慮將來可能切換到hibernate或其他框架的情況,儘量的將切換時不用變的程式碼移到service層。 
  14.  * 將切換時可能會變更的程式碼放在了dao層 
  15.  * 
  16.  */
  17. @Service("commonService")  
  18. publicclass CommonServiceImpl implements CommonService {  
  19.     @Resource(name = "commonDao")  
  20.     protected CommonDao commonDao;  
  21.     @Override
  22.     public <T extends Serializable> int save(T pojo) {  
  23.         return commonDao.save(pojo);  
  24.     }  
  25.     @Override
  26.     public <T extends Serializable> int deleteById(Class<T> clazz,  
  27.             Serializable id) {  
  28.         return commonDao.deleteById(clazz, id);  
  29.     }  
  30.     @Override
  31.     public <T extends Serializable> T getById(Class<T> clazz, Serializable id) {  
  32.         return commonDao.getById(clazz, id);  
  33.     }  
  34.     @Override
  35.     public <T extends Serializable> List<T> listAll(Class<T> clazz) {  
  36.         return commonDao.listAll(clazz);  
  37.     }  
  38.     @Override
  39.     public <T extends Serializable> int pageCount(Class<T> clazz,  
  40.             String[] attrs, Object[] values) {  
  41.         return commonDao.pageCount(clazz, attrs, values);  
  42.     }  
  43.     @Override
  44.     public <T extends Serializable> Page<T> pageSelect(Class<T> clazz,  
  45.             Page<T> p, String[] attrs, Object[] values) {  
  46.         return commonDao.pageSelect(clazz, p, attrs, values);  
  47.     }  
  48.     @Override
  49.     public <T extends Serializable> int countAll(Class<T> clazz) {  
  50.         return commonDao.countAll(clazz);  
  51.     }  
  52.     @Override
  53.     public List<Map<String, Object>> selectMap(String statement,  
  54.             Map<String, Object> paraMap) {  
  55.         return commonDao.selectMap(statement, paraMap);  
  56.     }  
  57. }  
通過泛型,這裡做到了service層可以查詢各種實體。如果實體的操作簡單,完全沒有必要再寫service層,commonService應該就夠用,當然你還可以增加CommonService增加方法(當然可能需要同步增加CommonDao),使其更通用。

如果CommonService不夠用了,你的介面應該繼承CommonService介面,你的實現應該繼承CommonServiceImpl實現,然後根據需要override其中的一些方法。

需要說明一下,我們把protected <T> String getStatement(Class<T> clazz, String prefix)放置在dao層,因為它並不是業務邏輯的一部分,而且對於mybaits框架,你需要這個方法,而對應hibenate你可能根本不需要(或則可以把這個方法重構到另外的一個介面)。

最後附上例子model和mapping:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.model;  
  2. import java.io.Serializable;  
  3. import java.util.Date;  
  4. publicclass BaseModel implements Serializable{  
  5.     /** 
  6.      *  
  7.      */
  8.     privatestaticfinallong serialVersionUID = -459530011111182045L;  
  9.     protected Long id;  
  10.     protected Date createDate;  
  11.     public Long getId() {  
  12.         return id;  
  13.     }  
  14.     publicvoid setId(Long id) {  
  15.         this.id = id;  
  16.     }  
  17.     public Date getCreateDate() {  
  18.         return createDate;  
  19.     }  
  20.     publicvoid setCreateDate(Date createDate) {  
  21.         this.createDate = createDate;  
  22.     }  
  23. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.wls.websvn.model;  
  2. publicclass UserModel extends BaseModel {  
  3.     /** 
  4.      *  
  5.      */
  6.     privatestaticfinallong serialVersionUID = 5715947400419117755L;  
  7.     //登入名
  8.     private String userName;  
  9.     //真實姓名
  10.     private String realName;  
  11.     //密碼
  12.     private String userPwd;  
  13.     private String phoneNum;  
  14.     public String getUserName() {  
  15.         return userName;  
  16.     }  
  17.     publicvoid setUserName(String userName) {  
  18.         this.userName = userName;  
  19.     }