Java--JDBC连接数据库

     我们知道Java中的jdbc是用来连接应用程序和数据系统的,本篇文章主要就来看看关于JDBC的实现和使用细节。主要包含以下几点内容:

  • JDBC的基本知识(数据驱动程序)
  • JDBC的连接配置
  • 使用JDBC增删改查
  • JDBC的一些使用细节

一、JDBC的基本知识      我们用Java写的程序,无论是桌面应用程序还是web应用程序都是不能直接访问我们本机上的数据库系统的,这就需要使用驱动程序去构成两者之间的连接。

像这样,我们的应用程序需要针对不同的数据库系统调用不同的驱动程序来连接操作数据库系统,但是对于不同的数据库系统,我们就需要学习他们各自提供的驱动程序接口的使用,还是比较麻烦的。并且程序一旦数据迁移,将导致关于数据操作的代码模块需要重写。      于是sun公司为了简化Java对数据库的连接操作,定义了一套Java操作数据库的规范,JDBC(Java Database Connectivity)。从此程序员就可以使用纯Java代码连接和操作数据库了。

JDBC向上提供了一系列的使用接口,包括连接数据库,增删改查操作等。向下会去调用相对应了驱动程序,然后这些驱动程序又会去直接的操作数据库,执行sql语句,返回结果。对于我们程序员,只需要学习怎么使用JDBC,不用再去关心各个驱动程序怎么使用。

二、JDBC的连接配置      想要成功的使用jdbc连接我们的本地数据库主要需要以下几个步骤:

  • 下载对应的数据库系统提供的驱动程序
  • 将驱动程序包添加到jdk包中
  • 调用 DriverManager 类的 getConnection()获取数据库连接对象

     下面一步步演示并解释,首先下载对应的DBMS(数据库管理系统提供驱动程序),你可以使用IBM的DB2,或者微软的Sql Server,或者mysql。本篇文章使用的是sql server。下载地址:https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=11774 。运行sqljdbc_6.0.8112.100_chs.exe解压文件,或者直接解压sqljdbc_6.0.8112.100_chs.tar.gz,然后进入解压出来的文件夹,找到jre文件夹,(应该有两个版本7,8),找到对应自己的jdk版本,复制里面的sqljdbc42.jar包,到本机的jdk文件夹。 默认应该在:C:\Program Files\Java中,进入jdk文件夹中(不要进错了),然后jre\lib\ext,将刚刚的jdbc包粘贴到其中即可。      下面打开IDE创建一个project,main函数中粘贴以下代码,具体什么意思,后文会说。

