MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)
(本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295)
在上一篇博文的最后,介紹了使用@PostConstruct注解標注StudentDao的init方法,這樣在Spring完成依賴注入后此方法即會被Spring調用,從而也就完成了studentMapper的初始化工作。
如果只有StudentDao一個DAO類,這樣做當然沒有問題。不過在實際應用中,必定存在多個DAO類。每個DAO類的初始化方法,除了傳入的映射器接口類型(如StudentMapper接口)不同外,代碼都是一樣的,也就是說,同樣的代碼會重復多遍。顯然,這種情況是需要避免的。那么更好的做法,是只寫一個初始化方法,就能初始化所有的DAO對象。本文就來探討如何實現這個目標。
初始化方法只想寫一次,就能初始化所有的DAO對象,那么這個初始化方法就只能寫在父類中,在本文的例子中,也就是BaseDao了(當然,@PostConstruct注解是必需的)。在初始化方法中對子類的映射器屬性(如StudentDao的StudentMapper類型的studentMapper屬性)進行初始化,顯然是不現實的,因為父類的方法不能訪問子類的屬性。那么,子類就不能定義自己的映射器屬性,只能是在父類中定義,子類繼承。不過這又遇到一個問題,父類不知道映射器屬性具體的類型——對于StudentDao來說是StudentMapper類型,對于TeacherDao來說就是TeacherMapper類型了。這個問題如何解決呢?也許你已經想到了,我們可以用泛型。把BaseDao定義為泛型類,用泛型來定義映射器變量,子類在繼承BaseDao時,再把泛型指定為自己需要的具體的映射器類型。所以,目前我們的BaseDao代碼如下:
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;@Autowiredpublic void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate){super.setSqlSessionTemplate(sqlSessionTemplate);}}?
相應地,在StudentDao中,應指定泛型T為StudentMapper類型,刪除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 stubint count = this.mapper.add(student);System.out.println("添加了" + count + "行數據。");} }?
最后的關鍵點,同時也是難點,是如何在BaseDao中編寫這個init方法。其實本質上關鍵的地方就是如何獲取子類的映射器類型,有了這個類型,獲取映射器對象就很容易了。這里需要用到反射中有關泛型的知識,init方法的代碼如下:
@PostConstructpublic 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);}?
以上代碼中提到的Type,JAVA API文檔的解釋是“Type 是 Java 編程語言中所有類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型”。Class類是它的實現類,ParameterizedType是它的子接口,表示參數化類型,其實也就是泛型。
仿照StudentDao,我們可以寫出TeacherDao如下(簡單起見,只有一個方法):
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.xml中context:component-scan元素的配置,以及相應Service類和DAO類上的注解。本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295),而測試、執行的類(TestGenericDaoSupport)的代碼如下:
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方法被調用時打印的信息。
??
?????(本文示例工程源代碼下載地址:http://down.51cto.com/data/1975295)
?????? 猛戳這里全面系統地學習MyBatis 3
?????? MyBatis技術交流群:188972810,或掃描二維碼:
?
【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(二)
總結
以上是生活随笔為你收集整理的MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 委内瑞拉的通货膨胀属于哪种类型
- 下一篇: 获取request中的查询参数