文档章节

Spring&JDBC杂谈

cwalet
 cwalet
发布于 2012/07/13 11:13
字数 1800
阅读 668
收藏 5

下面的问题都是从以下代码引申而来:

this.simpleJdbcOperation.getJdbcOperations().update(new PreparedStatementCreator() {

	@Override
	public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
		sql = "DELETE FROM A a WHERE a.name=:name AND a.time=:time";// PreparedStatement不支持占位符格式
		PreparedStatement ps = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);// 返回id
		ps.setObject(1, obj.getName());// 可能为空的对象使用setObject
		if (null != obj.getDate())
			ps.setDate(4, new Date(obj.getDate().getTime()));
		else
			ps.setNull(4, Types.DATE);// 为空的对象使用setNull
		return ps;
	}

}, keyHolder);


一、SimpleJdbcTemplateNamedParameterJdbcTemplateJdbcTemplate 这三者的区别

参考:Spring Framework reference 2.0.5 参考手册中文版

SimpleJdbcOperations其实是包含Jdk5.0新特性的NamedParameterJdbcTemplate和JdbcTemplate的集合,

它的多数实现都是由NamedParameterJdbcTemplate完成的,并且有方法获取其他两个JdbcTemplate的实例, 推荐使用!

(在张培立同学的提醒(见评论)下,发现2.5中SimpleJdbcOperations也已经被标注为了@Deprecated,大概是作者更喜欢其他两个JdbcTemplate,而且也实现了SimpleJdbcOperations的所有功能,因此还是推荐使用NamedParameterJdbcTemplate和JdbcTemplate)

SimpleJdbcTemplate类是JdbcTemplate类的一个包装器(wrapper),它利用了Java 5的一些语言特性,比如Varargs和Autoboxing。对那些用惯了Java 5的程序员,这些新的语言特性还是很好用的。

另外说说NamedParameterJdbcTemplate,同时也回答我的第一个问题:JDBC不支持命名参数的占位符吗(如:name)?

自从使用了ORM或其他框架后,就很少直接接触JDBC API了,习惯了Spring封装的Template、ibatis、JPA的JPQL等这些支持参数占位符的写法,

其实JDBC中的SQL写法是不支持命名参数占位符

NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用'?'占位符来表示的。 NamedParameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,并作为其代理来完成大部分工作。

NamedParameterJdbcTemplate中有一个工具类专门用于命名参数SQL的解析和还原:

NamedParameterUtils.parseSqlStatement(sql);

因此, NamedParameterJdbcTemplate是JdbcTemplate的升级版,而SimpleJdbcTemplate则是最高级的版本!

关于SimpleJdbcTemplate的用法参见:使用Spring的NamedParameterJdbcTemplate完成DAO操作


二、关于 setObject 与 setNull

Jdbc中的PreparedStatement对象包含了众多的setXXX方法,用于对SQL语句中“?”对应的字段赋值。

通过查看MySQL驱动中的实现可知,使用setObject是一种最懒同时也是最保险的方法,它会自动去判断是否是常用数据类型并做相应处理,

因为几乎每一个setXXX方法中都有对空的判断,对于空值选择使用setNull方法。

可能为空的对象使用setObject但并不是为空(指为NULL)的对象就必须使用setObject才能正确赋值

说道setNull,实际上也是设定一个“null”的字符串来替代,其实这个方法对于接口使用者来说是基本无用的,可以作为protect方法不理。

因此,当你不确定你的程序里接受的是什么类型的值时,使用setObject吧,有益无害!


三、能否通过KeyHolder来获取一条删除语句的id?

想想就觉得不可能的。可以使用KeyHolder来获取新插入数据自动生成的ID,但有时候删除某条数据(通过其他字段删除,而非主键ID),

我们也希望能直接返回ID,而无需先去查询一次数据库。但这实际上是不行的。

在JDBC中通常以下面的方式获取新生成的ID:

PreparedStatement ps = connection.prepareStatement(
"insert into article(content,title) values('a','b')", Statement.RETURN_GENERATED_KEYS);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
rs.first();
System.out.println(rs.getString(1));

Spring将getGeneratedKeys()的操作封装到一个KeyHolder对象中,查看了一下源码,

实际上还是通过“SELECT LAST_INSERT_ID()”的方式来获取IDENTITY的ID,com.mysql.jdbc.StatementImpl.getLastInsertID()

This gets around the un-threadsafe behavior of "select LAST_INSERT_ID()" which is tied to the Connection that created this Statement, and therefore could have had many INSERTS performed before one gets a chance to call "select LAST_INSERT_ID()".

 这里列举了三种获取自增长主键的方法:MySQL中关于自增长主键的获取,其中第2点说的比较清楚:

(2)LAST_INSERT_ID: LAST_INSERT_ID 是与table无关的,如果向表a插入数据后,再向表b插入数据,LAST_INSERT_ID会改变。 在多用户交替插入数据的情况下max(id)显然不能用。 这就该使用LAST_INSERT_ID了,因为LAST_INSERT_ID是基于Connection的,只要每个线程都使用独立的Connection对象,LAST_INSERT_ID函数将返回该Connection对AUTO_INCREMENT列最新的insert or update*作生成的第一个record的ID。这个值不能被其它客户端(Connection)影响,保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁。使用单INSERT语句插入多条记录, LAST_INSERT_ID返回一个列表。

对于多列插入的LAST_INSERT_ID()返回的结果将只有第一个。具体见MySQL文档: 信息函数


四、关于Spring配置文件的bean标签中的id和name的区别

