看到数据库连接不由得想起了大一末参加团队考核时的悲催经历~~,还记得当初傻傻地按照书本的代码打到 Eclipse 上,然后一运行就各种报错。。。报错后还傻傻地和书本的代码一遍又一遍地进行核对,发现无误后,还特别纠结——代码和书本一样,怎么就报错了呢? 最后通过 Google 才得知要添加驱动包,就这样好多个小时就白白浪费掉了 ~~ 当初连 JDBC 与 JDBC Driver 还没区分好,往事不堪回首。。。
大二末,抱着“自己被抗了,也坑坑师弟,让他们体验下爬坑的经历”的心态,考核师弟时故意没发驱动包给他们,事后听他们说就因为这坑了他们几天的时间。。。
大三末,轮到大二师弟考核大一的师弟,然后大二的师弟和大一的说,“数据库连接时,需要一个驱动包,你们自己去了解、下载,具体的就不说了,要学会解决问题。当年带我的师兄也没直接提供给我,还害我花了几天的时间。所以今年我算好了,还提醒你们要注意。。。”,听到这我背后不由的一凉,这得有多大的怨气。。。(^_^,这不怪我,叫了你们遇到解决不了的问题可以问师兄,你们没问而已,逃~~)
好了,回忆结束~~。为了怀念以前的“懵懂青春”,总结下 Java的数据库连接以及 JDBC、JDBC Driver。
JDBC 与 JDBC Driver
首先要搞清楚的是,什么是 JDBC,什么是 JDBC Driver:
JDBC,JDBC 的全称为 Java Database Connectivity,它定义了一套访问数据库的 API。使用这些 API 你就可以使用 Java 来操控数据库,执行
select
、update
、delete
、insert
等常用的操作。(具体定义请看)JDBC Driver,JDBC Driver 就是 Java 与数据库之间的一层软件组件——驱动。就像我们的鼠标驱动、键盘驱动等驱动,它担任了一个中间人、一名翻译者。因此,要想使用 Java(JDBC API)来访问操控数据库,我们还需要 JDBC Driver 来负责翻译。()
JDBC Driver
JDBC Driver 一般是由相应的数据库提供的,比如 MySQL 提供了 (,Connector/J 属于第 4 种类型的驱动。想了解更详细、更多的驱动类型可以参加)。
JDBC Driver 的安装
JDBC Driver 的安装很简单,只需要去官网下载它提供的驱动,并把相应的 Jar 包(通常叫作 mysql-connector-java-version-bin.jar)放在 Java Classpath 下就 OK,如果你和我一样是搞 J2EE 的,你也可以直接把它放在 WEB-INF/lib 目录下,或者用类似 Maven 之类的工具来添加。详细请看 。
使用
JDBC Driver 的使用在 有很多例子,因此不再累赘了。毕竟它只是一个驱动,我们更多的是使用 JDBC API 调用这个驱动与数据库打交道。更多的使用总结请看下部分。
JDBC API
JDBC 只是 Java 中定义的一些接口,它也属于 JDK 的一部分,就像文件等普通接口一样,我们只需要调用它来完成目的就 OK 。既然是 API 我们就要去看文档熟悉它才能更好地使用它,这些类分别处于 和 。
连接
要想使用 JDBC API 来操控数据库,首先要连上数据库。连接数据库有两种方法:
- 使用 。第一次使用 DriverManager 来建立与数据库的连接时,它会自动在 class path 中寻找并加载 JDBC 4.0 驱动。要注意的是,如果是 4.0 之前的版本,需要手动去加载。
- 使用 。根据官方推荐,我们应该优先使用 DataSource 。相对于比较简单的 DriverManager ,它比较复杂,也比较全面、详细。
使用 DriverManager 连接数据库:
要使用 DriverManager ,我们先要把该类加载进来,使用(在要加载的类里添加以下代码)Class.forName("com.mysql.jdbc.Driver").newInstance();
加载了 DriverManager 后,我们就可以使用它来获取与数据库的连接(假设我们使用本地数据,默认路径为 localhost ;数据库名为 test ;用户名为 root;密码为 123):
// DriverManager、Connection 类在 java.sql 里都有定义String URL = "jdbc:mysql://localhost:3306/test?user=root&password=123";Connection conn = DriverManager.getConnection(URL); //或者String URL = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "123";Connection conn = DriverManager.getConnection(URL, user, password); //或者String URL = "jdbc:mysql://localhost:3306/test";Properties connectionProps = new Properties();connectionProps.put("user", this.userName);connectionProps.put("password", this.password);Connection conn = DriverManager.getConnection(URL, connectionProps);
(个人觉得,第一种看起来简单、方便,但是修改麻烦、可读性不高,不太建议使用。如果你只想简单地传递用户名与密码可以选用第二种。如果你有很多参数要传递,比如字符编码、用户名密码等,优先选择第三种。)
连接数据库,我们只需调用 getConnection() 方法并且返回与数据库的连接(Connection)就 OK ,有了此连接我们就可以操作数据了。
在这要注意的是 getConnection 方法里的字符串参数 URL 。该字符串指定了数据库的路径、数据库名、数据库配置(用户名密码等)。 MySQL 的 URL 语法如下:
jdbc:mysql://[host][,failoverhost...][:port]/[database] [?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
使用 DataSource 连接:
DataSource 连接涉及的东西比较多,找时间另开一篇来总结。 ^_^创建语句
连接上了数据库,我就可以操控数据库了。通常我们是编写 SQL 语句来操控数据库的。因此,在操控数据库之前,我们还要创建 SQL 语句。JDBC 定义了 3 种类型语句接口,用来运行 SQL 语句,并且返回执行结果:
- Statement
- PreparedStatement
- CallableStatement
相应地,创建语句也有三种方法:
Connection.createStatement()
——创建普通的语句,它通常不需要提供参数。Connection.prepareStatement(String stringSQL)
——创建预编译语句,通常要提供一个带有占位符的字符串 SQL 语句。Connection.prepareCall()
——创建存储过程。
这里要注意的是,Statement
与 PreparedStatement
的区别。它们的最主要区别就是:
PreparedStatement
对 SQL 语句进行了预编译,在需要运行多次 SQL 语句是能得到显著的性能提升- 可以有效地防止 SQL 注入攻击( )
- 可以轻松地在 SQL 字符串里使用非标准的 Java 对象,如
Date
、Time
、Timestamp
、BigDecimal
等 - 相对于使用拼接方式的 Statement,它使用占位符(?) 很好地把查询语句以及变量值分开。
- 更多请看
操控数据库
平时我们操控数据库,最常用的、最简单的就是select
、update
、delete
、insert
等常用的操作了。那么我们是怎么通过 JDBC API 来实现这些行为的呢?
通常,我们会使用 Statement.executeQuery(String sql)
来执行 select
查询操作,它会返回一个 的对象,这个对象包含了查询返回的数据。update
、delete
、insert
等更新操作使用 Statement.executeUpdate(String sql)
,它会返回一个整数,代表影响的行数。
ResultSet
ResultSet 是查询数据库时返回的数据集,我们可以把它想象为一张与数据表类似的数据表,就像我们使用命令行执行 select 语句时控制台返回的数据表。不同之处是它拥有一个一开始处于第一行数据的前一行的指针。然后我们就可以通过不停地调用 ResultSet.next()
来移动指针获取每一行的数据,该函数在指针移动到最后一行的下一行时就返回 false
,我们可以利用这个特性来作为终止条件遍历整张表。(第一行的前一行与最后一行的下一行都是不存在的行,是虚拟的行)
此外,ResultSet 有 3 中类型():
- TYPE_FORWARD_ONLY:这个是默认的类型,它只能不同地调用
next()
方法把指针向下一行移动,而不能往回走。 - TYPE_SCROLL_INSENSITIVE:这个类型除了可以调用
next()
方法把指针向下一行移动外,还可以调用previous()
方法把指针指向前一行,使用first
方法把指针移动到第一行等。 - TYPE_SCROLL_SENSITIVE:此方法与第 2 个类型一样,可以任意移动指针。但它是敏感型的。也就是说,当你使用
Statement.executeQuery(String sql)
产生了 ResultSet 后,数据库中响应的数据发生了改变,它会更新 ResultSet 并保持数据与数据库一致。而第 2 个类型是非敏感型的,它不会更新 ResultSet。
要指定 ResultSet 的类型,我们只需在创建 Statement 时指定:
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE);
OK,我已经可以在获取数据表中的任意行了,我们现在来获取一行数据中的特定列的数据。ResultSet 提供了 getter 方法(getBoolean、getLong、getInt等方法)来获取当前行的列。这些方法的参数既可以是列的索引号(从 1 开始的整型)也可以是列的别名或者列名(字符串)。比如 ResultSet.getInt(1) 获取第一列的数据,ResultSet.getFloat("score") 获取列名为 score 的列。