JDBC知识点总结
一:JDBC 概述
一、简介
1. JDBC(Java DataBase Connection,Java 数据库连接)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
2. JDBC 是一个标准 SQL(Structured Query Language,结构化查询语言)数据库访问接口,可以为多种关系数据库提供统一访问。也提供一种基准,据此可以构建更高级的工具和接口。
3. JDK(Java Development Kit,Java 开发工具包)软件捆绑包括 JDBC 和 JDBC-ODBC(Open DataBase Connection,开放式数据库连接)桥。
二、API
二:JDBC 开发步骤
一、配置依赖 jar 包
1. 下载
1. MySQL
2. Oracle
2. 配置
1. 导入 jar 包
2. Maven 配置
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency> <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc10 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc10</artifactId>
<version>19.3.0.0</version>
</dependency>
二、注册驱动
public class DriverTest {
/**
* 通过反射机制,加载数据库驱动,类初始化的时候执行静态代码块
* 优点1:此方式由于参数为字符串,因此很容易修改,移植性强。
* 优点2:不依赖特定的Driver库,很容易改造成从配置文件读取JDBC配置,从而可以在运行时动态更换数据库连接驱动。
*/
static {
try {
/**
* MySQL:8.0版本,5.0版本为:com.mysql.jdbc.Driver
*/
Class.forName("com.mysql.cj.jdbc.Driver"); /**
* Oracle
*/
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 8版本
}
}
三、获取连接
public class ConnectionTest {
/**
* MySQL
*/
public Connection getMysqlConnection() {
// 本地连接URL:jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
// 远程连接URL:jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
final String url = "jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC";
// 连接用户名
final String user = "root";
// 连接密码
final String password = "000000";
Connection conn = null;
if (conn == null) {
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.err.println("Oracle数据库连接出错");
e.printStackTrace();
}
}
return conn;
} /**
* Oracle
*/
public Connection getOracleConnection() {
/**
* 1. 使用thin连接:jdbc:oracle:thin:@<host>:<port>:<database>
* 优点:thin完全由Java代码编写,与平台无关,不需要Oracle客户端。
* 缺点:thin性能一般,达不到如OCI方式的企业级的要求,一般适合一台主机连接。
*
* 2. 使用oci连接:jdbc:oracle:oci:@<host>:<port>:<database>
* 优点:用OCI连接数据库是企业级的做法,适应于单个数据库和集群数据库,性能优越,尤其是连接池功能大大提高了应用程序的性能和并发量。
* 缺点:若想使用OCI必须要安装Oracle客户端。
*/
final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
// 连接用户名
final String user = "scott";
// 连接密码
final String password = "tiger";
// 连接对象
Connection conn = null;
if (conn == null) {
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.err.println("Oracle数据库连接出错");
e.printStackTrace();
}
}
return conn;
}
}
四、创建Statement、PreparedStatement、CallableStatement接口,执行SQL语句
package pers.mj.test; import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types; public class MysqJDBClTest {
/**
* Statement 的作用:用于执行静态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。
* Statement 的优点:语法简单,对于只执行一次的 SQL 语句,使用 Statement 比 PreparedStatement 对象的开销更小。
* Statement 的缺点:每次执行时相似SQL都会进行编译 ,采用硬编码效率低,安全性较差,字符串拼接方式的 SQL 语句是非常繁琐的,中间有很多的单引号和双引号的混用,极易出错。
* Statement 的适用场景:普通的不带参的查询SQL
*/
public void testStatement() {
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 创建 Statement 对象
Statement st = conn.createStatement();
// 定义SQL语句
String sql = "insert into student(stu_id, stu_name) values(20200626, " + " '张三')"; // 字符串拼接麻烦
/**
* 演示SQL注入问题:如果此时传递给字段的值为:or 1 = 1,那么不论如何条件都成立,导致结果都成功,这就是SQL注入
*/
String SQL = "select * from student where stu_name="+"'张三' and stu_id= "+"'or 1 = 1' ";
// 执行SQL语句
if (st.execute(sql)) {
System.out.println("信息插入成功");
}
} catch (SQLException e) {
System.err.println("插入语句执行失败");
e.printStackTrace();
}
} /**
* PreparedStatement 的作用:用于执行动态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。继承Statement
* PreparedStatement 的优点:相似SQL只编译一次,减少编译次数,代码的可读性和可维护性更高,提高了安全性(阻止了SQL注入)。
* PreparedStatement 的缺点:执行非相似SQL语句时,速度较慢。
* PreparedStatement 的适用场景:支持可变参数的SQL
*/
public void testPreparedStatement() {
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "insert into student(stu_id, stu_name) values(?, ?)";
/**
* 解决SQL注入问题:PreparedStatement不是将参数简单拼凑成sql,而是做了一些预处理,将参数转换为string,两端加单引号,将参数内的一些特殊字符(换行,单双引号,斜杠等)做转义处理,这样就很大限度的避免了sql注入。
*/
String SQL = "select * from student where stu_name=? and stu_id= ? ";
// 预编译SQL语句,防止SQL注入
PreparedStatement ps = conn.prepareStatement(sql);
// 给占位符(?)赋值:索引从1开始,数据类型需要相对应
ps.setInt(1, 20180627);
ps.setString(2, "李四");
// 执行SQL语句
if (ps.execute()) {
System.out.println("信息插入成功");
}
} catch (SQLException e) {
System.err.println("插入语句执行失败");
e.printStackTrace();
}
} /**
* CallableStatement 的作用:实现了存储过程函数调用的方法以及对于输出的处理。继承PreparedStatement
* CallableStatement 的使用场景:支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持
*/
public void testCallableStatement(){
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "call p3(?,?)";
// 预编译SQL
CallableStatement cs = conn.prepareCall(sql);
// 给站位符赋值
cs.setString(1, "王五");
cs.registerOutParameter(2, Types.INTEGER); // 注册一个输入参数
// 执行SQL
cs.execute();
// 获取结果集对象
ResultSet resultSet = cs.getResultSet();
while (resultSet.next()) {
System.out.println(resultSet.getString("name")+" ");
}
// 获取输出参数
System.out.println(cs.getInt(2));
} catch (Exception e) {
// TODO: handle exception
}
}
}
五、execute、executeQuery和executeUpdate详解
public class ExecuteTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* executeQuery()
* 作用:只能执行DQL(SELECT语句),是使用最多的查询语句。
* 返回值:单个结果及对象(ResultSet)
*/
public void testExecuteQuery() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student WHERE stu_id=? ";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 给占位符赋值
ps.setInt(1, 20200626);
// 执行SQL语句
rs = ps.executeQuery();
while (rs.next()) {
System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* executeUpdate()
* 作用:执行DML(除去SELECT语句)和DDL,修改表中零行或多行中的一列或多列。
* 返回值:受影响的行数(整数)
*/
@Test
public void testExecuteUpdate() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "UPDATE student SET stu_name=? WHERE stu_id=?";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 给占位符赋值
ps.setString(1, "王五");
ps.setInt(2, 20200626);
// 执行SQL语句
if (ps.executeUpdate() != 0) {
System.out.println("信息修改成功");
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* execute()
* 作用:用于执行返回多个结果集、多个更新计数或二者组合的语句。例如:执行某个已存储过程或动态执行未知 SQL 字符串。
* 返回值:多个ResultSet对象、多个更新计数或ResultSet对象与更新计数。
* 使用
* 多个结果集
* 1. 执行完execute()方法后,使用CallableStatement对象调用getResultSet()方法获取第一个结果集,调用适当的getXXX方法获取值
* 2. 如果存在第二个结果集,则必须调用getMoreResults()方法,然后再调用getResultSet()方法来获取结果集,依次类推。
* 多个更新计数
* 1. 执行完execute()方法后,则首先调用方法 getUpdateCount,然后调用 getMoreResults,并再次调用 getUpdateCount,依次类推。
*
*/
public void testExecute() {
List<List<Map<String, Object>>> resultList = new ArrayList<>();
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "sp_help 'test.student'";
// 预编译SQL
CallableStatement cs = conn.prepareCall(sql);
// 外循环获取结果集的个数
boolean oprFlg = cs.execute(sql);
while (oprFlg) {
List<Map<String, Object>> result = new ArrayList<>();
// 获取第一个结果集
rs = cs.getResultSet();
// 内循环获取每个结果集的记录
while (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Map<String, Object> map = new HashMap<String, Object>();
for (int i = 0; i < columnCount; i++) {
map.put(rsmd.getColumnName(i + 1).toLowerCase(), rs.getObject(i + 1));
}
result.add(map);
}
resultList.add(result);
// 获取更多的结果集
oprFlg = cs.getMoreResults();
}
} catch (Exception e) {
// TODO: handle exception
}
}
六、处理结果集
1. ResultSet:在线
public class ResultSetTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* 可滚动,可更新
* ResultSet.TYPE_FORWARD_ONLY:该常量控制ResultSet记录指针只能向前移动(默认)。
* ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),但底层数据的改变不会受ResultSet的内容。
* ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),并且底层数据的改变会影响ResultSet的内容。
* ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)。
* ResultSet.CONCUR_UPDATABLE: 该常量指示ResultSet是可更新的并发默认。
*
*/
public void testScrollAndUpdate() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// 执行SQL语句
rs = ps.executeQuery();
// 处理结果集
while (rs.next()) {
System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* ResultSetMetaData:分析结果集,当不清楚该ResultSet里包含哪些数据列,以及每个数据列的数据类型,那么可以通过ResultSetMetaData来获取关于ResultSet的描述信息。
* getMetaData():获取ResultSetMetaData对象。
* int getColumnCount():返回该ResultSet的列数量。
* String getColumnName(int columnIndex):返回对应列的名称。
* int getColumnType(int columnIdex):返回对应列的数据类型。
*/
public void testResultSetMetaData() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 执行SQL语句
rs = ps.executeQuery();
// 处理结果集
while (rs.next()) {
// 获取结果集元数据对象
ResultSetMetaData rsmd = rs.getMetaData();
// 获取结果集列数
int columnCount = rsmd.getColumnCount();
for (int i = 0; i < columnCount; i++) {
// 获取结果集对应列名称
System.out.println(rsmd.getColumnName(i + 1));
// 获取结果集对应数据类型
System.out.println(rsmd.getColumnType(i + 1));
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
2. RowSet:离线
public class RowSetTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* RowSet:实现了ResultSet接口,并且有子接口CachedRowSet(离线查询)
* 概念:离线查询:在本地搞一个结果集的副本,关闭结果集、数据库连接,使用本地的这个副本。
* 作用:RowSet默认是可滚动,可更新,可序列化的结果集,并且作为对JavaBean使用,因此能方便地在网络上传输,用于同步两端的数据。
* 优点:程序在创建RowSet时已把底层数据读取到了内存中,因此可以充分利用计算机的内存,从而减低数据库的负载,提高程序的性能。
*/
@Test
public void testRowSetOffline() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 执行SQL语句
rs = ps.executeQuery();
/**
* 离线查询
*/
// 通过RowSetProvider的静态方法创建RowSetFactory对象
RowSetFactory rsf = RowSetProvider.newFactory();
// 创建CachedRowSet对象
CachedRowSet crs = rsf.createCachedRowSet();
// 使用结果集填充CachedRowSet
crs.populate(rs); // 使用给定的ResultSet装填RowSet,从ResultSet的第startRow条记录开始装填。
/**
* 关闭数据库资源
*/
rs.close();
ps.close();
conn.close();
// 离线处理结果集:CachedRowSet是ResultSet的孙接口,使用的方法都相同。
while (crs.next()) {
System.out.println("学号:" + crs.getInt("stu_id") + " 姓名:" + crs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* 分页:不推荐使用每个数据库特有的分页,追求跨数据库,代码可用性更高
* 1. 使用游标实现
* 2. 使用离线查询实现
*/
public void pagination() {
try {
/**
* 使用游标实现
*/
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// 执行SQL语句
rs = ps.executeQuery();
// 定义分页
int start = 0; // 起始页
int pageSize = 10; // 分页大小
// 定义游标
rs.absolute(start); // 游标指向起始位
while (rs.next()) {
// ......
if (rs.getRow() == pageSize) { // getRow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
break;
}
} /**
* 使用离线查询实现
*/
// 创建RowSetFactory对象
RowSetFactory rsf = RowSetProvider.newFactory();
// 创建CachedRowSet对象
CachedRowSet crs = rsf.createCachedRowSet();
// 设置分页大小
crs.setPageSize(10);
// 使用结果集填充CachedRowSet
crs.populate(rs);
// 释放资源
rs.close();
ps.close();
conn.close();
while (crs.next()) {
// ......
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
JDBC知识点总结的更多相关文章
- jdbc知识点(连接mysql)
jdbc连接mysql 1.JDBC简介 JDBC: 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库.从根本上来说,JDBC ...
- JavaSE_XMind总结
1 JDBC知识点总结
- java用JDBC连接MySQL数据库的详细知识点
想实现java用JDBC连接MySQL数据库.需要有几个准备工作: 1.下载Connector/J的库文件,下载Connector/J的官网地址:http://www.mysql.com/downlo ...
- Spring知识点总结(五)Spring整合JDBC
1. 回顾JDBC a. java操作关系型数据的API.导入相关数据库的驱动包后可以通过JDBC提供的接口来操作数据库. b. 实现JDBC的六个步骤 ...
- 一个基础又很重要的知识点:JDBC原理(基本案例和面试知识点)
JDBC全称又叫做Java DataBase Connectivity,就是Java数据库连接,说白了就是用Java语言来操作数据库.这篇文章主要是对JDBC的原理进行讲解.不会专注于其使用.主要是理 ...
- JDBC面试知识点整理(温习用)
要面试,所以把之前的笔记整理一遍,嘻嘻,加油 JDBC编程 使用JDBC,java程序可以轻松地操作各种主流数据库,Oracle,MySQL,等,使用JDBC编写的程序不仅可以实现跨数据库,还具有跨平 ...
- JDBC 详解(转载)
原文链接:http://blog.csdn.net/cai_xingyun/article/details/41482835 什么是JDBC? Java语言访问数据库的一种规范,是一套API JDBC ...
- JDBC详解(转)
原文链接:http://blog.csdn.net/cai_xingyun/article/details/41482835 什么是JDBC? Java语言访问数据库的一种规范,是一套API JDBC ...
- JDBC代码示例
package test; import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;imp ...
随机推荐
- 题解 P4071 【[SDOI2016]排列计数】 (费马小定理求组合数 + 错排问题)
luogu题目传送门! luogu博客通道! 这题要用到错排,先理解一下什么是错排: 问题:有一个数集A,里面有n个元素 a[i].求,如果将其打乱,有多少种方法使得所有第原来的i个数a[i]不在原来 ...
- [注]一条牛B的游戏推送要具备哪些条件?
旁白:推送内容写的好,可以给游戏带来很大的收益,但如果写的很糟糕,就可能是在提醒用户还有一个该卸载的软件没卸载.那么如何写出一个优秀的推送内容呢? 总结:推送文字八字原则 从运营的角度来讲,我们需要找 ...
- Java中的集合(五)继承Collection的List接口
Java中的集合(五)继承Collection的List接口 一.List接口简介 List是有序的Collection的,此接口能够精确的控制每个元素插入的位置.用户能够根据索引(元素在List接口 ...
- 使用python的socket模块进行网络编程
使用socket编程可以分成基于tcp和基于udp,tcp和udp两者最主要的区别是有无面向连接. 基于tcp的socket流程:
- Asp.Net Mvc基于Fleck开发的多人网页版即时聊天室
一.项目的核心说明 1.Fleck这个是实现websocket一个比较简单第三方组件,它不需要安装额外的容器.本身也就几个接口可供调用. 2.项目是基于.net framework 4.7.2 ,在v ...
- Java实现 蓝桥杯 算法训练 出现次数最多的整数
算法训练 出现次数最多的整数 时间限制:1.0s 内存限制:512.0MB 提交此题 问题描述 编写一个程序,读入一组整数,这组整数是按照从小到大的顺序排列的,它们的个数N也是由用户输入的,最多不会 ...
- Java实现 LeetCode 335 路径交叉
335. 路径交叉 给定一个含有 n 个正数的数组 x.从点 (0,0) 开始,先向北移动 x[0] 米,然后向西移动 x[1] 米,向南移动 x[2] 米,向东移动 x[3] 米,持续移动.也就是说 ...
- Java实现 LeetCode 213 打家劫舍 II(二)
213. 打家劫舍 II 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金.这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的.同时,相邻的房屋装有相互连通的防盗 ...
- Java实现 蓝桥杯VIP 算法提高 进制转换
算法提高 进制转换 时间限制:1.0s 内存限制:256.0MB 问题描述 程序提示用户输入三个字符,每个字符取值范围是0-9,A-F.然后程序会把这三个字符转化为相应的十六进制整数,并分别以十六进制 ...
- Java实现 LeetCode 115 不同的子序列
115. 不同的子序列 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字 ...