MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)

简介:

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

在上一篇博文的最后,介绍了使用@PostConstruct注解标注StudentDaoinit方法,这样在Spring完成依赖注入后此方法即会被Spring调用,从而也就完成了studentMapper的初始化工作。

如果只有StudentDao一个DAO类,这样做当然没有问题。不过在实际应用中,必定存在多个DAO类。每个DAO类的初始化方法,除了传入的映射器接口类型(如StudentMapper接口)不同外,代码都是一样的,也就是说,同样的代码会重复多遍。显然,这种情况是需要避免的。那么更好的做法,是只写一个初始化方法,就能初始化所有的DAO对象。本文就来探讨如何实现这个目标。

初始化方法只想写一次,就能初始化所有的DAO对象,那么这个初始化方法就只能写在父类中,在本文的例子中,也就是BaseDao了(当然,@PostConstruct注解是必需的)。在初始化方法中对子类的映射器属性(如StudentDaoStudentMapper类型的studentMapper属性)进行初始化,显然是不现实的,因为父类的方法不能访问子类的属性。那么,子类就不能定义自己的映射器属性,只能是在父类中定义,子类继承。不过这又遇到一个问题,父类不知道映射器属性具体的类型——对于StudentDao来说是StudentMapper类型,对于TeacherDao来说就是TeacherMapper类型了。这个问题如何解决呢?也许你已经想到了,我们可以用泛型。把BaseDao定义为泛型类,用泛型来定义映射器变量,子类在继承BaseDao时,再把泛型指定为自己需要的具体的映射器类型。所以,目前我们的BaseDao代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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方法的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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是它的子接口,表示参数化类型,其实也就是泛型。

仿照StudentDao,我们可以写出TeacherDao如下(简单起见,只有一个方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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(二)










本文转自 NashMaster2011 51CTO博客,原文链接:http://blog.51cto.com/legend2011/1604009,如需转载请自行联系原作者
目录
相关文章
|
XML Oracle Java
mybatis反向生成实体类、dao层以及映射文件
mybatis反向生成实体类、dao层以及映射文件
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
406 10
|
Java 数据库连接 Maven
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
|
Java 数据库连接 mybatis
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
|
XML 关系型数据库 MySQL
支付系统----微信支付19---集成MyBatis-plus,数据库驱动对应的依赖版本设置问题,5没版本没有cj这个依赖,mysql驱动默认的是版本8,这里是一个父类,数据库都有,写个父类,继承就行
支付系统----微信支付19---集成MyBatis-plus,数据库驱动对应的依赖版本设置问题,5没版本没有cj这个依赖,mysql驱动默认的是版本8,这里是一个父类,数据库都有,写个父类,继承就行
|
Java 数据库连接 mybatis
MyBatis中Mapper接口和dao区别是什么?
MyBatis中Mapper接口和dao区别是什么?
381 0
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
|
6月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1064 1
Spring boot 使用mybatis generator 自动生成代码插件
|
9月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
712 0