详解JDBC连接数据库

一、概念

  1. 为了能让程序操作数据库,对数据库中的表进行操作,每一种数据库都会提供一套连接和操作该数据库的驱动,而且每种数据库的驱动都各不相同,例如mysql数据库使用mysql驱动,oracle数据库使用oracle驱动,这样假如我们编写的程序哪一天想要换数据库,那样就会很不方便,因为所有连接数据库的代码都要从新编写。SUN公司为了简化。统一对数据库的操作,定义了一套java操作数据库的标准或者规范,这个规范就是JDBC。

  2.JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。我们在开发过程中,只要实现它相应的接口就可以非常进行连接。    

  3.我们在开发JDBC应用时,还需要导入相应的数据库的驱动jar包,这些驱动jar包是由数据库公司自己编写的。

 

二、编写JDBC应用程序(需要连接数据库的程序)的前提准备

   1.首先要确定连接的是哪个数据库实例,例如在mysql中,我们可以先创建一个库,然后在库中新建一张表,在表中插入一些数据,我在这里提供一段在mysql数据库中创建一个库,以及表和数据的sql语句,这也是下面连接数据库后操作的库和表。

复制代码
create database test ;     /*创建一个名为Test的数据库*/
use test;              /*使用该数据库或者说切换到该数据库*/
create table book (id int primary key auto_increment,  /*列:id ,类型:int,从0开始,自动增加, 备注:主键*/name varchar(40) NOT NULL,        /*列:name ,类型:varchar, 备注:非空*/author varchar(40)NOT NULL,        /*列:author ,类型:varchar, 备注:非空*/prices double NOT NULL            /*列:prices ,类型:double, 备注:非空*/
);        /*新建一张名为book的表*/
/*插入四大名著的数据*/
insert into book(id,name,author,prices) values (null,'西游记','吴承恩',25.00);
insert into book(id,name,author,prices) values (null,'水浒传','施耐庵',30.00);
insert into book(id,name,author,prices) values (null,'红楼梦','曹雪芹',35.00);
insert into book(id,name,author,prices) values (null,'三国演义','罗贯中',40.00);
复制代码

   2.新建一个java项目,然后把mysql的驱动jar包导入进来,即添加到程序运行的库中,具体的驱动jar包,我们可以在数据库的安装目录下找到,或者都网上自己下载相对应的数据库驱动jar包

 

三、连接数据库操作的步骤解析

  (1)注册数据库驱动

    虽然我们刚才在新建java项目的时候将mysql数据库的驱动jar包导入进来了,但是JBDC不知道这里有一个驱动包,此时我们就需要将这个驱动包交给JBDC去管理,我们可以使用java.sql包下的DriverManager 工具类 提供的registerDriver(Driver driver) 方法来在JDBC中注册这个数据驱动,这个registerDriver(Driver driver)方法需要一个Driver对象,而这个Driver类本身是JDBC提供的一个接口,我们的驱动里面已经实现了这个接口所以我们只需要写如下代码就可以实现注册数据库驱动的功能

  

import java.sql.DriverManager; //需要导入的是接口类包
DriverManager.registerDriver(new Driver());

  

  (2)获取(创建)数据库的连接

   我们注册好数据库驱动后,并没有连接上数据库,以往,我们不管在CMD窗口下,通过可视化数据库管理工具操作数据库时,我们都需要先连接数据库服务器,java程序连接数据库也不例外,这里的java程序就相当于客户端,只有先连接上数据库服务,才能对数据库进行操作

客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:

      createStatement():创建向数据库发送sql的statement对象。

      prepareStatement(sql) :创建向数据库发送预编译sql的

  这里我们可以通过DriverManager 工具类里的getConnection(url,user,password)方法来创建数据库连接对象,此方法需要传入三个参数:

              User: 数据库的用户名

              Password:用户密码

       URL:数据库服务器地址,不同的数据库的URL写法不同,我在这里提供三种主流数据库的URL地址写法:

        Oracle写法:jdbc:oracle:thin:@localhost:1521:sid

        SqlServe写法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid

        MySql写法:jdbc:mysql://localhost:3306/sid

        Mysql的url地址的简写形式: jdbc:mysql:///sid

        注:后面的sid就是数据库的实例名称(使用的数据库名)

