Java之JDBC技术详解
一、简介
1. 什么是JDBC
JDBC (Java Date Base Connectivity),指 Java 数据库连接,是一种标准Java应用编程接口 (Java API),用来连接Java编程语言和广泛的数据库。
JDBC API 库包含下面提高的每个任务,都是与数据库相关的常用用法。
- 制作到数据库的连接
- 创建 SQL 或 MySQL 语句
- 创建 SQL 或 MySQL 查询数据库
- 查看和修改所产生的记录
从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 Java 编写不同类型的可执行文件,例如:
- Java 应用程序
- Java Applets
- Java Servlets
- Java ServerPages (JSPs)
- Enterprise JavaBeans (EJBs)
所有这些不同的可执行文件就可以使用JDBC驱动程序来访问数据库,这样可以方便的访问数据。
JDBC 具有 ODBC 一样的性能,允许 Java 程序包含与数据库无关的代码。
2. 先决条件
为了更好的理解本教程,需要对以下两个主题内容很好的理解:
- 核心 Java 编程
- SQL 或 MySQL 数据库
3. JDBC 架构
JDBC 的 API 支持两层和三层处理模式进行数据库访问,但一般的 JDBC 架构由两层处理模式组成:
- JDBC API:提供了应用程序对 JDBC 管理器的连接
- JDBC DRIVER API:提供了 JDBC 管理器对驱动程序连接
JDBC API 使用驱动程序管理器和数据库特定的驱动程序来提供异构 (heterogeneous) 数据库的透明连接。
JDBC 驱动程序管理器可确保正确的驱动程序来访问每个数据源。该驱动程序管理器能够支持连接到多个异构数据库的多个并发的驱动 程序。
以下是结构图,其中显示了驱动程序管理器相对于在 JDBC 驱动程序和 Java 应用程序所处的位置。
以上引自 JDBC 简介_w3cschool
二、常用接口
在开发 JDBC 程序前,首先了解一下 JDBC 常用的 API。JDBC API主要位于 java.sql 包中,该包定义了一系列访问数据库的接口和类,具体如下:
- Driver 接口
Driver 接口由数据库厂家提供,作为 Java 开发人员,只需要使用 Driver 接口就可以了。在编程中要连接的数据库,必须先装载特定厂商的数据库驱动程序,不同的数据库有不同的装载方法。如:
装载 MySQL 驱动:Class.forName ( "ciom.mysql.jdvc.Driver" );
装载 Oracle 驱动:Class.forName ( "oracle.jdbc.driver.OracleDriver" );
- Connection 接口
Connection 与特定数据库的连接(会话),在连接上下文中执行 sql 语句并返回结果。
DriverManager.getConnection ( url ,user ,password )
方法建立在 JDBC URL 中定义的数据库 Connection 连接上。
连接 MySQL 数据库:
Connection conn = DriverManager.getConnection ( "jdbc:mysql://host:port/database" , "user" , "password");
连接 Oracle 数据库:
Connection conn = DriverManager.getConnection ( "jdbc:oracle:thin:@host:port:database" , "user" , "password");
连接 SqlServer 数据库:
Connection conn = DriverManager.getConnection ( "jdbc:microsoft:sqlsever://host:port;DatabaseName=database" , "user" , "password");
常用方法:
createStatement()
:创建向数据库发送 sql 的 statement 对象。prepareStatement (sql)
:创建向数据库发送预编译 sql 的 PrepareSatement 对象。prepareCall (sql)
:创建执行存储过程的 callableStatement 对象。setAutoCommit (boolean autoCommit)
:设置事物是否自动提交。commit()
:在链接上提交事物。rollback()
:在此链接上回滚事物。
- Statement 接口
用于执行静态 SQL 语句并返回它所生成结果的对象。
三种 Statement 类:
Statement
:由createStatement
创建,用于发送简单的 SQL 语句 (不带参数)。PreparedStatement
:继承自Statement
接口,由preparedStatement
创建,用于发送含有一个或多个参数的 SQL 语句。PreparedStatement
对象比Startement
对象的效率更高,并且可以防止 SQL 注入,所以一般我们都使用PreparedStatement
。CallableStatement
:继承自PreparedStatement
接口,由方法prepareCall
创建,用于调用 存储过程。
常用Statement
方法:
execute (String sql)
:运行语句,返回是否有结果集executeQuery (String sql)
:运行select
语句,返回ResultSet
结果集。executeUpdate (String sql)
:运行insert/update/delete
操作,返回更新的行数。addBatch (String sql)
:把多条 sql 语句放到一个批处理中。executeBatch()
:向数据库发送一批 sql 语句并执行。
- ResultSet 接口
ResulttSet 提供检索不同类型字段的方法,常用的有:
- getString (int index)、getString (String columnName):获得在数据库里是varchar、char等类型的数据对象。
- getFloat (int index)、getFloat (String columnName):获得在数据库里是Float类型的数据对象。
- getDate (int index)、getDate (String columnName):获得在数据库里是Date类型的数据。
- getBoolean (int index)、getBoolean (String columnName):获得在数据库里是Boolean类型的数据。
- getObject(int index)、getObject(String columnName):获取在数据库里任意类型的数据。
ResultSet还提供了对结果集进行滚动的方法:
- next ():移动到下一行
- Previous ():移动到前一行
- absolute (int row):移动到指定行
- beforeFirst ():移动resultSet的最前面。
- afterLast ():移动到resultSet的最后面。
使用后依次关闭对象及连接:ResultSet → Statement →Connection
三、使用JDBC的步骤
加载JDBC驱动程序 → 建立数据库连接Connection → 创建执行SQL的语句Statement → 处理执行结果ResultSet → 释放资源
- 注册驱动 (只做一次)
方式一:Class.forName(“com.MySQL.jdbc.Driver”);
推荐这种方式,不会对具体的驱动类产生依赖。
方式二:DriverManager.registerDriver(com.mysql.jdbc.Driver);
会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
- 建立连接
Connection conn = DriverManager.getConnection(url, user, password);
URL用于标识数据库的位置,通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
其他参数如:useUnicode=true&characterEncoding=utf8
- 创建执行SQL语句的statement
//Statement
String id = "5";
String sql = "delete from table where id=" + id;
Statement st = conn.createStatement();
st.executeQuery(sql);
//存在sql注入的危险
//如果用户传入的id为“5 or 1=1”,那么将删除表中的所有记录
//PreparedStatement 有效的防止sql注入(SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令)
String sql = “insert into user (name,pwd) values(?,?)”;
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, "col_value"); //占位符顺序从1开始
ps.setString(2, "123456"); //也可以使用setObject
ps.executeQuery();
- 处理执行结果(ResultSet)
ResultSet rs = ps.executeQuery();
While(rs.next()){
rs.getString("col_name");
rs.getInt(1);
//…
}
- 释放资源
// 数据库连接(Connection)非常耗资源,尽量晚创建,尽量早的释放 //都要加try catch 以防前面关闭出错,后面的就不执行了
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null) {
st.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上文引自 JDBC详解 - ErBing - 博客园 (cnblogs.com) ,如有侵权请通知。
三、PreparedStatement 接口的解释和用法
PreparedStatement
是 Statement 接口的子接口
优点:
- 使用 PreparedStatement 接口可以防止 SQL 注入
- PreparedStatement 是预编译(Statement 每次执行sql语句,都要执行相关数据库的编译,而 PreparedStatement 的sql是一个模板 (可以类比函数),编译过程与执行是分开的,当为其参数赋予值时,实际上只是将值给传入进去,放进模板中,需要时取出插入数据即可,不需要继续编译。)的,对于批量处理可以大大提高效率。总的来说,区别在于前者编译执行一体化,后者属于先编译后执行。
- 可以重复使用同一SQL模板,给予其不同的参数来重复的使用。
第二点也就是为什么预编译能够防止SQL注入。
创建 PreparedStatement 对象
PreparedStatement ps = null;
try{
……
String sql = "select studentNo from student where studentName = ?";
ps = connection.prepareStatement(sql);
……
} catch (SQLException e) {
……
} finally {
ps.close();
}
在使用 PreparedStatement 对象的同时,所有的参数都被用 ?符号表示,而为其参数赋值则需要用到 setXXX() 方法将值绑定到参数,其中 XXX 表示参数的数据类型。
当你没有给参数赋予值,你会收到一个 SQLException
setXXX (int parementerIndex , XXX类型变量) ,每个参数的起始下标为1。
Statement 和 PreparedStatement 执行SQL语句方法的区别
PreparedStatement对象独有的executeQuery()方法是没有参数的,而Statement的executeQuery()是需要参数(SQL语句)的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了,所以在调用它的executeQuery()和executeUpdate()方法时就不再需要参数了。
总结
- JDBC 由一组使用 Java 语言编写的类和接口组成,可以为多种关系型数据库提供统一的访问方式。
- JDBC API 是一套接口规范,数据库厂商或第三方中间件厂商根据这套接口规范提供针对不同数据库的数据库驱动
- JDBC操作步骤
- 加载JDBC驱动
- 获取数据库连接
- 创建SQL语句集,发送SQL语句,并得到返回结果
- 处理返回结果
- 每个JDBC驱动只对应一种数据库,甚至只对应某个版本的数据库
- 数据库操作结束后,应该关闭数据库连接,释放系统资源。为了确保程序的执行,关闭数据库连接语句要放到 finally 语句块中
- Connection 接口负责连接数据库并担任传达数据库的任务
- Statement 接口负责执行 SQL 语句
- ResultSet 接口负责保存和处理 Statement 接口执行后所产生的查询结果
- SQL 注入是通过提交一段 SQL 代码,执行超出用户权限的数据库操作的攻击行为
- PreparedStatement 接口能够提高代码的可读性、可维护性、SQL语句的执行性能和安全性