1.首先说明什么是JDBC
在第一眼看到这个名词之前,我觉得有必要知道它的英文全称是什么,Java Database Connectivity,从英文字面上理解就直译为
可连通的Java数据库,说白了也就是想提供一套中间环节,去连接Java代码与数据库,使之可以直接通过操作Java代码就可以控制数据库。
2.JDBC的实质
它是Java访问数据库的解决方案,希望能过用同样的方式访问不同的数据库,以达到实现与具体数据库无关的Java操作界面。
JDBC实质上就是就是一套标准化的接口,不同的数据库厂商根据自己的数据库特点去实现这套接口,实现的具体方法无需我们去关心。
JDBC中数据库厂商实现的主要接口如下:
DriverManager :驱动管理
Connection、
DatabaseMetaData :连接接口
Statement、
PreparedStatement
CallableStatement: 语句对象接口
ResultSet、
ResultSetMetaData: 结果集接口
3.JDBC的工作原理
程序员调用的是底层数据库厂商实现的部分,
即:1)通过Connection 接口实现第一步的连接
2)通过Statement结果传送sql语句
3)数据库返回结果保存到ResultSet结果集合接口中
主要流程可归纳为:
1)加载驱动,创建连接
2)创建语句对象
3)执行SQL语句
4)发回结果集
5)关闭连接
下面我以我学的oracle数据库配合eclips为例逐步阐述一下如何实现JDBC
1)加载驱动
使用的方法为:Class.forName(“驱动”);
对于如何获得到这个驱动,我所知道的方法是:展开JDBC的jar包,如我使用的是ojdbc6.jar,在里面找到oracle.jdbc.driver,在里面再找到OracleDriver然后鼠标右键点qualitycopy,粘贴到引号之中即可,如:Class.forName("oracle.jdbc.driver.OracleDriver");
2)创建连接
使用的方法为: conn=DriverManager.getConnection(“jdbc:oracle:thin:@IP地址:1521:orcl","数据库账号","数据库密码”);
如:conn=DriverManager.getConnection("jdbc:oracle:thin:@172.16.3.8:1521:orcl","jsd1601","jsd1601");
3)创建语句对象
使用的方法为:Statement stmt=conn.createStatement();
需要注意的是,使用的是第二步上面创建出来的连接去调用方法
调用executeUpdate方法将sql语句传入其中即可执行所写的sql语句,这里需要注意的是,executeUpdate方法能执行的sql种类为insert,update,delete
如: Statement stmt=conn.createStatement();
String sql="insert into emp_jiawenzhe(empno,ename,sal,deptno) values(1000,'贾文哲',1500,10)";
int i=stmt.executeUpdate(sql);
这里面的返回值i就是受影响的行数,我们可以根据这个受影响的行数来判断是否操作成功
4)而对于返回的结果集主要是指进行select操作(这里暂不提)
5)最后关闭连接
如:conn.close();
列举一整体代码,包括注释:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package jdbc_day01;
import java.sql.*;
/**
* 演示JDBC的操作步骤
* 1、加载驱动程序
* 2、创建连接
* 3、创建语句对象
* 4、发送SQL语句
* 5、如果发送的是select语句,处理结果集
* 6、关闭连接
* @author jiawenzhe
*
*/
public class JDBCDome01 {
public static void main(String[] args) throws SQLException {
//需求:创建一个员工,员工号,员工名,工资,部门号
//1、
Connection conn= null ;
try {
Class.forName( "oracle.jdbc.driver.OracleDriver" );
System.out.println( "驱动加载成功" );
//2、
conn=
DriverManager.getConnection( "jdbc:oracle:thin:@172.16.3.8:1521:orcl" , "jsd1601" , "jsd1601" );
System.out.println(conn.getClass().getName());
//3、
//Statment 语句对象。发送并执行SQL语句
/*
* int excuteUpdate(String sql);
* 发送insert,update,delete语句
* 返回值int表示影响数据库表的行数
*/
Statement stmt=conn.createStatement();
String sql= "insert into emp_jiawenzhe(empno,ename,sal,deptno) "
+ "values(1000,'王小二',1500,10)" ;
int i=stmt.executeUpdate(sql);
if (i> 0 ){
System.out.println( "保存成功!" );
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
//1、记录日志
//2、通知调用者
throw new RuntimeException( "加载驱动错误" ,e);
} finally {
//关闭连接
if (conn!= null ){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
|
注:oracle数据库可以使用的jar包:ojdbc14.jar/ojdbc6.jar(oracle12c用这个)
mysql数据库可以使用的jar包:mysql-connector-java-5.0.4-bin.jar
加载驱动类:
1
|
Class.forName( "com.mysql.jdbc.Driver" );
|
1.封装方法的引出
学了一段时间的Java给我感触最深的就是,当前写某一系列的代码的时候,如果出现了代码的复用,肯定会选择一种方法对代码进行一定程度的封装,从封装一个方法到封装一个类,之前有提到的使用JDBC进行数据库的操作(增,删,改,因为查询涉及到对结果集的操作,将单独声明)分为四个过程:
1)加载驱动
2)创建连接
3)创建语句对象,发送SQL
4)关闭连接
也就是说我们在进行任何对数据库操作的时候,都要进行上述步骤,这便出现了代码的冗余,于是便提出了封装这些共性的步骤到一个类中,使其能成为一种工具类,为我所用
2.三个版本的封装
1.版本1
我在学习的时候是逐步对这些类进行一个渐进性的封装,逐步完善的,因为如果直接提出终极版的封装,对于初学者很难接受,下面我将阐述第一种也就是最简单的封装方法:
你在前面会发现,无论你想如何操作数据库,加载驱动都是必不可少的,而加载驱动里面主要就是声明,驱动的名字,IP地址,端口号,数据库账户名,密码等等,而这些的实质就是字符串所以我将这些字符串单独定义出来,如下面所示:
1
2
3
4
|
private static String driverclass= "oracle.jdbc.driver.OracleDriver" ;
private static String url= "jdbc:oracle:thin:losthost:1521:orcl" ;
private static String user= "system" ;
private static String password= "123" ;
|
这样在创建连接的时候我可以直接拿到变量的名字去代替很长的字符串,而加载驱动时地方法Class.forName,我们将它声明在静态块中,因为加载数据的同时,加载了驱动
如下面所示:
1
2
3
4
5
6
7
8
|
static {
try {
Class.forName(driverclass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException( "加载驱动错误" ,e);
}
}
|
对于创建连接,就是调用DriverManager的getConnection方法,并将对应的用户名,密码放入其中,我们将这个方法直接放到我自己定义的方法中,然后直接调用我的方法便可以创建连接,需要注意的是,方法的返回值是Connection这个对象,很好理解,因为就是要拿到这个连接类型的对象,如下面所示:
1
2
3
4
5
|
public static Connection getConnection() throws SQLException{
Connection conn=
DriverManager.getConnection(url,user,password);
return conn;
}
|
然后是创建语句对象,发送SQL,当然SQL是这里面唯一特殊的地方,因为SQL要做的事千差万别,所以这个步骤就不用封装了。
最后是关闭连接,就是调用了close()这个方法,如下面所示
1
2
3
4
5
6
7
8
9
10
|
public static void close(Connection conn){
if (conn!= null ){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException( "关闭连接错误" ,e);
}
}
}
|
整体的第一版本的封装如下面所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package jbbc_day01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 用来管理连接
* @author jiawenzhe
*
*/
public class DBUtil {
private static String driverclass= "oracle.jdbc.driver.OracleDriver" ;
private static String url= "jdbc:oracle:thin:losthost:1521:orcl" ;
private static String user= "system" ;
private static String password= "123" ;
//1、加载驱动
static {
try {
Class.forName(driverclass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException( "加载驱动错误" ,e);
}
}
//2、创建连接
/*
* 如何定义一个能够创建连接的方法
* 返回值类型:是否有运算结果,如果有,结果的类型即为返回值类型
* 参数列表:
* 方法功能中是否有不确定的数据参与运算,如果有,即为参数
*/
public static Connection getConnection() throws SQLException{
Connection conn=
DriverManager.getConnection(url,user,password);
return conn;
}
//3、关闭连接
public static void close(Connection conn){
if (conn!= null ){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException( "关闭连接错误" ,e);
}
}
}
}
|
这样一个封装就好了,然后在进行SQL操作的时候直接调用这个封装类就可以了,而你只需要写的就是创建你的语句对象,发送你的SQL语句即可
2.版本2
其实版本2与版本一很类似,就是为了去弥补版本1的一个不足之处,就是,当你更换数据库的时候,不同数据库的账号密码是不一样的,这就要对账号密码和IP地址进行修改,我之前将这些以字符串的形式封装在了工具类之中,那就意味着我们每次更换数据库必须对工具类进行修改,这样是很不妥当的,于是提出了一种改进办法就是将这些连接数据放到一个配置文件之中,工具类去读取这个配置文件,我们在修改的时候直接去修改这个配置文件就可以了
在介绍这个版本之前,我前引出一个新类就是Properties,他就是一个能读取文件,并以流的形式去读取配置文件内容然后返回给工具类的
首先我先把配置文件示例出来,其实不用解释,一目了然,如下所示:
1
2
3
4
|
jdbc.driverclass=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:localhost:orcl
jdbc.user=system
jdbc.password= 123
|
前面是键,后面是值,前面的键值是我们自己定义的,就像定义变量名字一样,后面的值就是我们数据库的实际情况,这里我们需要特别注意的是,这个配置文件的后缀名一定要以.properties结尾,因为这样Properties这个类才能读取的到。
这部分的示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
static {
try {
//加载属性文件数据
Properties pop= new Properties();
pop.load(DBUtil2. class .getClassLoader().getResourceAsStream( "db.properties" ));
url=pop.getProperty( "jdbc.url" );
driverclass=pop.getProperty( "jdbc.driverclass" );
user=pop.getProperty( "jdbc.user" );
password=pop.getProperty( "jdbc.password" );
Class.forName(driverclass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException( "加载驱动错误" ,e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
|
load()这个方法就是去读取也可以认为是加载配置文件的,这个整整一句话记住就行,不用去深究其意义,而getProperty()就是通过键获得到了对应的值,很像键值对集合获取值得形式
整体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
package jbbc_day01;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* 用来管理连接
* 数据库连接信息,保存在属性文件中
* @author jiawenzhe
*
*/
public class DBUtil2 {
private static String driverclass;
private static String url;
private static String user;
private static String password;
//1、加载驱动
static {
try {
//加载属性文件数据
Properties pop= new Properties();
pop.load(DBUtil2. class .getClassLoader().getResourceAsStream( "db.properties" ));
url=pop.getProperty( "jdbc.url" );
driverclass=pop.getProperty( "jdbc.driverclass" );
user=pop.getProperty( "jdbc.user" );
password=pop.getProperty( "jdbc.password" );
Class.forName(driverclass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException( "加载驱动错误" ,e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//2、创建连接
/*
* 如何定义一个能够创建连接的方法
* 返回值类型:是否有运算结果,如果有,结果的类型即为返回值类型
* 参数列表:
* 方法功能中是否有不确定的数据参与运算,如果有,即为参数
*/
public static Connection getConnection() throws SQLException{
Connection conn=
DriverManager.getConnection(url,user,password);
return conn;
}
//3、关闭连接
public static void close(Connection conn){
if (conn!= null ){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException( "关闭连接错误" ,e);
}
}
}
}
|