import java.sql.Connection; //导入的是接口类包
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"); //这里使用的是一个名为test的mysql数据库,用户名和密码都是root

 

  (3)创建传输器对象

  上面我们已经创建了数据库的连接,已经连上数据库了,但是如果我们想要操作该数据库,我们需要用到sql语句,而我们怎样使用在java程序中使用sql语句来操作数据库呢,这里我们就需要一个传输器对象来传输sql语句到数据库中去执行。上文提到在Connection 类中就有一个createStatement()的方法可以创建一个传输器对象

import java.sql.Statement; //导入的是接口类包
Statement stat = conn.createStatement();

   

  (4)利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回

  java.sql.Statement身上有许多传输sql语句的方法:其中用的最多的是

    executeQuery(String sql) :用于向数据发送查询语句。

    executeUpdate(String sql):用于向数据库发送insert、update或delete语句

    execute(String sql):用于向数据库发送任意sql语句

   

import java.sql.ResultSet; //需要导入的接口类包
ResultSet rs =  stat.executeQuery("select * from book"); //传输一条查询语句,查询book表中所有的元组数据

 

  (5) 遍历结果集,并获取查询对象

     Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。

  ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:

  获取指定类型的数据,例如:

    getString(int index)

    getString(String columnName)

  ResultSet还提供了对结果集进行滚动的方法:

    next():移动到下一行

    Previous():移动到前一行

    absolute(int row):移动到指定行

    beforeFirst():移动resultSet的最前面。

    afterLast() :移动到resultSet的最后面。

while(rs.next()){String name = rs.getString("name");System.out.println(name);
}

 

  (6)关闭连接(先创建的后关闭)

  Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。

  特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

rs.close(); 
stat.close();
conn.close();

 

  初期完整的源代码

