7.JDBC编程
本章目标
- 简介
- 数据库连接常用为和接口
- JDBC访问数据库
本章内容
一、简介
1、概念
JDBC是java DataBase Connectivity的缩写。它是Sun的Javasoft公司制定的Java数据库连接技术,是一套标准接口。
在Java.sql包中提供了JDBC API,开发人员可以通过它连接到各种数据库系统,编写访问数据库的程序。
JDBC API不能直接访问数据库,它依赖于数据库厂商提供的JDBC Driver(JDBC驱动程序)。
使用Java和JDBC开发的程序可以跨数据库平台运行,受数据库限制很少
2、JDBC编程涉及的三个部分:
- 应用程序:开发人员编写的客户端程序。在应用程序中调用JDBC API,将SQL语句发送到数据库并检索结果。
- 驱动程序管理器:JDBC将驱动程序管理器负责使用正确的JDBC驱动程序和连接信息访问数据库,在Java应用程序和数据库系统之间建立连接。
- 驱动程序:驱动程序由数据库厂商提供,实现数据库驱动接口,能够把SQL指令正确的发送的数据库服务器。
3、JDBC至数据库的通信路径

二、Java.SQL包
Java.SQL包中常用的接口和类包括:
- Driver接口和DriverManager类
- Connection
- Statement或者PreparedStatement
- ResultSet
1、Driver接口和DriverManager类
所有的JDBC驱动程序都必须实现Driver接口,JDBC驱动程序由数据库厂商提供,所以必须把JDBC驱动程序加入到项目中。
DriverManager用来建立和数据库的连接以及管理JDBC驱动程序。
DriverManager的常用方法
| 方法 | 描述 |
|---|---|
| registerDriver(Driver driver) | 在DriverManager中注册JDBC驱动程序 |
| getConnection(String url, String user, String password) | 建立到给定数据库 URL 的连接,返回Connection对象 |
| setLoginTimeout(int seconds) | 设定等待数据库连接的最长时间 |
| setLogWriter(PrintWriter out) | 设定输出数据库日志的PrintWriter对象 |
2、Connection
Connection代表java程序和数据库的连接。在连接上下文中执行 SQL 语句并返回结果
Connection的常用方法如下:
| 方法 | 说明 |
|---|---|
| createStatement() | 创建并返回Statement对象 |
| preparedStatement(String sql) | 创建并返回PreparedStatement对象 |
3、Statement
Statement接口定义了一组数据库操作的方法,可以通过这个接口的实现类对象执行指定的SQL命令
Statement 对象的方法:
| 方法 | 说明 | 示例 |
|---|---|---|
| executeUpdate() | 用来创建和更新表 | stmt.executeUpdate(query); |
| executeQuery() | 对于SELECT 语句 | stmt.executeQuery(query); |
| execute() | 返回布尔值,用于执行任何 SQL 语句 | stmt.execute(); |
4、PreparedStatement
PreparedStatement表示预编译的 SQL 语句的对象,是Statement的子接口,扩展了Statement的功能
- PreparedStatement接口使我们可以使用占位符(?)作为参数定义一条SQL语句。
- 占位符是在SQL语句中出现的标记符,在SQL语句执行之前会被替换成实际的值。
- 通过调用connection.preparedStatement()方法来生成PreparedStatement对象
设置查询参数:
| setAsciiStream() | setBigDecimal() | setBinaryStream() | setBoolean() |
|---|---|---|---|
| setByte() | setBytes() | setDate() | setDouble() |
| setFloat() | setInt() | setLong() | setNull() |
| setObject() | setShort | setString() | setTime() |
| setTimestamp() | setUnicodeStream() |
格 式:setXXXX(位置参数,值参数)
位置参数:用于指定所指的是哪一个占位符;
值参数: 指定给该占位符的值。
占位符号从左向右,从1开始。
5、ResultSet
ResultSet表示select语句查询得到的结果集。
- ResultSet中记录的行号从1开始,一个Statement对象在同一时刻只能打开一个ResultSet对象。
- 调用ResultSet的next()方法,可以使游标定位到下一条记录。
- 调用ResultSet的getXXX()方法,可以取得某个字段的值。
ResultSet的常用方法:
| 目录 | 描述 |
|---|---|
| getString(int index) | 返回指定字段的String类型的值,参数index代表字段的序号。 |
| getString(String indexName) | 返回指定字段的String类型的值,参数indexName代表字段的名字。 |
| getInt(int index) | 返回指定字段的int类型的值,参数index代表字段的序号。 |
| getInt(String indexName) | 返回指定字段的int类型的值,参数indexName代表字段的名字。 |
| getFloat(int index) | 返回指定字段的float类型的值,参数index代表字段的序号。 |
| getFloat(String indexName) | 返回指定字段的float类型的值,参数indexName代表字段的名字。 |
6、SQL到Java的数据类型
从一个JDBC数据源检索数据的时候,ResultSet实现了把SQL数据类型映射到Java数据类型上
| SQL数据类型 | Java数据类型 |
|---|---|
| CHAR | String |
| VARCHAR | String |
| LONGVARCHAR | String |
| NUMERIC | java.math.BigDecimal |
| DECIMAL | java.math.BigDecimal |
| BIT | boolean |
| TINYINT | byte |
| SMALLINT | short |
| INTEGER | int |
| BIGINT | long |
| REAL | float |
| FLOAT | double |
| DOUBLE | double |
| BINARY | byte[] |
| VARBINARY | byte[] |
| LONGVARBINARY | byte[] |
| DATE | java.sql.Date |
| TIME | java.sql.Time |
| TIMESTAMP | java.sql.Timestamp |
三、JDBC访问数据库
1、步骤一
pom.xml文件
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
装载并注册数据库的JDBC驱动程序:
| 数据库 | 驱动程序 |
|---|---|
| MySQL Driver | Class.forName(“com.mysql.jdbc.Driver”); |
| Oracle Driver | Class.forName(“oracle.jdbc.driver.OracleDriver”); |
| SQL Server Driver | Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”) |
注:Class.forName()这步操作可以省略
Applications no longer need to explicitly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
2、步骤二
-
建立与数据库的连接:
Connection conn = DriverManager.getConnection(url,user,pwd);
其中url表示连接数据库的JDBC URL,user和pwd表示连接数据库的用户名和口令。
-
JDBC的连接由数据库 URL标识 :
jdbc:
:
Subprotocol是有效JDBC驱动程序名称,subname通常是指映射到物理数据库的逻辑名或别名。
-
MySQL的url
jdbc:mysql://localhost:3306/mydb
3、JDBC URL格式
| 数据库名 | 驱动程序 | URL |
|---|---|---|
| MySQL5.7 | com.mysql.jdbc.Driver | jdbc:mysql:// |
| MySQL8 | com.mysql.cj.jdbc.Driver | jdbc:mysql:// |
| MS SQL Server2005 | com.microsoft.sqlserver.jdbc.SQLServerDriver | jdbc:sqlserver://[ip]:[port];DatabaseName=[Database];user=[user];password=[pw] |
| Oracle thin Driver | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@[ip]:[port]:[sid] |
注意:由于数据库厂商提供的数据库驱动不同,因此url也不同,使用时请查阅相关资料
mysql的 url参数详解
| 参数名 | 含义 | 通常取值 |
|---|---|---|
user |
数据库用户名(用于连接数据库) | —– |
passWord |
用户密码(用于连接数据库) | —– |
useSSL |
SSL(Secure Sockets Layer),安全套接字协议。 MySQL的版本为5.7以上时,必须加上useSSL=false,直接通过用户账号和密码进行连接;MySQL的版本是5.7以下不进行要求,默认使用useSSL=false useSSL=false:使用用户账号密码进行连接。 useSSL=true:y一般通过证书或者令牌进行安全验证。 | false |
useUnicode |
是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true | true |
characterEncoding |
当useUnicode设置为true时,指定字符编码。比如可设置为gb2312或gbk | utf8 |
serverTimezone |
用于设置时区时间 | Asia/Shanghai |
| autoReconnect | 当数据库连接异常中断时,是否自动重新连接? | —– |
| autoReconnectForPools | 是否使用针对数据库连接池的重连策略 | —– |
| maxReconnects | autoReconnect设置为true时,重试连接的次数 | —– |
| failOverReadOnly | 自动重连成功后,连接是否设置为只读? | —– |
| zeroDateTimeBehavior | exception:默认值,即抛出SQL state [S1009]. Cannot convert value…的异常 convertToNull:将日期转换成NULL值;round:替换成最近的日期即0001-01-01 |
convertToNull |
格式一:
jdbc:mysql://localhost:3306/hrms?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
格式二:
jdbc:mysql://localhost:3306/hrms?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
二选一:不要混,否则会出现Public Key Retrieval is not all
4、步骤三
创建Statement对象,准备调用sql语句:
Statement stm = conn.createStatement();
或创建PreparedStatement对象
PreparedStatement pstm = conn.preparedStatement(sql);
5、步骤四
执行SQL语句,获取结果集(select操作):Statement对象:
ResultSet rs = stm.executeQuery(sql);
PreparedStatement对象:
ResultSet rs = pstm.executeQuery();
6、步骤五
访问ResultSet中的记录集
While(rs.next()){
String col1 = rs.getString(1);
String col2 = rs.getString(2);
int col3 = rs.getInt(3);
…
}
7、步骤六
依次关闭ResultSet、Statement/PrearedStatement和Connection对象:
finally {
try{
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
}catch(SQLException e){
System.out.println(e.toString());
}
}
8、完整示例
/*存放数据的List*/
List depList = new ArrayList();
Connection conn = null;
try{
//加载驱动程序
Class.forName("com.mysql.cj.jdbc.Driver");
//指定连接数据库的URL
String strUrl = "jdbc:mysql://localhost:3306/hrms?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
//进行数据库连接
conn=DriverManager.getConnection(strUrl,"root","root");
//创建一个statement对象
Statement stm = conn.createStatement();
//定义sql语句
String strSql = "select * from Dept";
//定义一个结果集
ResultSet rs = stm.executeQuery(strSql);
while(rs.next) {
//创建部门对象
Dep clsDep=new Dep();
//将从结果集中取出的数据存放到部门对象指定的属性中
clsDep.setDepId(rs.getString(1));
clsDep.setDepName(rs.getString(2));
clsDep.setDepDesc(rs.getString(3));
//将部门对象放入List中
depList.add(clsDep);
}
}
finally{
conn.close();
}
扩展JDBC中Statement 和 PrepareStatement 的区别
作用:数据库连接的时候创建一个对象,然后通过对象去调用executeQuery方法来执行sql语句
创建的时候:
Statement statement = conn.createStatement();
PreparedStatement preStatement = conn.prepareStatement(sql);
执行的时候:
ResultSet rSet = statement.executeQuery(sql);
ResultSet pSet = preStatement.executeQuery();
PrepareStatement继承自Statement:
效率:
Statement 执行每一条SQL语句时,都是编译+执行,相当于静态SQL;
PrepareStatement执行的SQL语句,会进行预编译,SQL中可以包含动态参数”?“,在执行时可以为”?“动态设置参数值,当下次执行相同类型的SQL语句时,可以解析并直接执行编译好的SQL语句,从而减少编译次数提高数据库的性能,相当于动态SQL;
安全性:
Sql注入的问题
Statement:SQL语句每次都是重新编译执行的,这就导致你传进去的参数和SQL语句是有联系,可以改变原先SQL的功能结构
select * from user where username= '"+name+"' and userpwd='"+passwd+"'
如果传进去的passwd参数值是 ’ or ‘1’ = ’1 那SQL就变成了永真式:
select * from user where username= '"+name+"' and userpwd=' or 1 = 1'
权限就这样被轻易获取了;
PrepareStatement:SQL的参数会被强制类型转换成表中的列属性值,由于SQL语句已经实现被编译过,参数和原来SQL语句不会有交集,也就避免了这种情况的发送;
思维导图

本文来自博客园,作者:icui4cu,转载请注明原文链接:https://www.cnblogs.com/icui4cu/p/18818219

浙公网安备 33010602011771号