MyBatis中如何經過繼承SqlSessionDaoSupport來編寫DAO(二)

(本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295 html

在上一篇博文的最後,介紹了使用@PostConstruct註解標註StudentDaoinit方法,這樣在Spring完成依賴注入後此方法即會被Spring調用,從而也就完成了studentMapper的初始化工做。 java

若是隻有StudentDao一個DAO類,這樣作固然沒有問題。不過在實際應用中,一定存在多個DAO類。每一個DAO類的初始化方法,除了傳入的映射器接口類型(如StudentMapper接口)不一樣外,代碼都是同樣的,也就是說,一樣的代碼會重複多遍。顯然,這種狀況是須要避免的。那麼更好的作法,是隻寫一個初始化方法,就能初始化全部的DAO對象。本文就來探討如何實現這個目標。 spring

初始化方法只想寫一次,就能初始化全部的DAO對象,那麼這個初始化方法就只能寫在父類中,在本文的例子中,也就是BaseDao了(固然,@PostConstruct註解是必需的)。在初始化方法中對子類的映射器屬性(如StudentDaoStudentMapper類型的studentMapper屬性)進行初始化,顯然是不現實的,由於父類的方法不能訪問子類的屬性。那麼,子類就不能定義本身的映射器屬性,只能是在父類中定義,子類繼承。不過這又遇到一個問題,父類不知道映射器屬性具體的類型——對於StudentDao來講是StudentMapper類型,對於TeacherDao來講就是TeacherMapper類型了。這個問題如何解決呢?也許你已經想到了,咱們能夠用泛型。把BaseDao定義爲泛型類,用泛型來定義映射器變量,子類在繼承BaseDao時,再把泛型指定爲本身須要的具體的映射器類型。因此,目前咱們的BaseDao代碼以下: sql

package com.abc.dao.base;
import java.lang.reflect.ParameterizedType;
import javax.annotation.PostConstruct;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class BaseDao<T> extends SqlSessionDaoSupport {
 //保護類型,子類可直接訪問
 protected T mapper;
 
 @Autowired
 public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)
    {
     super.setSqlSessionTemplate(sqlSessionTemplate);
    }
   
}

 

相應地,在StudentDao中,應指定泛型TStudentMapper類型,刪除init方法和studentMapper屬性,並使用繼承過來的mapper屬性代替studentMapper屬性。修改後的StudentDao代碼以下: 編程

package com.abc.dao;
import org.springframework.stereotype.Repository;
import com.abc.dao.base.BaseDao;
import com.abc.domain.Student;
import com.abc.mapper.StudentMapper;
@Repository
public class StudentDao extends BaseDao<StudentMapper>{
 
 public Student getById(int id)
 {
  return this.mapper.getById(id);
 }
 
 public void deleteById(int id)
 {
  int count = this.mapper.delete(id);
  System.out.println("刪除了" + count + "行數據。");
 }
 
 public void update(Student student)
 {
  int count = this.mapper.update(student);
  System.out.println("修改了" + count + "行數據。");
 }
 public void add(Student student) {
  // TODO Auto-generated method stub
  int count = this.mapper.add(student);
  System.out.println("添加了" + count + "行數據。");
 }
}

 

最後的關鍵點,同時也是難點,是如何在BaseDao中編寫這個init方法。其實本質上關鍵的地方就是如何獲取子類的映射器類型,有了這個類型,獲取映射器對象就很容易了。這裏須要用到反射中有關泛型的知識,init方法的代碼以下: 數組

 @PostConstruct
 public void init()
 {
  //在init方法被經過子類(如StudentDao)的對象被調用時,this
  //指代的是子類的對象,this.getClass()返回表明子類的Class對象,
  //再接着調用getGenericSuperclass()方法,能夠返回表明子類的直接
  //超類(也就是BaseDao類)的Type對象。由於它是泛型,所以可強制類型
  //轉換爲ParameterizedType類型,再調用getActualTypeArguments()
  //方法,可得到子類給泛型指定的實際類型的數組。由於這裏只有一個泛型
  //參數,因此取數組的第0個元素,即爲子類的映射器類型。變量mapperType
  //表明子類的映射器類型。
  @SuppressWarnings("unchecked")
  Class<T> mapperType = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  System.out.println("初始化..." + "   " + mapperType.getName());
  //初始化映射器屬性
  this.mapper = this.getSqlSession().getMapper(mapperType);
 }

 

