什么是DAO?
我们在写代码的时候,不可能每次都写这么多的代码针对于我们CURD的操作,所以我们就把我们的操作封装在DAO里,需要调用的时候进行调用就可以了
所以我们对于我们所使用的基础操作,都封装在这个basedao里(里面要放考虑到事务的代码)
现在,我们已经有了一个通用的增删改方法,和一个通用的查询方法,但是实际开发中,我们还会有一些特殊的要求,譬如说,返回这个表中的记录数总和,怎么写这个通用的方法?
我们现在也不知道自己要返回什么,先写void
注入占位符
处理结果集
但是,我们得到了结果集中我们想要的东西,应该怎么返回呢,我查到的东西可能是date或者string或者int,我们可以用泛型来返回,把结果集拿到的数据强转就可以了
所以我们的basedao就是最底层的针对不同表都通用的方法,所以要把这个类写成抽象类,不能被其他地方直接调用
按照常理来说,这个时候,我们建立一个方法,实现basedao,在这个方法里调用就可以了,但是我们一般都写一个接口来规范我们的使用,我们就以test表来举例
在接口里,我们只写针对于这一个表的操作,可以根据业务的不同自行添加
下面就要写对于Test表具体的实现类了
继承BaseDAO并且实现TestDAO,我们在下面的这些方法体里写我们的sql语句和要在basedao里调用的具体方法就可以了
下面我们来对TestDAOImpl进行测试
-
插入操作
成功
删除操作
成功
更新数据
根据ID查询
中间的sql语句写错了,没有加表名
获取表中所有数据
获取表中的记录时
中间的问题:
在basedao中
没有用preparestatement接受预编译后的sql语句
没有用结果集接受查询后返回的结果
我是傻逼,调错了一个小时
获取最大的创建时间
所以,以后我们写代码,针对不同的表,只需要再对应这张表创建一个接口和一个实现类就可以了
但是,我们现在发现了一个问题,既然我们的TestDAO和TestDAOImpl都是对同一张表操作,为什么我们的方法里还要说明对哪个对象进行CURD操作呢?
那么我们就需要优化了,想办法把Test.class去掉 ,我们先把TestDAOImpl里的test.class和baseDAO里的class clazz去掉看一下
发现报错了,我们的两个查询方法中都需要clazz进行 生成一个泛型对象用来存放数据,那么我们在刚刚使用到baseDAO的时候,就从TestDAOImpl里知道自己要处理的表是谁,并且生成一个class类型的对象,即获取父类的泛型,不就可以了吗
我们在baseDAO里加上泛型参数
在我们操作子类TestDAOImpl的时候写好我们要操作的表名
即在TestDAOImpl里想获得BaseDAO的泛型类型Test
先在父类里声明一个class类型的变量用来存放我们想操作的表名
因此,我们写的两个泛型方法也要和父类要操作的表名一样,所以类型直接去掉就可以了
那么我们什么时候才需要获取这个clazz呢?
在TestDAOImpl调用baseDAO的时候,在new TestDAOImpl的时候最好,这样子一制造了关于一张表的对象,basedao里那边就可以使用了,所以代码应该写在TestDAOImpl里
但是问题又出现了 ,我们需要在baseDAO里用到clazz,在TestDAOImpl怎么能行?所以要放到baseDAO里
很离谱,那我们的
this.getClass().getGenericSuperclass()
现在这个this不就是baseDAO了吗,baseDAO根本就没有父类,怎么能这样子写?
解释:我们的代码流程是TestDAOImplTest进行测试,进入TestDAOImpl,在TestDAO的接口规范下,编译sql语句,然后用sql语句调用baseDAO的通用方法
这时候子类去调用父类,才会进入父类的代码块,那此时的this不就是指子类,也就是TestDAOImpl了,TestDAOImpl通过代码调用自己父类baseDAO的泛型是什么(在我们TestDAOImpl继承父类的时候给父类指明泛型类型),再在父类中进行使用,合情合理合情合理!!!!
测试成功: