使用原生jdbc的一些诀窍

最近又需要接触原生jdbc,又遇到了不少问题,同时也学到了不少诀窍。

 

1.在select中使用中文作为查询条件时查不到数据

如果select能正常使用英文作为查询条件,那么很有可能是以下问题

(1)当前数据库不支持utf-8

需要修改配置文件进行手动指定。linux下的配置文件和win下是不同的,这里不做展开讨论。

(2)当前数据库链接的编码没有指定为utf-8

我这次的问题就是出在这里。

一般的数据库链接地址是这样的:

但是如果没有注意,漏掉了数据库characterEncoding=utf8,那么就可能出现这个问题

(3)当前表编码格式不是utf-8

我遇到的默认情况都是utf-8的,但是不排除有极端情况呀。

这就需要手动去修改当前表的编码格式。这里不展开讨论。

以上是最有可能导致该问题的罪魁祸首。特别要注意的是,以上三个条件都要保证无误,不然都有可能导致这个问题。

(4)字段中有不可见字符

很有可能刚好查询的字段中有不可见字符,导致查询条件不匹配。最好把这个字段中的字符全删除了然后重新输入。

2.preparedStatement.execute(sql);

这个错误经常出现在sql需要进行拼接的时候。尤其是使用StringBuilder,用append进行拼接的情况,比较容易出错。

如果使用preparedStatement,一般都是直接preparedStatement.execute()就好

但是,如果指定了sql,就会去执行指定的sql。

这时候就很有可能执行了原始sql(没有进行拼接的sql)。这将导致一系列问题,比如说:因为sql没有拼接完成,所以preparedStatement的参数注入就会不对应,但是报错却会sql执行错误。一旦出现这个错误,大多数人都会浪费精力去找sql本身的问题,很有可能忽略掉实际执行的sql这个小细节。

3.拼接sql语句的技巧

这个其实和一些orm框架的原理比较接近了,都是使用一些技巧进行sql的拼接,实现根据输入的参数调整sql的功能。

示例如下:

如果没有传入相应的参数,那么sql也会自动进行调整。主要应用于update和insert的情况。比如说修改一些信息,一般都是修改哪个就要update哪个。但是我们不可能每个字段都去写一个update。这就要判断输入的参数来实现sql的改变,从而减少工作量。

而且,在不使用orm框架往往会出现以下情景:

假如一个表user下有id,username,password字段,现在我要根据用户id来修改用户的username字段。

我只传入id和username,而且sql没有进行调整。因为password没有传入,就会默认为null,然后就会把本来不想修改的password字段置为空值。

这时候,很多人为了偷懒,就会一次性在前端把修改后的所有字段一次性传入。不只是我们仅仅需要的id和username,而是把不需要修改的password的值又传进来一次。这种做法在带宽足够,表中字段少,update成本很低的情况下(一般情况)是不会导致问题的,但是依然会占用一些资源。

但是如果习惯了这种做法,在写容易遇到性能瓶颈的地方(如中间件),就可能导致一些严重问题。不推荐使用这种做法(虽然我很懒)。

那么有没有更好的解决办法呢?我认为最好的办法是去使用成熟的orm框架,如mybatis。如果要在原生jdbc中做这种优化,要花费很多精力去写相应代码。而且这样做有点像重复造轮子,个人感觉没有效率,不太现实。

4.超多问号

如果使用preparedStatement,而表中的参数又很多,就要特别小心。

写update和insert的sql的时候,如果要进行大量参数注入,sql中就会出现一长串的问号,后面紧跟着一大堆参数注入的语句。这次我写的sql语句有16个问号,想想之前写过30几个字段的sql语句,我就感恩幸好没使用原生的jdbc。

然而现实开发中,难免会遇到各种各样的情况。总有各种各样不科学的设计,要去处理超多问号也是迫不得已的。

5.jdbc使用时间的技巧

jdbc中操作时间总是很麻烦,至少我个人觉得很不方便。所以这个技巧应该很多人都知道。

我写pojo时,一般的日期都是用的java.util中的Date,但是preparedStatement.setDate()方法需要使用java.sql中的Date。因为没有涉及任何基本类型,所以没有自动拆装箱的好事。这里需要经历一次虐心的类型转换。

很多人会上eclipse提示的当:

这样会报错,无法进行类型转换。

要强制进行类型转换,只有这样:

那么问题又来了:

我们拿日期的时候会使用resultSet.getDate(),这个拿出来又是java.sql中的Date,要映射到java.util中的Date,又要再转换一次!

上面繁琐的类型转换还不算什么,最大的问题其实是时间精度丢失的问题,具体如下:

分分钟丢失所有时分秒,这个问题实在是不能再忍了,完全不可行。

如何解决?换用preparedStatement.setTimestamp()

参数注入时:

获取时

这样就能比较好地解决时间这个虐心问题。

5.总结

说了这么多使用jdbc时会导致的问题,也该说说jdbc的好话了。

基本不用配置环境,运行速度快,排错比较简单,还有其他吗,以后我再想想吧。

发表评论

电子邮件地址不会被公开。 必填项已用*标注