public static void main(String[] args){

        String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver";
        String dbURL="jdbc:sqlserver://localhost:1433;DatabaseName=你的某个数据库的名字";
        String userName="你的数据库登录名";
        String userPwd="你的数据库登录密码";
        try{
            //加载驱动程序
            Class.forName(driverName);
            //获取连接对象
            Connection dbConn= DriverManager.getConnection(dbURL, userName, userPwd);
            System.out.println("数据库连接成功");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

     运行以上代码如果打印连接成功,就继续下文。否则,可以评论留言或者自行百度解决。下面开始解释每一条语句:      首先,所有的操作的前提都是告诉jvm我们的程序将要使用的数据驱动是什么,是mysql,sqlserver,还是oracle。Class.forName(driverName);这条语句就是这个作用,我们看driverName字符串。

装载MySql驱动:Class.forName("com.mysql.jdbc.Driver");

装载Oracle驱动:Class.forName("oracle.jdbc.driver.OracleDriver");

装载SqlServer驱动:Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

我们上述代码中使用的driverName的值是第三种中的参数值,主流的数据库管理系统是这三者,这三句代码是不变的,读者可以根据自己电脑上的数据库自行选择。      第二步就是获取连接对象,如果没有抛异常就说明连接是成功的,我们首先从三个参数说起。第一个参数是一个URL,他的格式是:jdbc:<子协议>:<子名称>,这种格式基本上也是被每个数据库提供商定死了,你只需要选择他们并增加自己的参数即可。常见的三个URL格式:

对于 Oracle 数据库连接,采用如下形式:
jdbc:oracle:thin:@localhost:1521:sid

对于 SQLServer 数据库连接,采用如下形式:
jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=sid

对于 MYSQL 数据库连接,采用如下形式:
jdbc:mysql://localhost:3306/sid

sid就是本地数据库中某个具体数据库的名字。下面说第二个参数,从命名上读者也是可以轻松的判断出这是在判别身份,第三个参数是密码。相信这三个参数还是可以很轻松理解的。下面看看DriverManager类和他的一些方法。      DriverManager可以叫它驱动程序管理接口,主要实现的是对驱动程序的管理的功能。例如:初始化驱动程序,启动驱动程序建立jdbc连接对象,还有一些获取日志信息的操作。我们主要用它来创建数据库连接对象,然后通过这个对象操作数据库的增删改查。此间如果数据库连接失败将会抛出异常。下面我们介绍这个连接对象,并通过它完成增删改查。

三、使用JDBC增删改查      实现增删改查的操作的前提是需要获取数据库连接对象。以下是这个Connection接口的主要方法:

Statement createStatement()
PreparedStatement prepareStatement(String sql)
CallableStatement prepareCall(String sql)

先看第一个方法,这个方法返回一个Statement对象,这个对象是用来向数据库发送静态sql语句的,第二个方法返回了一个PreparedStatement对象,这是一个预编译的Statement对象,主要用来发送动态的sql语句的。具体的区别下文说。第三个方法返回的对象是用来执行存储过程的相关操作的。      下面我们看可以操作一般sql语句的对象Statement。他有如下常用方法:

ResultSet executeQuery(String sql)
int executeUpdate(String sql)
boolean execute(String sql)
int[] executeBatch()
void addBatch( String sql )

测试方法executeQuery

public static void main(String[] args){
        try{

            //加载驱动程序
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            //获取连接对象
            Connection dbConn= DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName=FitWeb", "sa", "123456");
            Statement statement = dbConn.createStatement();
            ResultSet rs =  statement.executeQuery("SELECT * FROM users");

            while(rs.next()){
                System.out.println(rs.getString("name"));
            }
            rs.close();
            dbConn.close();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    //程序的输出结果是我的表FitWeb中users表中字段名为name的所有的值

对于上代码中的ResultSet结果集的相关操作,暂时可以先过。只需要知道我们向executeQuery方法中传入可执行的sql语句,他会返回执行之后的结果。对于方法executeUpdate主要是完成对数据表的增删改。

int x = statement.executeUpdate("UPDATE users SET NAME = '华为' WHERE NAME ='李斯'");

可以像这样修改表中数据,还可以insert,delete等操作。对于execute方法,它不区分是查询还是修改操作,你可以向他传入任意的sql语句,只是对于查询不会返回结果集,如果成功的修改了表中内容返回true,否则false。下面看看批处理sql操作:

Statement statement = dbConn.createStatement();
statement.addBatch("UPDATE users SET NAME ='Walker' WHERE NAME = '华为'");
statement.addBatch("UPDATE users SET NAME ='华为' WHERE NAME = 'Walker'");
int[] count = statement.executeBatch();
 for(int c : count){
   System.out.print(c);
   System.out.print(",");
 }
 statement.close();
 dbConn.close();
//输出结果:1,1

     之前的方法都只能一次操作一条sql语句,而我们的executeBatch是用来一次执行多条sql语句的,返回值是int数组,它表示了每一次操作数据库之后影响的行数。第一次sql执行之后影响的行数保存在索引为0中,后面以此类推。关于预编译Statement的操作,我们放在下一个小节说。

四、JDBC的一些使用细节      SQL注入的大名想必大家都是知道的,而在我们之前介绍的方法中,好像都没有关于如何防止这种黑客行为。SQL注入就是指在带有参数的sql语句中注入的sql语法。类似这样:

select * from users where name = userName

如果我们的应用程序中需要查询某个人的信息,而查询的条件是需要用户输入自己的用户名,然后我们根据用户名进行查询,向上面一样如果用户输入的是以下内容:

userName = "'张三' or '李四'";
select * from users where name = userName
等价:
select * from users where name = '张三' or '李四'

这样岂不是将张三和李四的信息都查询出来了,如果此人通过大数据列举,很可能数据表中的所有数据都会被查询出来。      我们可以使用,预编译Statement对象来避免这件事情。先看代码:

PreparedStatement statement = dbConn.prepareStatement("insert into user(id,Name) values (?,?)");
statement.setInt(1,1);
statement.setString(2,"walker");

statement.executeUpdate();

statement.close();
dbConn.close();

     程序运行的结果是,插入一条数据到了我的user表中。接下来我们看看每条语句是什么含义。首先,?表示占位符的意思,就是说此处会有参数传入,只是具体的值是什么暂时不知道。下面的两条setXXX就是在为占位符赋值,然后执行更改操作,完成数据库更新。我们说为什么它能够防止Sql注入呢?因为所有用户的输入参数都是用?占位,也就是说无论你传入的是什么,我都只把你当做参数。

userName = "'张三' or '李四'";
select * from users where name = ?
等价:
select * from users where name = ''张三' or '李四''
//相当于:'?',无论?是什么都不会产生任何问题

     另外,使用这种预编译Statement,可以很大程度上提高性能,因为他会缓存sql模板,就是除了参数部分,其余内容会被缓存,等到下次再遇到的时候会直接调用,提高性能。因此建议使用这种方式来操作数据库。

     最后详细的介绍一下,关于结果集的操作。本篇刚开始的时候用过,但是那只是很简单的一部分。ResultSet(结果集)接口的主要方法如下:

boolean next()
String getString(int columnIndex)
boolean getBoolean(int columnIndex)
int getInt(int columnIndex)
String getString(String columnLabel)

java.sql.Date getDate(int columnIndex)
java.sql.Time getTime(int columnIndex)
java.sql.Timestamp getTimestamp(int columnIndex)

void beforeFirst()
void afterLast()

Blob getBlob(int columnIndex)
Clob getClob(int columnIndex)

     这个接口有着四千多行的代码,我们只列举了常用的方法。我们可以将整个结果集理解为一张二维的表,每张表都有一个游标用于遍历所有的行。next()方法用于判断是否还有下一行,返回值是boolean。getXXX方法表示获取当前游标指向的行中指定的字段,可以使用索引来定位字段,也可以是通过字段的名字来定位。如果是索引,1为起始位置。      关于LOB类型数据,这是一类大对象,往往是图片或者是一些其他的数据。二进制大对象称作BLOB,字符型大对象称作CLOB。调用getBlob或者getClob可以获取到相应的对象。通过他们自己内部的getBytes,或者getInputStream等方法,可以获取其中的内容。此处不细说。      下面看看多结果集的操作,看代码:

Statement statement = dbConn.createStatement();
boolean b = statement.execute("select * from users;select * from sports;");
    if(b){
         ResultSet rs = statement.getResultSet();
         while (rs.next()){
             System.out.println(rs.getString("name"));
          }
        b = statement.getMoreResults();
        if (b){

         ResultSet rs2 = statement.getResultSet();
           while (rs2.next()){
               System.out.println(rs2.getString("sportsName"));
                    }
                }
            }
            statement.close();
            dbConn.close();

我们调用execute方法执行sql语句,而需要执行的是两条sql语句,如果成功的获取了结果集则返回true。通过getResultSet方法获取第一个结果集,输出所有字段名为name的信息,调用getMoreResults方法判断是否有别的结果集,如果有返回true。然后通过getResultSet获取当前结果集,也就是第二个结果集,输出信息。

为了不使文章篇幅过长,还剩下一个知识点放在下篇。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏salesforce零基础学习

salesforce 零基础学习(三十七) DML及Database方法简单描述

在apex中通过soql查询可以使用两种方式,使用DML语句或者使用Database的方法。 使用DML语句和使用Database类的方法对于我们来说用的都很多...

1927
来自专栏更流畅、简洁的软件开发方式

我自己写的一个分页控件(源码和演示代码)PostBack分页版 for vs2003、SQL Server

温馨提示: asp.net分页控件已经升级了,基于.net2.0 ,支持多种数据库。 正式命名为:QuickPager Asp.net 2.0 分页控件。 ...

1865
来自专栏分布式系统进阶

Librdkafka的基础数据结构 2 --- 定时器 原子操作与引用计数

引用了一个新的struct来将引用计数和调用信息结合起来, 使用链表来管理这个struct的对象. 每次对引用计数的操作都要操作这个链表.

551
来自专栏blackpiglet

Go 语言反射和范型在 API 服务中的应用

  API 接口自然是要获取传过来的数据,不同接口要获取的数据自然也不一样,如果不做特殊处理,必然是每个接口都有一堆功能重复的从 request 里获取参数的代...

542
来自专栏Kevin-ZhangCG

MySQL数据库实用技巧

培养兴趣   兴趣是最好的老师,不论学习什么知识,兴趣都可以极大地提高学习效率。当然学习MySQL 5.6也不例外。 夯实基础   计算机领域的技术非常强调基础...

911
来自专栏数据和云

【千里之行始于足下】谈Oracle的system表空间

编辑手记:SYSTEM表空间是Oracle数据库最重要的表空间,在创建数据库时被最先创建,其中包含了数据库的元数据,对于数据库来说生死攸关。对于很多初学者,全面...

3155
来自专栏流柯技术学院

loadrunner动态从mysql取值

loadrunner动态从mysql取值 [需要下载跟数据库服务器一致的dll,32位或64位]

563
来自专栏H2Cloud

游戏服务器ID生成器组件

游戏服务器程序中,经常需要生成全局的唯一ID号,这个功能很常用,本文将介绍一种通用ID生成组件。游戏服务器程序中使用此组件的场景有:  创建角色时,为其分配唯一...

3908
来自专栏Java3y

Hibernate入门这一篇就够了

前言 本博文主要讲解介绍Hibernate框架,ORM的概念和Hibernate入门,相信你们看了就会使用Hibernate了! 什么是Hibernate框架?...

2924
来自专栏技术小黑屋

Android 中 SQLite 性能优化

数据库是应用开发中常用的技术,在Android应用中也不例外。Android默认使用了SQLite数据库,在应用程序开发中,我们使用最多的无外乎增删改查。纵使操...

821

扫码关注云+社区