这里有新鲜出炉的 Java 并发编程示例,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
本文主要介绍了 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();
初期完整的源代码
- package jdbcDemo;
- /****************************
- * 初版连接数据库程序
- **************************/
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- //不能导入 java.sql 中的 Driver 接口,要导入驱动jar包中实现该接口的类,只有这要才能注册相对应的数据库驱动
- import com.mysql.jdbc.Driver;
- public class JDBCTest {
- public static void main(String[] args) throws SQLException {
- //1.注册数据库驱动
- DriverManager.registerDriver(new Driver());
- //2.获取数据库的连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
- //3.创建传输器对象
- Statement stat = conn.createStatement();
- //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
- ResultSet rs = stat.executeQuery("select * from book");
- //5.遍历结果集,并获取查询结果
- while (rs.next()) {
- String name = rs.getString("name");
- System.out.println(name);
- }
- //6.关闭连接(后开先关)
- rs.close();
- stat.close();
- conn.close();
- }
- }
数据表视图和运行结果:
四、初期连接数据库程序中出现的问题
1-- 注册数据库驱动方法不当导致出现了两次注册,程序通用性低
我们在查看 Driver 类的源码中可以看到如下代码,从第 7 行代码中我们可以看到,mysql 在 Driver 类的实现中自己注册了一次,而我们在程序中又注册了一次,导致注册两次
我们在注册驱动时,需要导入 mysql 驱动 jar 包中已经实现的 Driver 类,这样程序就和具体的数据库绑定在一起了,程序的通用性就降低了,如果我们想要切换数据库,还得改动源码
- public class Driver extends NonRegisteringDriver implements java.sql.Driver {
- //
- // Register ourselves with the DriverManager
- //
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch(SQLException E) {
- throw new RuntimeException("Can't register driver!");
- }
- }
修复方法:
使用 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 每个异常
修改后的源代码:
- package jdbcDemo;
- /****************************
- * 修改版连接数据库程序
- **************************/
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- public class JDBCTest {
- public static void main(String[] args) {
- Connection conn = null;
- Statement stat = null;
- ResultSet rs = null;
- try {
- //1.注册数据库驱动
- Class.forName("com.mysql.jdbc.Driver");
- //2.获取数据库的连接
- conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
- //3.创建传输器对象
- stat = conn.createStatement();
- //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
- rs = stat.executeQuery("select * from book");
- //5.遍历结果集,并获取查询结果
- while (rs.next()) {
- String name = rs.getString("name");
- System.out.println(name);
- }
- } catch(Exception e) {
- e.printStackTrace();
- } finally {
- //6.关闭连接(后开先关)
- try {
- rs.close();
- } catch(SQLException e) {
- e.printStackTrace();
- }
- try {
- stat.close();
- } catch(SQLException e) {
- e.printStackTrace();
- }
- try {
- conn.close();
- } catch(SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
五、修改后程序中被忽略的异常
异常问题
1. 由于我们在程序开头先声明了三个对象的引用,并且都赋值为 null, 假如程序在执行到注册数据库这一步时就抛出了异常,此时 catch 到这个异常 后执行 finally 代码块,结果发现 ResultSet 对象的引用,Connection 对象的引用以及 Statement 对象的引用都是空值,调用这个对象上的方法就会抛出空指针异常
2.close() 这个方法身上也有异常,如果我们不做相应的异常处理,那些对象还是不能被正常关闭
解决办法
1--- 为了防止出现空指针异常,我们可以先判断哪些对象的引用是否为 null, 如果不为 null,则执行异常处理代码
2--- 在每个 close() 异常处理后在加上一个 finally 静态代码块,将每个相应对象的引用值置为 null, 原理是:如果程序执行到 close() 方法并抛出了异常,那么最后 finally 代码块执行,给该对象的应用值置为 null, 由于这个对象没有任何引用指向它,它就成为了垃圾对象,JVM 垃圾回收器就会回收这个对象资源,这个对象也就关闭了
异常处理完后最终的源代码:
- package jdbcDemo;
- /****************************
- * 无异常版连接数据库程序
- **************************/
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- public class JDBCTest {
- public static void main(String[] args) {
- Connection conn = null;
- Statement stat = null;
- ResultSet rs = null;
- try {
- //1.注册数据库驱动
- Class.forName("com.mysql.jdbc.Driver");
- //2.获取数据库的连接
- conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
- //3.创建传输器对象
- stat = conn.createStatement();
- //4.利用传输器对象传输sql语句到数据库中执行操作,将结果用结果集返回
- rs = stat.executeQuery("select * from book");
- //5.遍历结果集,并获取查询结果
- while (rs.next()) {
- String name = rs.getString("name");
- System.out.println(name);
- }
- } catch(Exception e) {
- e.printStackTrace();
- } finally {
- //6.关闭连接(后开先关)
- if (rs != null) {
- try {
- rs.close();
- } catch(SQLException e) {
- e.printStackTrace();
- } finally {
- rs = null;
- }
- }
- if (stat != null) {
- try {
- stat.close();
- } catch(SQLException e) {
- e.printStackTrace();
- } finally {
- stat = null;
- }
- }
- if (conn != null) {
- try {
- conn.close();
- } catch(SQLException e) {
- e.printStackTrace();
- } finally {
- conn = null;
- }
- }
- } //--finally
- } //--main
- } //--class
总结:
这里我只是把所有的异常处理完,但是程序的通用性还不是特别高,因为连接数据库用到的 Driver 类名、URL、user 以及 password 都写在程序中,我们其实可以写在一个文本文件中,通过对文件的读取来获得每种数据库特有的连接参数。
还有就是在实际开发过程中,连接数据库的程序代码一般会写在一个工具类中,我们想要对数据库中的数据进行操作时,只需要调用这个工具类就可以了,不用每次都写那么多代码
接下来我还会更新一篇如何将数据库的连接信息保存在文本文件中,然后读取这个文件来实现连接数据库的操作,同时我也会将这个程序修改为连接数据库的一个工具类
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持 PHPERZ!
来源: http://www.phperz.com/article/17/1221/357959.html