谈谈Spring配置中<bean>的id和name属性的花拳秀腿,以下引用自CSDN上的讨论:http://sina.lt/dkX

1.id是唯一的,name可以指定多个,其他的就是别名,例如 <bean name= "A1,A2 ".../> A2就是别名
2.XML规范严格限定了在XML ID中合法的字符。例如在spring mvc中我们如果使用UrlFilenameViewController:   <bean name= "/index.htm " class= "org.springframework.web.servlet.mvc.UrlFilenameViewController "/> 那么只能用name,因为XML规范中ID不能含有“/ "之类的字符。
3.如果被引用的bean在同一个xml文件中而且bean的名称是bean的 id,那么就可以使用local属性.这 个是spring参考文档里面的,注意看看。


五、传说中的JDBC4

很久以前听说JDK6中会发布JDBC4,这里是它的新特性,但直到今天依然没有看到这一成果。

莫须有,JDBC4最终版并没有加入该功能。也许演变成了现在的spring-data-jdbc,以及JPA的部分特性。

JDBC4新特性之自动加载驱动:

Applications no longer need to explictly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.

也许你没有意识到,但是现在你确实无需写Class.forName...(已有程序自然也不会受影响)

When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application.

调用getConnection方法时,驱动管理器会尝试去定位一个合适的驱动。(驱动类必须放在Classpath里,否则,谁知道驱动在哪儿?)

  • 既然避免了手动加载驱动类,JVM是如何主动发现它的呢?

参考:http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html

The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC drivers implementation of java.sql.Driver. For example, to load the my.sql.Driver class, the META-INF/services/java.sql.Driver file would contain the entry: my.sql.Driver

DriverManagergetConnectiongetDrivers方法都被增强了,提供了所谓的Java标准服务提供机制,

因此实现JDBC4的驱动必须将实际的驱动类名写入到文件META-INF/services/java.sql.Driver中。

© 著作权归作者所有

共有 人打赏支持
cwalet
粉丝 44
博文 111
码字总数 87663
作品 0
其他
私信 提问
加载中

评论(3)

zplswf
zplswf

引用来自“cwalet”的评论

引用来自“张培立”的评论

3.1版本的 SimpleJdbcTemplate不过现在已经禁用了

为什么呢?还是有新的替代?现在用的是2.5

现在高版本的 用的是要么jdbctempate 要么是NamedParameterJdbcTemplate
cwalet
cwalet

引用来自“张培立”的评论

3.1版本的 SimpleJdbcTemplate不过现在已经禁用了

为什么呢?还是有新的替代?现在用的是2.5
zplswf
zplswf
3.1版本的 SimpleJdbcTemplate不过现在已经禁用了
杂谈nginx 301 重定向在非常规破解中的利用

杂谈nginx 301 重定向在非常规破解中的利用 火星信息安全研究院2017-12-281 阅读 Python 在某些特定的情况下,如果软件采用本地加服务器校验的方式进行注册时候。单纯的本地破解可能很快就是...

火星信息安全研究院
2017/12/28
0
0
好书推荐.Philosophy.>

图书封面: 书籍简介: 主要讲述了作者在该作品中倾注了其对中国民众的关注,以反讽和幽默的手法直面生活,从一个轻松的角度来解析身边复杂的事态. 书籍目录: 第 001 章 沉默的大多数 第 002 章 ...

满满李
2016/05/07
152
0
【目录】姜晔的技术空间目录

逆向工程系列 逆向工程第001篇:解锁FIFA07传奇模式 逆向工程第002篇:打造自己的仙剑奇侠 逆向工程第003篇:跨越CM4验证机制的鸿沟(上) 逆向工程第004篇:跨越CM4验证机制的鸿沟(中) 逆...

ioio_jy
2014/09/15
0
0
我的友情链接

51CTO博客开发 王春海的博客 桌面虚拟化杂谈 ZJS的微软桌面虚拟化 让"云"无处不在 欢迎光临ciywind博客 snowyan welcome! 海狗哥的流媒体空间 叔宝(孙亮) 下里巴人的家...

abchw
2017/11/22
0
0
我的友情链接

51CTO博客开发 兔样兔森破 王春海的博客 性能测试 Jack zhai 三角阳台的技术笔记本 虚拟化桌面支持 黄锦辉专栏 Citrix、网络工程师 桌面虚拟化杂谈 About:Blank H4cking 月缺 未暖 飞翔的猪 ...

yuanwx0328
2017/11/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Ubuntu常用操作

查看端口号 netstat -anp |grep 端口号 查看已使用端口情况 netstat -nultp(此处不用加端口号) netstat -anp |grep 82查看82端口的使用情况 查找被占用的端口: netstat -tln netstat -tl...

hc321
昨天
0
0
网站cdn的静态资源突然访问变的缓慢,问题排查流程

1.首先我查看了一下是否自己的网络问题,通过对比其他资源的访问速度和下载速度,确认不是 2.通过ping 和 tracert 判断cdn域名能否正常访问,(最后回想感觉这一步可以省略,因为每次最终能访...

小海bug
昨天
0
0
Mybatis 学习笔记四 MyBatis-Plus插件

Mybatis 学习笔记四 MyBatis-Plus插件 maven依赖 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <ve......

晨猫
昨天
2
0
小白带你认识netty(二)之netty服务端启动(下)

承接上一篇小白带你认识netty(二)之netty服务端启动(上),还剩下两步骤:3、注册Selector:将Channel注册到Selector上 和 4、端口的绑定:服务端端口的监听。 3、注册Selector:将Chann...

天空小小
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部