复制代码
 1 package jdbcDemo;2 /****************************3  * 初版连接数据库程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 //不能导入 java.sql 中的 Driver 接口,要导入驱动jar包中实现该接口的类,只有这要才能注册相对应的数据库驱动
11 import com.mysql.jdbc.Driver; 
12 public class JDBCTest {
13     public static void main(String[] args) throws SQLException  {
14         //1.注册数据库驱动
15         DriverManager.registerDriver(new Driver());
16         //2.获取数据库的连接 
17         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
18         //3.创建传输器对象
19         Statement  stat = conn.createStatement();
20         //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
21          ResultSet rs =  stat.executeQuery("select * from book");
22         //5.遍历结果集,并获取查询结果
23         while(rs.next()) {
24             String name = rs.getString("name");
25             System.out.println(name);
26         }
27         //6.关闭连接(后开先关)
28         rs.close(); 
29         stat.close();
30         conn.close();
31     }    
32 }
复制代码

  数据表视图和运行结果:

    

 

四、初期连接数据库程序中出现的问题

   1--注册数据库驱动方法不当导致出现了两次注册,程序通用性低

  我们在查看Driver类的源码中可以看到如下代码,从第7行代码中我们可以看到,mysql在Driver类的实现中自己注册了一次,而我们在程序中又注册了一次,导致注册两次

  我们在注册驱动时,需要导入mysql驱动jar包中已经实现的Driver类,这样程序就和具体的数据库绑定在一起了,程序的通用性就降低了,如果我们想要切换数据库,还得改动源码

      

复制代码
 1 public class Driver extends NonRegisteringDriver implements java.sql.Driver {2     //3     // Register ourselves with the DriverManager4     //5     static {6         try {7             java.sql.DriverManager.registerDriver(new Driver());8         } catch (SQLException E) {9             throw new RuntimeException("Can't register driver!");
10         }
11     }
复制代码

  修复方法:

  使用Class.forname() 方法将mysql中已经实现的Driver类加载到程序中来,由于Driver类在实现接口时使用的是静态代码块,而静态代码块只会在类加载的时候执行一次,即保证了数据库驱动只会被注册一次,同时不用导入mysql驱驱动里的类包,程序通用性提高

Class.forName("com.mysql.jdbc.Driver");

  

  2--忽略了程序中可能会抛出的异常(最大的问题)

  我们在执行程序时,它的许多方法的调用都会抛出异常,如果它抛出异常后,没有做相应的处理(catch 这个异常)那么程序就会中断执行,Statement对象和Connection对象就没有被关闭,而我们知道Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机,所以我们需要保证无论程序中哪一步出现了异常导致程序中断,连接关闭的代码都会被执行,此时我们就会想到异常处理中的finally代码块,我们可以把异常向上抛出,而是先 try 住然后 catch 异常,最后执行 finally 代码块

  修改之后,我们发现每个close() 都提示有异常要处理,此时我们也直接 try/catch 每个异常

  修改后的源代码:

复制代码
 1 package jdbcDemo;2 /****************************3  * 修改版连接数据库程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 
11 public class JDBCTest {
12     public static void main(String[] args)  {
13         Connection conn = null;
14         Statement stat = null;
15         ResultSet rs = null;
16         try {
17                 //1.注册数据库驱动
18                 Class.forName("com.mysql.jdbc.Driver");
19                 //2.获取数据库的连接 
20                  conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
21                 //3.创建传输器对象
22                   stat = conn.createStatement();
23                 //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
24                   rs =  stat.executeQuery("select * from book");
25                 //5.遍历结果集,并获取查询结果
26                 while(rs.next()) {
27                     String name = rs.getString("name");
28                     System.out.println(name);
29                 }
30         }catch(Exception e) {
31             e.printStackTrace();
32         }finally {
33             //6.关闭连接(后开先关)
34             try {
35                 rs.close();
36             } catch (SQLException e) {
37                 e.printStackTrace();
38             } 
39             try {
40                 stat.close();
41             } catch (SQLException e) {
42                 e.printStackTrace();
43             }
44             try {
45                 conn.close();
46             } catch (SQLException e) {
47                 e.printStackTrace();
48             }
49         }
50     }    
51 }
复制代码

 

五、修改后程序中被忽略的异常

  异常问题

  1.由于我们在程序开头先声明了三个对象的引用,并且都赋值为null,假如程序在执行到注册数据库这一步时就抛出了异常,此时catch 到这个异常 后执行finally 代码块,结果发现ResultSet 对象的引用,Connection对象的引用以及Statement对象的引用都是空值,调用这个对象上的方法就会抛出空指针异常

  2.close()这个方法身上也有异常,如果我们不做相应的异常处理,那些对象还是不能被正常关闭

  解决办法

1---为了防止出现空指针异常,我们可以先判断哪些对象的引用是否为null,如果不为null,则执行异常处理代码

2---在每个close()异常处理后在加上一个finally静态代码块,将每个相应对象的引用值置为null,原理是:如果程序执行到close() 方法并抛出了异常,那么最后finally代码块执行,给该对象的应用值置为null,由于这个对象没有任何引用指向它,它就成为了垃圾对象,JVM垃圾回收器就会回收这个对象资源,这个对象也就关闭了

  异常处理完后最终的源代码:

复制代码
 1 package jdbcDemo;2 /****************************3  * 无异常版连接数据库程序4  **************************/5 import java.sql.Connection;6 import java.sql.DriverManager;7 import java.sql.ResultSet;8 import java.sql.SQLException;9 import java.sql.Statement;
10 
11 public class JDBCTest {
12     public static void main(String[] args)  {
13         Connection conn = null;
14         Statement stat = null;
15         ResultSet rs = null;
16         try {
17                 //1.注册数据库驱动
18                 Class.forName("com.mysql.jdbc.Driver");
19                 //2.获取数据库的连接 
20                  conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
21                 //3.创建传输器对象
22                   stat = conn.createStatement();
23                 //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
24                   rs =  stat.executeQuery("select * from book");
25                 //5.遍历结果集,并获取查询结果
26                 while(rs.next()) {
27                     String name = rs.getString("name");
28                     System.out.println(name);
29                 }
30         }catch(Exception e) {
31             e.printStackTrace();
32         }finally {
33             //6.关闭连接(后开先关)
34             if(rs != null) {
35                     try {
36                         rs.close();
37                     } catch (SQLException e) {
38                         e.printStackTrace();
39                     } finally {
40                         rs = null;
41                     }
42             }
43             if(stat != null) {
44                     try {
45                         stat.close();
46                     } catch (SQLException e) {
47                         e.printStackTrace();
48                     }finally {
49                         stat = null;
50                     }
51             }
52             if(conn != null) {
53                     try {
54                         conn.close();
55                     } catch (SQLException e) {
56                         e.printStackTrace();
57                     }finally {
58                         conn = null;
59                     }
60             }    
61         } //--finally
62     } //--main    
63 }//--class
复制代码

 

