- 浏览: 69001 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
颓废主义:
楼主敢不敢把你的原文删除了,或者把更正的内容放后边,然后附上原 ...
spring源码分析-controller的线程安全 -
_Yggd:
嗯,大神学习了
模板方法和Callback回调应用实践-自己动手写JdbcTemplate(附源码) -
chinagdvea:
为啥我觉得通过传入匿名类的方法实现方法调用,这是成了策略模式么 ...
模板方法和Callback回调应用实践-自己动手写JdbcTemplate(附源码) -
finallygo:
<div class="quote_title ...
模板方法和Callback回调应用实践-自己动手写JdbcTemplate(附源码) -
ameer:
<div class="quote_title ...
模板方法和Callback回调应用实践-自己动手写JdbcTemplate(附源码)
最近一直在研读spring源码和学习设计模式,想把自己的一些领悟与大家分享,前几天发了几篇简单的文章,可能由于文字过于简单,几次被评为新手贴,心中滴汗啊 没办法,工作太忙,大家都知道,写篇文章是要很大精力地~~~~~
今天恰有时间,把这两天的学习所得与大家分享,尽量写得详细一些,专家饶路走,新手觉得好赞一下(不要拍砖哦~~~~)。
文章源码在附件中
注:本文目的意不在“重复发明轮子”,而是借此文来探讨Spring JdbcTemplate的内部实现原理,掌握其运用精妙之处,以便在以后的“造轮运动”中能灵活运用。
话回正转,这两天在读spring的jdbc模板,对Spring源码的精妙真是佩服得五体投地,极为经典。
spring中真是集设计模式之大成,而且用得是炉火纯青。模板方法(template method)就在spring中被大量使用,如:jdbcTemplate,hibernateTemplate,JndiTemplate以及一些包围的包装等都无疑使用了模板模式,但spring并不是单纯使用了模板方法,而是在此基础上做了创新,配合callback(回调)一起使用,用得极其灵活。
OK,为了防止文章再被拍砖,我写得更详细点吧,我们首先来回顾一下模板模式:
所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。
有些抽象???
好吧,我们用代码来说话吧:
首先,父类要是个抽象类:
父类中有三个方法,分别是method1(),method2()和method3()。
method1()是私有方法,有且只能由父类实现逻辑,由于方法是private的,所以只能父类调用。
method2()是所谓的勾子方法。父类提供默认实现,如果子类觉得有必要定制,则可以覆盖父类的默认实现。
method3()是子类必须实现的方法,即制定的步骤。
由此可看出,算法的流程执行顺序是由父类掌控的,子类只能配合。
下面我们来写第一个子类:
这个子类只覆盖了必须覆盖的方法,我们来测试一下:
在控制台中我们可以看到:
OK,我们来看看勾子方法的使用:
定义第2个子类,实现勾子方法:
来测试一下:
我们看控制台:
OK,经典的模板模式回顾完了(大家不要拍砖哦~~~~~~~~~~)
接下来,我们回到正题,自己模仿spring动手写一个基于模板模式和回调的jdbcTemplate。
回顾一下,spring为什么要封装JDBC API,对外提供jdbcTemplate呢(不要仍鸡蛋啊¥·%¥#%)
话说SUN的JDBC API也算是经典了,曾经在某个年代折服了一批人。但随着历史的发展,纯粹的JDBC API已经过于底层,而且不易控制,由开发人员直接接触JDBC API,会造成不可预知的风险。还有,数据连接缓存池的发展,也不可能让开发人员去手工获取JDBC了。
好了,我们来看一段曾经堪称经典的JDBC API代码吧:
上面的代码要若干年前可能是一段十分经典的,还可能被作为example被推广。但时过境迁,倘若哪位程序员现在再在自己的程序中出现以上代码,不是说明该公司的开发框架管理混乱,就说明这位程序员水平太“高”了。
我们试想,一个简单的查询,就要做这么一大堆事情,而且还要处理异常,我们不防来梳理一下:
1、获取connection
2、获取statement
3、获取resultset
4、遍历resultset并封装成集合
5、依次关闭connection,statement,resultset,而且还要考虑各种异常
6、.....
啊~~~~ 我快要晕了,在面向对象编程的年代里,这样的代码简直不能上人容忍。试想,上面我们只是做了一张表的查询,如果我们要做第2张表,第3张表呢,又是一堆重复的代码:
1、获取connection
2、获取statement
3、获取resultset
4、遍历resultset并封装成集合
5、依次关闭connection,statement,resultset,而且还要考虑各种异常
6、.....
这时候,使用模板模式的时机到了!!!
通过观察我们发现上面步骤中大多数都是重复的,可复用的,只有在遍历ResultSet并封装成集合的这一步骤是可定制的,因为每张表都映射不同的java bean。这部分代码是没有办法复用的,只能定制。那就让我们用一个抽象的父类把它们封装一下吧:
在上面这个抽象类中,封装了SUN JDBC API的主要流程,而遍历ResultSet这一步骤则放到抽象方法doInStatement()中,由子类负责实现。
好,我们来定义一个子类,并继承上面的父类:
由代码可见,我们在doInStatement()方法中,对ResultSet进行了遍历,最后并返回。
有人可能要问:我如何获取ResultSet 并传给doInStatement()方法啊??呵呵,问这个问题的大多是新手。因为此方法不是由子类调用的,而是由父类调用,并把ResultSet传递给子类的。我们来看一下测试代码:
就是这么简单!!
文章至此仿佛告一段落,莫急!不防让我们更深入一些...
试想,如果我每次用jdbcTemplate时,都要继承一下上面的父类,是不是有些不方面呢?
那就让我们甩掉abstract这顶帽子吧,这时,就该callback(回调)上场了
所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。
那我们就来把上面的代码改造一下,改用回调实现吧:
首先,我们来定义一个回调接口:
这时候,我们就要方法的签名改一下了:
里面的获取数据方式也要做如下修改:
为了看着顺眼,我们来给他封装一层吧:
OK,大功告成!
我们来写一个测试类Test.java测试一下吧:
这时候,访问有两种方式,一种是内部类的方式,一种是匿名方式。
先来看看内部类的方式:
在调用jdbcTemplate.query()方法时,传一个StatementCallBack()的实例过去,也就是我们的内部类。
再来看看匿名方式:
相比之下,这种方法更为简洁。
为什么spring不用传统的模板方法,而加之以Callback进行配合呢?
试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。
离spring jdbcTemplate再近一点
上面这种方式基本上实现了模板方法+回调模式。但离spring的jdbcTemplate还有些距离。
我们可以再深入一些。。。
我们上面虽然实现了模板方法+回调模式,但相对于Spring的JdbcTemplate则显得有些“丑陋”。Spring引入了RowMapper和ResultSetExtractor的概念。
RowMapper接口负责处理某一行的数据,例如,我们可以在mapRow方法里对某一行记录进行操作,或封装成entity。
ResultSetExtractor是数据集抽取器,负责遍历ResultSet并根据RowMapper里的规则对数据进行处理。
RowMapper和ResultSetExtractor区别是,RowMapper是处理某一行数据,返回一个实体对象。而ResultSetExtractor是处理一个数据集合,返回一个对象集合。
当然,上面所述仅仅是Spring JdbcTemplte实现的基本原理,Spring JdbcTemplate内部还做了更多的事情,比如,把所有的基本操作都封装到JdbcOperations接口内,以及采用JdbcAccessor来管理DataSource和转换异常等。
接下来的主题:进行范型的改造
我们可能发现,上面的接口中返回的还都是Object对象,在范型日益盛行的今天,我们怎能忍受每次都要把得到的对象进行强制类型转换?那我们就要心情享用JDK1.5给我们带来的范型盛宴。
未完待续...
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
你扯淡吧就,1,死读书不如无书,我全文给你讲的是一个思想,你不理解没办法,那什么是硬伤
2, 非要看见棺材才掉泪??
org.springframework.jdbc.core.JdbcTemplate
源码第331行:
Connection con = DataSourceUtils.getConnection(getDataSource());
你看的是你自己写的JdbcTemplate硬说成是Spring的?
1.是你没理解核心思想吧,简单提示 下你,ioc和aop怎么配合使用的
2.它的datasource是从哪里来的??什么叫"没了解本质",你给我上了一课
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
你扯淡吧就,1,死读书不如无书,我全文给你讲的是一个思想,你不理解没办法,那什么是硬伤
2, 非要看见棺材才掉泪??
org.springframework.jdbc.core.JdbcTemplate
源码第331行:
Connection con = DataSourceUtils.getConnection(getDataSource());
你看的是你自己写的JdbcTemplate硬说成是Spring的?
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
那个项目应该没有使用spring框架吧,如果使用spring框架,jdbcTemplate是首选(当然是在没有使用ORM框架的情况下)。
你最好的选择我认为是引入JdbcTemplate,JdbcTemplate是对直接使用jdbc api的最好升级途径。
你难道还在用连接相关的事务吗?
今天恰有时间,把这两天的学习所得与大家分享,尽量写得详细一些,专家饶路走,新手觉得好赞一下(不要拍砖哦~~~~)。
文章源码在附件中
注:本文目的意不在“重复发明轮子”,而是借此文来探讨Spring JdbcTemplate的内部实现原理,掌握其运用精妙之处,以便在以后的“造轮运动”中能灵活运用。
话回正转,这两天在读spring的jdbc模板,对Spring源码的精妙真是佩服得五体投地,极为经典。
spring中真是集设计模式之大成,而且用得是炉火纯青。模板方法(template method)就在spring中被大量使用,如:jdbcTemplate,hibernateTemplate,JndiTemplate以及一些包围的包装等都无疑使用了模板模式,但spring并不是单纯使用了模板方法,而是在此基础上做了创新,配合callback(回调)一起使用,用得极其灵活。
OK,为了防止文章再被拍砖,我写得更详细点吧,我们首先来回顾一下模板模式:
所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。
有些抽象???
好吧,我们用代码来说话吧:
首先,父类要是个抽象类:
public abstract class TemplatePattern { //模板方法 public final void templateMethod(){ method1(); method2();//勾子方法 method3();//抽象方法 } private void method1(){ System.out.println("父类实现业务逻辑"); } public void method2(){ System.out.println("父类默认实现,子类可覆盖"); } protected abstract void method3();//子类负责实现业务逻辑 }
父类中有三个方法,分别是method1(),method2()和method3()。
method1()是私有方法,有且只能由父类实现逻辑,由于方法是private的,所以只能父类调用。
method2()是所谓的勾子方法。父类提供默认实现,如果子类觉得有必要定制,则可以覆盖父类的默认实现。
method3()是子类必须实现的方法,即制定的步骤。
由此可看出,算法的流程执行顺序是由父类掌控的,子类只能配合。
下面我们来写第一个子类:
public class TemplatePatternImpl extends TemplatePattern { @Override protected void method3() { System.out.println("method3()在子类TemplatePatternImpl中实现了!!"); } }
这个子类只覆盖了必须覆盖的方法,我们来测试一下:
TemplatePattern t1 = new TemplatePatternImpl(); t1.templateMethod();
在控制台中我们可以看到:
父类实现业务逻辑 父类默认实现,子类可覆盖 method3()在子类TemplatePatternImpl中实现了!!
OK,我们来看看勾子方法的使用:
定义第2个子类,实现勾子方法:
public class TemplatePatternImpl2 extends TemplatePattern { @Override protected void method3() { System.out.println("method3()在子类TemplatePatternImpl2中实现了!!"); } /* (non-Javadoc) * @see com.jak.pattern.template.example.TemplatePattern#method2() */ @Override public void method2() { System.out.println("子类TemplatePatternImpl2覆盖了父类的method2()方法!!"); } }
来测试一下:
TemplatePattern t2 = new TemplatePatternImpl2(); t2.templateMethod();
我们看控制台:
父类实现业务逻辑 子类TemplatePatternImpl2覆盖了父类的method2()方法!! method3()在子类TemplatePatternImpl2中实现了!!
OK,经典的模板模式回顾完了(大家不要拍砖哦~~~~~~~~~~)
接下来,我们回到正题,自己模仿spring动手写一个基于模板模式和回调的jdbcTemplate。
回顾一下,spring为什么要封装JDBC API,对外提供jdbcTemplate呢(不要仍鸡蛋啊¥·%¥#%)
话说SUN的JDBC API也算是经典了,曾经在某个年代折服了一批人。但随着历史的发展,纯粹的JDBC API已经过于底层,而且不易控制,由开发人员直接接触JDBC API,会造成不可预知的风险。还有,数据连接缓存池的发展,也不可能让开发人员去手工获取JDBC了。
好了,我们来看一段曾经堪称经典的JDBC API代码吧:
public List<User> query() { List<User> userList = new ArrayList<User>(); String sql = "select * from User"; Connection con = null; PreparedStatement pst = null; ResultSet rs = null; try { con = HsqldbUtil.getConnection(); pst = con.prepareStatement(sql); rs = pst.executeQuery(); User user = null; while (rs.next()) { user = new User(); user.setId(rs.getInt("id")); user.setUserName(rs.getString("user_name")); user.setBirth(rs.getDate("birth")); user.setCreateDate(rs.getDate("create_date")); userList.add(user); } } catch (SQLException e) { e.printStackTrace(); }finally{ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } try { pst.close(); } catch (SQLException e) { e.printStackTrace(); } try { if(!con.isClosed()){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } catch (SQLException e) { e.printStackTrace(); } } return userList; }
上面的代码要若干年前可能是一段十分经典的,还可能被作为example被推广。但时过境迁,倘若哪位程序员现在再在自己的程序中出现以上代码,不是说明该公司的开发框架管理混乱,就说明这位程序员水平太“高”了。
我们试想,一个简单的查询,就要做这么一大堆事情,而且还要处理异常,我们不防来梳理一下:
1、获取connection
2、获取statement
3、获取resultset
4、遍历resultset并封装成集合
5、依次关闭connection,statement,resultset,而且还要考虑各种异常
6、.....
啊~~~~ 我快要晕了,在面向对象编程的年代里,这样的代码简直不能上人容忍。试想,上面我们只是做了一张表的查询,如果我们要做第2张表,第3张表呢,又是一堆重复的代码:
1、获取connection
2、获取statement
3、获取resultset
4、遍历resultset并封装成集合
5、依次关闭connection,statement,resultset,而且还要考虑各种异常
6、.....
这时候,使用模板模式的时机到了!!!
通过观察我们发现上面步骤中大多数都是重复的,可复用的,只有在遍历ResultSet并封装成集合的这一步骤是可定制的,因为每张表都映射不同的java bean。这部分代码是没有办法复用的,只能定制。那就让我们用一个抽象的父类把它们封装一下吧:
public abstract class JdbcTemplate { //template method public final Object execute(String sql) throws SQLException{ Connection con = HsqldbUtil.getConnection(); Statement stmt = null; try { stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); Object result = doInStatement(rs);//abstract method return result; } catch (SQLException ex) { ex.printStackTrace(); throw ex; } finally { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } try { if(!con.isClosed()){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } catch (SQLException e) { e.printStackTrace(); } } } //implements in subclass protected abstract Object doInStatement(ResultSet rs); }
在上面这个抽象类中,封装了SUN JDBC API的主要流程,而遍历ResultSet这一步骤则放到抽象方法doInStatement()中,由子类负责实现。
好,我们来定义一个子类,并继承上面的父类:
public class JdbcTemplateUserImpl extends JdbcTemplate { @Override protected Object doInStatement(ResultSet rs) { List<User> userList = new ArrayList<User>(); try { User user = null; while (rs.next()) { user = new User(); user.setId(rs.getInt("id")); user.setUserName(rs.getString("user_name")); user.setBirth(rs.getDate("birth")); user.setCreateDate(rs.getDate("create_date")); userList.add(user); } return userList; } catch (SQLException e) { e.printStackTrace(); return null; } } }
由代码可见,我们在doInStatement()方法中,对ResultSet进行了遍历,最后并返回。
有人可能要问:我如何获取ResultSet 并传给doInStatement()方法啊??呵呵,问这个问题的大多是新手。因为此方法不是由子类调用的,而是由父类调用,并把ResultSet传递给子类的。我们来看一下测试代码:
String sql = "select * from User"; JdbcTemplate jt = new JdbcTemplateUserImpl(); List<User> userList = (List<User>) jt.execute(sql);
就是这么简单!!
文章至此仿佛告一段落,莫急!不防让我们更深入一些...
试想,如果我每次用jdbcTemplate时,都要继承一下上面的父类,是不是有些不方面呢?
那就让我们甩掉abstract这顶帽子吧,这时,就该callback(回调)上场了
所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。
那我们就来把上面的代码改造一下,改用回调实现吧:
首先,我们来定义一个回调接口:
public interface StatementCallback { Object doInStatement(Statement stmt) throws SQLException; }
这时候,我们就要方法的签名改一下了:
private final Object execute(StatementCallback action) throws SQLException
里面的获取数据方式也要做如下修改:
Object result = action.doInStatement(stmt);//abstract method
为了看着顺眼,我们来给他封装一层吧:
public Object query(StatementCallback stmt) throws SQLException{ return execute(stmt); }
OK,大功告成!
我们来写一个测试类Test.java测试一下吧:
这时候,访问有两种方式,一种是内部类的方式,一种是匿名方式。
先来看看内部类的方式:
//内部类方式 public Object query(final String sql) throws SQLException { class QueryStatementCallback implements StatementCallback { public Object doInStatement(Statement stmt) throws SQLException { ResultSet rs = stmt.executeQuery(sql); List<User> userList = new ArrayList<User>(); User user = null; while (rs.next()) { user = new User(); user.setId(rs.getInt("id")); user.setUserName(rs.getString("user_name")); user.setBirth(rs.getDate("birth")); user.setCreateDate(rs.getDate("create_date")); userList.add(user); } return userList; } } JdbcTemplate jt = new JdbcTemplate(); return jt.query(new QueryStatementCallback()); }
在调用jdbcTemplate.query()方法时,传一个StatementCallBack()的实例过去,也就是我们的内部类。
再来看看匿名方式:
//匿名类方式 public Object query2(final String sql) throws Exception{ JdbcTemplate jt = new JdbcTemplate(); return jt.query(new StatementCallback() { public Object doInStatement(Statement stmt) throws SQLException { ResultSet rs = stmt.executeQuery(sql); List<User> userList = new ArrayList<User>(); User user = null; while (rs.next()) { user = new User(); user.setId(rs.getInt("id")); user.setUserName(rs.getString("user_name")); user.setBirth(rs.getDate("birth")); user.setCreateDate(rs.getDate("create_date")); userList.add(user); } return userList; } }); }
相比之下,这种方法更为简洁。
为什么spring不用传统的模板方法,而加之以Callback进行配合呢?
试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。
离spring jdbcTemplate再近一点
上面这种方式基本上实现了模板方法+回调模式。但离spring的jdbcTemplate还有些距离。
我们可以再深入一些。。。
我们上面虽然实现了模板方法+回调模式,但相对于Spring的JdbcTemplate则显得有些“丑陋”。Spring引入了RowMapper和ResultSetExtractor的概念。
RowMapper接口负责处理某一行的数据,例如,我们可以在mapRow方法里对某一行记录进行操作,或封装成entity。
ResultSetExtractor是数据集抽取器,负责遍历ResultSet并根据RowMapper里的规则对数据进行处理。
RowMapper和ResultSetExtractor区别是,RowMapper是处理某一行数据,返回一个实体对象。而ResultSetExtractor是处理一个数据集合,返回一个对象集合。
当然,上面所述仅仅是Spring JdbcTemplte实现的基本原理,Spring JdbcTemplate内部还做了更多的事情,比如,把所有的基本操作都封装到JdbcOperations接口内,以及采用JdbcAccessor来管理DataSource和转换异常等。
接下来的主题:进行范型的改造
我们可能发现,上面的接口中返回的还都是Object对象,在范型日益盛行的今天,我们怎能忍受每次都要把得到的对象进行强制类型转换?那我们就要心情享用JDK1.5给我们带来的范型盛宴。
未完待续...
- SpringTemplateCallbackTemplate.rar (701 KB)
- 下载次数: 389
评论
26 楼
_Yggd
2013-08-07
嗯,大神学习了
25 楼
chinagdvea
2013-07-23
为啥我觉得通过传入匿名类的方法实现方法调用,这是成了策略模式么?匿名类当做一个策略来传入
24 楼
finallygo
2012-12-28
ameer 写道
finallygo 写道
ameer 写道
finallygo 写道
daquan198163 写道
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
你扯淡吧就,1,死读书不如无书,我全文给你讲的是一个思想,你不理解没办法,那什么是硬伤
2, 非要看见棺材才掉泪??
org.springframework.jdbc.core.JdbcTemplate
源码第331行:
Connection con = DataSourceUtils.getConnection(getDataSource());
你看的是你自己写的JdbcTemplate硬说成是Spring的?
1.是你没理解核心思想吧,简单提示 下你,ioc和aop怎么配合使用的
2.它的datasource是从哪里来的??什么叫"没了解本质",你给我上了一课
23 楼
ameer
2012-12-28
finallygo 写道
ameer 写道
finallygo 写道
daquan198163 写道
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
你扯淡吧就,1,死读书不如无书,我全文给你讲的是一个思想,你不理解没办法,那什么是硬伤
2, 非要看见棺材才掉泪??
org.springframework.jdbc.core.JdbcTemplate
源码第331行:
Connection con = DataSourceUtils.getConnection(getDataSource());
你看的是你自己写的JdbcTemplate硬说成是Spring的?
22 楼
finallygo
2012-12-28
ameer 写道
finallygo 写道
daquan198163 写道
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
从你刚才说要支持使用HsqldbUtil这个一个工具类,说明你对ioc的认识还是不清楚,建议你看看真正的spring JdbcTemplate的源码,你看看它是把获取数据库连接放到一个工具类中的么???
21 楼
ameer
2012-12-28
finallygo 写道
daquan198163 写道
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
真是够菜的,Spring要知道你把它的类用new来创建要活活气死了!
你还是先别自己去写什么jdbc template了,你水平还远远不够。先去理解一下Spring最最基本的IoC
Spring的核心就是,业务代码中需要使用到什么Bean或者Connection之类的资源,绝对不需要自己来创建,
要么委托给Spring的BeanFactory创建和注入,要么委托给第三方资源管理器,比如工厂类或者资源池
这才叫做“反转注入”
人家虽然使用了一个什么HsqldbUtil,我没有下载源代码看,但是从描述中能看出,这种将获取连接的方式委托出去就是一个很好的实践:
1: 获取连接这个操作的具体实现细节就给隐藏了,你管人家是完全重新new了一个资源,还是从已经管理好的连接池里找了个空闲的连接?
2: 在释放资源时,你只能硬生生的对connection执行真正的释放动作,我继续使用第三方工具对connection进行释放,你管我是真的释放了还是仅仅把连接进行了清理归还进了连接池?
什么时候你不再使用到new这个关键字,你再来和我们讨论Spring吧
20 楼
whao189
2011-05-26
刚好这两天看模板方法方法模式,
看了楼主的解释 正好有助于我对此模式的理解。但是对于spring 我一直有心去研究
但是源码从哪个地方看起我还不太清楚,楼主应该看spring 有一段时间了走过去的人
了,不知道能不能指点一下我让我少走些弯路!
看了楼主的解释 正好有助于我对此模式的理解。但是对于spring 我一直有心去研究
但是源码从哪个地方看起我还不太清楚,楼主应该看spring 有一段时间了走过去的人
了,不知道能不能指点一下我让我少走些弯路!
19 楼
cai3178940
2010-12-14
写的非常好啊,支持楼主,不过还是被投了好多新手贴。。。
楼上说用反射是怎么做的呢,我觉得像楼主说的用泛型就可以不用对每个pojo做一个jdbcTemplateImpl
楼上说用反射是怎么做的呢,我觉得像楼主说的用泛型就可以不用对每个pojo做一个jdbcTemplateImpl
18 楼
goolcona
2010-12-14
说一点关于类映射的相关,可以考虑使用反射在组装这个User,这样的话就不必针对每个pojo做一个JdbcTepmlateImpl。
17 楼
xchao
2010-10-30
回调方法的原理、设计、实现、示例讲解的很好!
学习了!
学习了!
16 楼
finallygo
2010-10-26
daquan198163 写道
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢?
15 楼
xchao
2010-10-25
不错的文章,条理清晰,JAVA新手来学习了!
14 楼
daquan198163
2010-10-20
finallygo 写道
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
13 楼
finallygo
2010-10-20
daquan198163 写道
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
12 楼
daquan198163
2010-10-09
finallygo 写道
我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
11 楼
jakoes
2010-10-09
blackchoc 写道
感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
那个项目应该没有使用spring框架吧,如果使用spring框架,jdbcTemplate是首选(当然是在没有使用ORM框架的情况下)。
10 楼
ironsabre
2010-09-06
blackchoc 写道
感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
你最好的选择我认为是引入JdbcTemplate,JdbcTemplate是对直接使用jdbc api的最好升级途径。
9 楼
blackchoc
2010-09-04
感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
8 楼
ironsabre
2010-07-23
finallygo 写道
我感觉有点问题吧,首先jdbctemplate好像没有与你这里的HsqldbUtil这种类耦合在一起吧,还有一个就是,你这里好像进行了一次查询之后数据库连接就关闭了,那我怎么做事务呢?
你难道还在用连接相关的事务吗?
7 楼
finallygo
2010-07-22
说到spring,我有点小小的疑问,
我先说下我对spring的认识啊,spring中最主要的两个思想是ioc,aop
ioc就体现在工厂模式的应用,也就是说我们采用的都是面向接口的方式的编程,以后如果实现类发生变化了,可以通过修改配置文件而不用修改代码来实现系统的灵活性,但是实际上好像这种需求并不多啊,我们项目中都是一个接口,一个实现类,也就是说配置文件我们添加一个Dao的时候才去改配置文件,之后就再也不去动了,反而接口是经常变动的,因为需求是一直在增加的,所以给我的感觉就是接口成为了一个累赘,我改一个接口就要改一堆的东西(因为我们分了好几层,而一个方法的添加就从dao一直污染到顶层了),我觉得还不如直接创建一个实现类来的方便.
还有一个就是aop,我觉得主要就是用来做事务和日志的,但是这些用动态代理就可以实现了,我觉得spring太复杂了,没有必要用的
不知道我这两个思想有什么问题,麻烦你讲解一下.
我先说下我对spring的认识啊,spring中最主要的两个思想是ioc,aop
ioc就体现在工厂模式的应用,也就是说我们采用的都是面向接口的方式的编程,以后如果实现类发生变化了,可以通过修改配置文件而不用修改代码来实现系统的灵活性,但是实际上好像这种需求并不多啊,我们项目中都是一个接口,一个实现类,也就是说配置文件我们添加一个Dao的时候才去改配置文件,之后就再也不去动了,反而接口是经常变动的,因为需求是一直在增加的,所以给我的感觉就是接口成为了一个累赘,我改一个接口就要改一堆的东西(因为我们分了好几层,而一个方法的添加就从dao一直污染到顶层了),我觉得还不如直接创建一个实现类来的方便.
还有一个就是aop,我觉得主要就是用来做事务和日志的,但是这些用动态代理就可以实现了,我觉得spring太复杂了,没有必要用的
不知道我这两个思想有什么问题,麻烦你讲解一下.
相关推荐
`JdbcTemplate`执行SQL查询时,会调用用户提供的回调方法来处理结果集,这类似于同步回调,因为结果处理在查询完成后立即进行,与模板模式的应用场景相似。 总的来说,回调函数和模板模式都是为了实现代码的复用和...
总结起来,基于鸿洋的OkHttpUtils封装数据Bean和Callback回调,可以帮助我们更高效地处理网络请求,减少手动解析数据的工作,同时利用泛型提供类型安全。在实际项目中,可以结合`OkCallbackUtil`进一步优化网络请求...
本文实例分析了C++中回调函数(CallBack)的用法。分享给大家供大家参考。具体分析如下: 如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过。 其错误是普通的C++成员函数都隐含了一个传递...
回调(Callback)是编程中一个重要的概念,尤其是在异步编程中。回调函数是一种将功能作为参数传递给另一个函数,以便在特定事件发生或任务完成后执行的编程技术。回调的使用可以解决程序执行顺序的问题,特别是在...
Callback回调函数作为一种重要的编程模式,在各种编程语言和框架中都有广泛的应用。理解和掌握回调函数的工作原理及使用方法对于提高程序设计能力具有重要意义。无论是进行事件处理、异步编程还是多线程编程,合理...
为了克服上述局限性,可以考虑使用模板化的方法来设计回调对象。这种方式不仅可以提高类型安全性,还能增强代码的可读性和可维护性。 ##### 1. 模板化回调对象的设计 下面是一个具体的模板化回调对象的设计示例,...
通过阅读和学习《回调技术(CallBack)》的相关资料,如给出的博客链接(虽然这里没有实际链接,但在实际场景中,你可以找到类似的教程或文章),可以深入理解回调的原理及其在不同场景下的应用。同时,不断实践和...
在jQuery中,回调函数被广泛应用,尤其是在处理异步操作时。本篇文章将深入探讨jQuery中的回调函数及其应用。 首先,我们需要了解什么是回调函数。回调函数本质上是一个作为参数传递给另一个函数的函数,当这个外层...
通过以上步骤,你已经掌握了在Linux环境下编写回调函数和制作库文件的基本方法。在实际开发中,可以根据项目需求进行扩展和优化,比如添加错误处理、多线程支持等。希望这篇教程能帮助你更好地理解和运用这些技术。
本文将详细介绍如何在 C# 环境下利用 Halcon 的外触发机制来实现图像采集,并通过 `get_framegrabber_callback` 函数注册回调函数的方法。 #### 二、Halcon 外触发机制介绍 在实际应用中,很多时候我们需要根据...
综上所述,JNI回调函数Callback是Android开发中连接Java和C/C++的重要方式,它使得两个世界之间的通信更为灵活,能够实现更多复杂的逻辑。在实际应用中,开发者需要熟练掌握JNI的基础知识,并了解如何安全有效地使用...
可能包含了具体的信号槽连接示例,而`mainwindow.ui`则是Qt Designer生成的用户界面文件,`callback.pro`和`callback.pro.user`则是项目配置文件,它们共同构成了一个关于Qt回调函数使用的实例项目。
回调(Callback)是一种在软件设计模式中常见的编程概念,它允许一个函数或对象在完成某个操作后通知另一个函数或对象。在本示例"CallBack_DEMO"中,我们可能正在探讨如何在Java或其他编程语言中实现回调机制。回调...
### 回调函数Callback Function #### 一、基本概念 **回调函数**是一种常见的编程模式,广泛应用于多种编程语言中,特别是在C/C++等语言中非常常见。简单来说,回调函数是指通过函数指针传递的一个函数,该函数会...
在Android开发中,回调接口是一种常见的设计模式,用于在组件之间传递信息,特别是在需要一个组件(如Fragment)通知另一个组件(如...通过不断地实践和探索,开发者可以更加熟练地运用回调接口解决各种编程问题。
在C++编程中,回调是一种常见的...模板类使得回调函数更加灵活,可以适应各种不同的数据类型和接口,而不仅仅是原始的函数指针。通过这种方式,我们可以编写出更加通用且可复用的代码,提高程序的可维护性和可扩展性。
TClientDataset不仅能够存储数据,还可以作为客户端和服务器之间的中介,负责处理数据的传输和回调。在使用回调时,通常需要进行以下步骤: 1. **创建TClientDataset组件**:在客户端的表单上添加TClientDataset...
回调函数在许多领域都有广泛的应用,例如图形用户界面(GUI)开发中的事件处理、数据排序和过滤、多线程编程中的同步和通信等。例如,在GUI编程中,我们可能会定义一个处理按钮点击事件的回调函数,然后将该函数注册...
其次,自动回调(Callback)是API设计的一种常见模式。在USDT支付过程中,当一笔交易完成或状态发生变化时,API会自动调用预先设定的回调函数,通知系统交易的状态更新。这种机制使得支付系统能够实时获取交易状态,...