01 JDBC的问题

jdbc编程步骤:

1、 加载、注册数据库驱动   DriverManager

2、 创建并获取数据库链接   Connection

3、 创建jdbc statement/preparedStatement对象

4、 编写sql语句

5、 设置sql语句中的参数(使用preparedStatement)

6、 通过statement执行sql并获取结果

7、 对查询结果进行转换处理并将处理结果返回 

8、 释放资源(关闭Connection,关闭Statement,关闭ResultSet

 

jdbc编程案例:

 

java环境:

jdk1.7.0_72

eclipseindigo

mysql5.1

导入下边的脚本:

 

sql_table.sql:记录表结构

sql_data.sql:记录测试数据,在实际企业开发中,最后提供一个初始化数据脚本

 

使用jdbc查询mysql数据库中用户表的记录。

创建java工程,加入jar包:数据库驱动包(mysql5.1

 

 1 public static void main(String[] args) {
 2             Connection connection = null;
 3             PreparedStatement preparedStatement = null;
 4             ResultSet resultSet = null;
 5             try {
 6                 //加载数据库驱动
 7                 Class.forName("com.mysql.jdbc.Driver");
 8                 
 9             //通过驱动管理类获取数据库链接
10             connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
11 
12                 //定义sql语句 ?表示占位符
13                  String sql = "select * from user where username = ?";
14                 //获取预处理statement
15                 preparedStatement = connection.prepareStatement(sql);
16                 //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
17                 preparedStatement.setString(1, "王五");
18 
19                 //向数据库发出sql执行查询,查询出结果集
20                 resultSet =  preparedStatement.executeQuery();
21                 //遍历查询结果集
22                 while(resultSet.next()){
23                     System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));
24                 }
25             } catch (Exception e) {
26                 e.printStackTrace();
27             }finally{
28                 //释放资源
29                 if(resultSet!=null){
30                     try {
31                         resultSet.close();
32                     } catch (SQLException e) {
33                         e.printStackTrace();
34                     }
35                 }
36                 if(preparedStatement!=null){
37                     try {
38                         preparedStatement.close();
39                     } catch (SQLException e) {
40                         e.printStackTrace();
41                     }
42                 }
43                 if(connection!=null){
44                     try {
45                         connection.close();
46                     } catch (SQLException e) {
47                         e.printStackTrace();
48                     }
49                 }
50             }
51         }

上边使用jdbc的原始方法(未经封装)实现了查询数据库表记录的操作。

jdbc问题总结&解决方案

1 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

  数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。

问题描述:

设想:使用数据库连接池管理数据库连接。

数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题。

通过连接池就可以反复利用已经建立的连接去访问数据库了。减少连接的开启和关闭的时间。

常用的数据库连接池有:c3p0 druid dbcp

2 Sql语句在java代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码,java代码就需要重新编译和发布。

  sql语句硬编码java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。

第一,可读性很差,不利于维护以及做性能调优。

第二,改动Java代码需要重新编译、打包部署。

第三,不利于取出SQL在数据库客户端执行(取出后还得删掉中间的Java代码,编写好的SQL语句写好后还得通过+号在Java进行拼凑)

解决问题:

设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

我们可以考虑不把SQL语句写到Java代码中,那么把SQL语句放到哪里呢?

首先需要有一个统一存放的地方,我们可以将这些SQL语句统一集中放到配置文件或者数据库里面(以key-value的格式存放)。

然后通过SQL语句的key值去获取对应的SQL语句。

既然我们将SQL语句都统一放在配置文件或者数据库中,那么这里就涉及一个SQL语句的加载问题。

3 preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。

  Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

问题描述:

很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,

这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配。

但是,如果我们传入的参数是不确定的(比如列表查询,根据用户填写的查询条件不同,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),

那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句的命运。

既然我们已经把SQL语句统一存放在配置文件或者数据库中了,怎么做到能够根据前台传入参数的不同,动态生成对应的SQL语句呢?

解决问题:

设想:sql语句及占位符号和参数全部配置在xml中。

第一,我们先解决这个动态问题,按照我们正常的程序员思维是,通过ifelse这类的判断来进行是最直观的,这个时候我们想到了JSTL中的<if test=””></if>这样的标签,那么,能不能将这类的标签引入到SQL语句中呢?假设可以,那么我们这里就需要一个专门的SQL解析器来解析这样的SQL语句,但是,if判断的变量来自于哪里呢?传入的值本身是可变的,那么我们得为这个值定义一个不变的变量名称,而且这个变量名称必须和对应的值要有对应关系,可以通过这个变量名称找到对应的值,这个时候我们想到了key-valueMap。解析的时候根据变量名的具体值来判断。

假如前面可以判断没有问题,那么假如判断的结果是true,那么就需要输出的标签里面的SQL片段,但是怎么解决在标签里面使用变量名称的问题呢?这里我们需要使用一种有别于SQL的语法来嵌入变量(比如使用#变量名#)。这样,SQL语句经过解析后就可以动态的生成符合上下文的SQL语句。

还有,怎么区分开占位符变量和非占位变量?有时候我们单单使用占位符是满足不了的,占位符只能为查询条件占位,SQL语句其他地方使用不了。这里我们可以使用#变量名#表示占位符变量,使用$变量名$表示非占位符变量。

sql语句通过#{}表示占位符号,{}中写变量名,也可以写po的属性名。完成自动将java对象映射到sql语句 中。

 

4 resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。

  对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

问题描述:

执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源是一整套下来的。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以搞定了。

解决问题:

设想:将查询的结果集,自动映射java对象。

我们分析一下,一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等等,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值copy到对应的数据结构上。

  接下来,我们可以进而考虑对SQL执行结果的缓存来提升性能。缓存数据都是key-value的格式,那么这个key怎么来呢?怎么保证唯一呢?即使同一条SQL语句几次访问的过程中由于传入参数的不同,得到的执行SQL语句也是不同的。那么缓存起来的时候是多对。但是SQL语句和传入参数两部分合起来可以作为数据缓存的key值。

5 解决重复SQL语句问题

问题描述:

由于我们将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,

有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。

解决问题:

当我们的代码程序出现重复代码时怎么办?

将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。

对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,

然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。

问题优化总结:

我们总结一下上面对JDBC的优化和封装:

1  使用数据库连接池对连接进行管理

2 SQL语句统一存放到配置文件

3 SQL语句变量和传入参数的映射以及动态SQL

4 动态SQL语句的处理

5  对数据库操作结果的映射和结果缓存

6  SQL语句的重复

原文地址:https://www.cnblogs.com/wihainan/p/6247630.html