总结:

   这里我只是把所有的异常处理完,但是程序的通用性还不是特别高,因为连接数据库用到的Driver类名、URL、user以及password 都写在程序中,我们其实可以写在一个文本文件中,通过对文件的读取来获得每种数据库特有的连接参数。

  还有就是在实际开发过程中,连接数据库的程序代码一般会写在一个工具类中,我们想要对数据库中的数据进行操作时,只需要调用这个工具类就可以了,不用每次都写那么多代码

  接下来我还会更新一篇如何将数据库的连接信息保存在文本文件中,然后读取这个文件来实现连接数据库的操作,同时我也会将这个程序修改为连接数据库的一个工具类

转载于:https://www.cnblogs.com/zhuyeshen/p/10968080.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ZOJ4024 Peak

题意 给出一个数组 判断这个数组是否形成了一个“山峰” 即中间有个数最大 从第一个数到这个数递增 从这个数到最后一个数递减 模拟 从两端分别以递增和递减判断 看第一个不满足递增或递减的数是否相等并且没越界就可以了 AC代码&#xff1a; 1 #include<bits/stdc.h>2 u…

springmvc跨域问题

1、跨域问题&#xff1a; 按照网上所有的方法试了一遍&#xff0c;都没跨过去&#xff0c;正在无助之际&#xff0c;使用filter按照下面的方法解决的时候出现了转机&#xff1a; 添加filter&#xff1a; package com.thc.bpm.filter;import javax.servlet.*; import javax.serv…

成功秀了一波scala spark ML逻辑斯蒂回归

1、直接上官方代码&#xff0c;调整过的&#xff0c;方可使用 package com.test import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.mllib.classification.{LogisticRegressionModel, LogisticRegressionWithLBFGS} import org.apache.spark.mllib.e…

nodeJS中的异步编程

nodejs 不是单线程 在博客项目中关于异步问题&#xff1a; 1.当用户添加一条博客时 需要通过post方式向服务器发送数据 后台获取用户以post方式拿到传送过来的数据 然后存入数据库&#xff1a; 上面的代码&#xff1a;创建一个空字符串 当用户向服务器发送请求时出发data事件将…

nodeJs 操作数据库

首先在node中下载mysql包 npm install mysql 连接数据库 var mysql require(mysql); var con mysql.createConnection({host : localhost,user : root,password : root,database : blog });开启链接 con.connect();执行增删改查 不同功能创建不同的sql语句即可…

总结面试题——Javascript

文章目录1.闭包2.作用域链3.JavaScript的原型 原型链 有什么特点4.事件代理5.Javascript如何实现继承6.this对象7.事件模型8.new操作符9.ajax原理10.解决跨域问题11.模块化开发怎么做12.异步加载js的方式有哪些13.会造成内存泄漏的操作14.XML和JSON的区别15.webpack16.AMD和Com…

OAuth2.0 知多少

OAuth2.0 知多少 原文:OAuth2.0 知多少1. 引言 周末逛简书&#xff0c;看了一篇写的极好的文章&#xff0c;点击大红心点赞&#xff0c;就直接给我跳转到登录界面了&#xff0c;原来点赞是需要登录的。 可是没有我并没有简书账号&#xff0c;一直使用的QQ的集成登录。下面有一排…

五分钟带你摸透 Vue组件及组件通讯

一.组件化开发 组件 (Component) 是 Vue.js 强大的功能之一。组件可以扩展 HTML 元素&#xff0c;封装可重用的代 码。在较高层面上&#xff0c;组件是自定义元素&#xff0c;Vue.js 的编译器为它添加特殊功能。在vue中都是组件化开发的&#xff0c;组件化开发就是把一个完整的…

微信公众号开发-接入

一 首先实现内网穿透&#xff0c;公众号需要连接我们的服务器&#xff0c;内外无法访问&#xff0c;所以先实现自己的内网可以测试时连接外网&#xff0c;下载natapp&#xff0c;选择windows&#xff0c;顺便下载config,ini 配置文件。注册好购买免费的隧道 然后将token写入配置…