以上代碼中提到的TypeJAVA API文檔的解釋是「Type Java 編程語言中全部類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型」。Class類是它的實現類,ParameterizedType是它的子接口,表示參數化類型,其實也就是泛型。 mybatis

仿照StudentDao,咱們能夠寫出TeacherDao以下(簡單起見,只有一個方法): app

package com.abc.dao;
import org.springframework.stereotype.Repository;
import com.abc.dao.base.BaseDao;
import com.abc.domain.Student;
import com.abc.domain.Teacher;
import com.abc.mapper.StudentMapper;
import com.abc.mapper.TeacherMapper;
@Repository
public class TeacherDao extends BaseDao<TeacherMapper>{
 
 public Teacher getById(int id)
 {
  return this.mapper.getById(id);
 }
 
}

 

Spring會把這兩個DAO類的對象注入到相應的Service組件中(具體請參見源代碼中Spring的主配置文件applicationContext.xmlcontext:component-scan元素的配置,以及相應Service類和DAO類上的註解。本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295),而測試、執行的類(TestGenericDaoSupport)的代碼以下: dom

package com.demo;
import org.springframework.context.ApplicationContext;
import com.abc.service.StudentService;
import com.abc.service.TeacherService;
import com.abc.domain.Student;
import com.abc.domain.Teacher;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGenericDaoSupport {
 private static ApplicationContext ctx;
 static {
  // 在類路徑下尋找spring主配置文件,啓動spring容器
  ctx = new ClassPathXmlApplicationContext(
    "classpath:/applicationContext.xml");
 }
 public static void main(String[] args) {
  // 從Spring容器中請求服務組件
  StudentService studentService = (StudentService) ctx
    .getBean("studentService");
  TeacherService teacherService = (TeacherService) ctx
    .getBean("teacherService");
  studentService.deleteById(11);
  Teacher teacher = teacherService.getById(1);
  System.out.println("查詢到的教師的姓名:" + teacher.getName());
 }
}

 

執行結果以下,注意紅框內init方法被調用時打印的信息。 編程語言

wKioL1S2KWyjiTm9AAh_s0LRxlQ541.jpg

  

     (本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295

       猛戳這裏全面系統地學習MyBatis 3

       MyBatis技術交流羣:188972810,或掃描二維碼:

wKioL1SaztmBchKiAADsv4YAWBY259.jpg


 

【MyBatis學習筆記】系列之預備篇一:ant的下載與安裝

【MyBatis學習筆記】系列之預備篇二:ant入門示例

【MyBatis學習筆記】系列之一:MyBatis入門示例

【MyBatis學習筆記】系列之二:MyBatis增刪改示例

【MyBatis學習筆記】系列之三:MyBatis的association示例

【MyBatis學習筆記】系列之四:MyBatis association的兩種形式

【MyBatis學習筆記】系列之五:MyBatis與Spring集成示例

【MyBatis學習筆記】系列之六:MyBatis與Spring集成示例續

【MyBatis學習筆記】系列之七:MyBatis一對多雙向關聯

【MyBatis學習筆記】系列之八:MyBatis MapperScannerConfigurer配置

【MyBatis學習筆記】系列之九:MyBatis collection的兩種形式

【MyBatis學習筆記】系列之十:MyBatis日誌之Log4j示例

【MyBatis學習筆記】系列之十一:MyBatis多參數傳遞之註解方式示例

【MyBatis學習筆記】系列之十二:MyBatis多參數傳遞之默認命名方式示例

【MyBatis學習筆記】系列之十三:MyBatis多參數傳遞之Map方式示例

【MyBatis學習筆記】系列之十四:MyBatis中的N+1問題

【MyBatis學習筆記】系列之十五:MyBatis多參數傳遞之混合方式

【MyBatis學習筆記】系列之十六:Spring聲明式事務管理示例

【MyBatis學習筆記】系列之十七:MyBatis多對多保存示例

【MyBatis學習筆記】系列之十八:MyBatis多對多關聯查詢示例

【MyBatis學習筆記】系列之十九:如何在MyBatis-3.2.7中使用Log4j2 rc2

MyBatis中如何經過繼承SqlSessionDaoSupport來編寫DAO(一)

MyBatis中如何經過繼承SqlSessionDaoSupport來編寫DAO(二)

相關文章
相關標籤/搜索