Vue 项目上线优化

上线项目的优化 优化上线项目&#xff0c;首先在上线打包时我们通过babel插件将console清除&#xff0c;当然对项目打包后的体积的影响是微乎其微&#xff0c;对项目的入口文件的改善也是很有必要的&#xff0c;因为在开发阶段和上线如果我们使用的是同一入口文件&#xff0c;…

Python并发编程—进程

多任务编程 1.意义&#xff1a; 充分利用计算机多核资源&#xff0c;提高程序的运行效率。 2.实现方案 &#xff1a;多进程 &#xff0c; 多线程 3.并行与并发 并发 &#xff1a; 同时处理多个任务&#xff0c;内核在任务间不断的切换达到好像多个任务被同时执行的效果&#xf…

Vue 脚手架中的.eslintrc.js代码规范 的解决

在我们使用Vue脚手架 创建项目时 尤其是团队共同开发项目时 会按照一个共同的代码规范来编程 创建Vue脚手架中有一个.eslintrc.js格式 但是在编程中我们通常会使用 shiftaltf 进行代码格式化 但是由于格式化后的代码 与Vue中的.eslintrc规范不协调 尤其是 “” &#xff1b; 以…

前端面试---Vue部分考点梳理

一. Vue的使用 1. Vue的基本使用 指令 插值 插值 表达式 指令 动态属性 v-html 会有XSS风险 会覆盖子组件 computed 和 watch computed 有缓存 data不变则不会重新计算watch 如何深度监听watch 监听引用类型时 拿不到oldVal v-for v-for 和 v-if 不能同时使用:key的值尽量…

.net core实现跨域

什么是跨域在前面已经讲解过了&#xff0c;这里便不再讲解&#xff0c;直接上代码。 一、后台API接口 用.net core创建一个Web API项目负责给前端界面提供数据。 二、前端界面 建立两个MVC项目&#xff0c;模拟不同的ip&#xff0c;在view里面添加按钮调用WEB API提供的接口进行…

TCP/IP简介

TCP/IP简介 OSI的“实现”&#xff1a;TCP/IP参考模型 并不完全符合OSI的七层参考模型&#xff0c;但我们可以理解为OSI的一种实现 TCP/IP协议简述 在很多情况下&#xff0c;它只是利用IP协议进行通信时&#xff0c;所必须用到的协议群的统称&#xff0c;具体来说&#xff0c;I…

Spring-Cloud 学习笔记-(4)负载均衡器Ribbon

目录 Spring-Cloud 学习笔记-&#xff08;4&#xff09;负载均衡器Ribbon1、前言2、什么是负载均衡2.1、问题分析2.2、什么是Ribbon3、快速入门3.1、实现方式一3.1.1、修改代码3.2、实现方式二3.2.1、启动类3.2.2、调用代码3.2.3、测试3.2.4、实现原理3.2.5、断点调式3.3、修改…

‘仿微信发表朋友圈’项目中登录功能的业务逻辑

登录功能 手机号验证码都通过后端验证后 返回用户数据 登陆成功 成功后 调用store中的setUser方法 store中的setUser方法 将后端返回的用户信息存储到localStorage中 同时登录成功后服务器会将token自动存入我们的cookie中 有过期时间 在我们请求需要登录的接口时将cookie中的…

kubernetes--配置文件

转载于:https://www.cnblogs.com/caiciadeliliang/p/10993388.html

微信动态中的背景图更换

初衷&#xff1a; 图一中的红框中的部分&#xff0c;作为用户自定义的背景图&#xff0c;如果用户没有上传也会为其自动设置一张背景图&#xff0c;当用户点击时则会出现图二中的选项 &#xff0c;点击取消则选项消失&#xff0c;点击从相册选择则会跳转本机的相册&#xff0c…

大数据学习——akka自定义RPC

实现 package cn.itcast.akkaimport akka.actor.{Actor, ActorSystem, Props} import akka.actor.Actor.Receive import com.typesafe.config.ConfigFactoryimport scala.collection.mutableimport scala.concurrent.duration._class Master(val host: String, val port: Int) …