一、JDBC概述
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成,是Java访问数据库的标准规范,具体的实现由各大数据库厂商来实现。即真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即可,数据库驱动由数据库厂商提供。
我使用的是mysql的驱动mysql-connector-java-5.1.37-bin.jar
链接:https://pan.baidu.com/s/1HDQFZIL7MGfjOFdqZBIQ0A
提取码:ab4d
导入jar包过程:
使用 JDBC 的好处:
- 程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。
2. 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库。
使用JDBC开发时可能使用的包:
会使用到的包 说明 | |
java.sql | 所有与 JDBC 访问数据库相关的接口和类 |
javax.sql | 数据库扩展包,提供数据库额外的功能。如:连接池 |
数据库的驱动 | 由各大数据库厂商提供,需要额外去下载,是对 JDBC 接口实现的类 即mysql-connector-java-5.1.37-bin.jar |
JDBC 的核心 API
接口或类 作用 | |
DriverManager 类 |
|
Connection 接口 | 一个连接对象,可用于创建 Statement 和 PreparedStatement 对象 |
Statement 接口 | 一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器。 |
PreparedStatement 接口 | 一个 SQL 语句对象,是 Statement 的子接口 |
ResultSet 接口 | 用于封装数据库查询的结果集,返回给客户端 Java 程序 |
二、JDBC实现
JDBC 访问数据库的步骤:
- 注册和加载驱动(可以省略)
- 获取连接DriverManager.getConnection(url,user,password)
- Connection 获取 Statement 对象connection.createStatement()/perpareStatement()
- 使用 Statement / perparedStatement 对象执行 SQL 语句
- 返回结果集
- 释放资源(关闭ResultSet结果集、connection连接和statement语句)
- 释放原则:先开的后关,后开的先关。ResultSet-->Statement-->Connection
- 放在哪个代码块中:finally 块
1. 导入驱动jar包:
https://blog.csdn.net/krismile__qh/article/details/89305380*
*2. 加载和注册驱动:(注:从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。Class.forName 这句话可以省略。)
加载和注册驱动的方法 描述 | |
Class.forName(数据库驱动实现类) | 加载和注册数据库驱动,数据库驱动由 mysql 厂商提供 "com.mysql.jdbc.Driver"说明是com.mysql.jdbc包下的Driver接口 Driver 接口,所有数据库厂商必须实现的接口,表示这是一个驱动类 |
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
//抛出类找不到的异常,注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//固定写法
}
}
3. 获得连接:DriverManager类
(作用:管理和注册驱动、创建数据库的连接)
1. DriverManager类中的方法:
DriverManager 类中的静态方法 描述 | |
Connection getConnection (String url, String user, String password) | 通过连接字符串,用户名,密码来得到数据 库的连接对象 |
Connection getConnection (String url, Properties info) | 通过连接字符串,属性对象来得到连接对象 |
2. 通过用户名、密码、URL得到连接对象
代码:Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb”,”root”,”root”);
其中三个参数分别表示:url 需要连接数据库的位置(网址) user用户名 password 密码
url比较复杂,例如mysql的url:jdbc:mysql://localhost:3306/mydb
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
1.第一部分是jdbc,这是固定的;
2.第二部分是数据库名称,那么连接mysql数据库,第二部分当然是mysql了;
3.第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb)组成。
3. 使用属性文件和 url 得到连接对象
public static void main(String[] args) throws SQLException {
//url 连接字符串
String url = "jdbc:mysql://localhost:3306/day24";
//属性对象
Properties info = new Properties();
//把用户名和密码放在 info 对象中
info.setProperty("user","root");
info.setProperty("password","root");
Connection connection = DriverManager.getConnection(url, info);
//com.mysql.jdbc.JDBC4Connection@68de145 System.out.println(connection);
}
4. 获得语句执行平台:Connection 接口
(具体的实现类由数据库的厂商实现,代表一个连接对象)
1. Connection接口下的方法:
Statement接口:
(代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所执行成结果的对象。)
String sql = "某SQL语句";
获取Statement语句执行平台:Statement stmt = connection.createStatement();
常用方法:
- int executeUpdate(String sql); --执行insert update delete语句.
- ResultSet executeQuery(String sql); --执行select语句.
- boolean execute(String sql); --执行select查询出结果集返回true 执行其他的语句返回false.
处理结果集:ResultSet接口
(封装数据库查询的结果集,对结果集进行遍历,取出每一条记录)
常用方法:
ResultSet 接口中的方法 描述 | |
boolean next() |
|
数据类型 getXxx() |
|
常用数据类型转换表:
SQL 类型 Jdbc 对应方法 返回类型 | ||
BIT(1) bit(n) | getBoolean() | boolean |
TINYINT | getByte() | byte |
SMALLINT | getShort() | short |
INT | getInt() | int |
BIGINT | getLong() | long |
CHAR,VARCHAR | getString() | String |
Text(Clob) Blob | getClob getBlob() | Clob Blob |
DATE | getDate() | java.sql.Date 只代表日期 |
TIME | getTime() | java.sql.Time 只表示时间 |
TIMESTAMP | getTimestamp() | java.sql.Timestamp 同时有日期和时间 |
(注:java.sql.Date、Time、Timestamp(时间戳),三个共同父类是:java.util.Date)
SQL注入问题:
示例:
· 当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了
请输入用户名:
newboy
请输入密码:
'a' or '1' = '1'
登录成功,欢迎您:newboy
· 问题分析:
select * from user where name='newboy' and password='a' or '1'='1'
(name='newboy' and password='a') 为假
('1'='1') 真
相当于
select * from user where true; 查询了所有记录
我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有 SQL 真正的意义,以上问题称为 SQL 注入。要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进行简单的字符串拼接。
PreparedStatemrnt接口:
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句。
PerparedStatement的执行原理:
- 因为有预先编译的功能,提高 SQL 的执行效率。
- 可以有效的防止 SQL 注入的问题,安全性更高。
PreparedStatement 接口中的方法:
PreparedStatement 接口中的方法 描述 | |
int executeUpdate() | 执行 DML,增删改的操作,返回影响的行数。 |
ResultSet executeQuery() | 执行 DQL,查询的操作,返回结果集 |
PreparedStatement 中设置参数的方法 描述 | |
void setDouble(int parameterIndex, double x) | 将指定参数设置为给定 Java double 值。 |
void setFloat(int parameterIndex, float x) | 将指定参数设置为给定 Java REAL 值。 |
void setInt(int parameterIndex, int x) | 将指定参数设置为给定 Java int 值。 |
void setLong(int parameterIndex, long x) | 将指定参数设置为给定 Java long 值。 |
void setObject(int parameterIndex, Object x) | 使用给定对象设置指定参数的值。 |
void setString(int parameterIndex, String x) | 将指定参数设置为给定 Java String 值。 |
使用 PreparedStatement 的步骤:
- 编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
- 获得 PreparedStatement 对象(传参数sql)
- 设置实际参数:setXxx(占位符的位置, 真实的值)
- 执行参数化 SQL 语句
- 关闭资源
三、JDBC事务的处理
1. 什么是事务
在实际的开发过程中,一个业务操作如:转账,往往是要多次访问数据库才能完成的。转账是一个用户扣钱,另一个用户加钱。如果其中有一条 SQL 语句出现异常,这条 SQL 就可能执行失败。
事务执行是一个整体,所有的 SQL 语句都必须执行成功。如果其中有 1 条SQL 语句出现异常,则所有的SQL 语句都要回滚,整个业务执行失败。
2. API介绍
Connection 接口中与事务有关的方法 说明 | |
void setAutoCommit(boolean autoCommit) | 参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务 start transaction;开启事务 |
void commit() | 提交事务 |
void rollback() | 回滚事务,会回退到开启事务时的状态 |
自动提交事务:
MySQL 默认每一条 DML(增删改)语句都是一个单独的事务,每条语句都会自动开启一个事务,语句执行完毕自动提交事务,MySQL 默认开始自动提交事务
手动提交事务:
MYSQL 中可以有两种方式进行事务的操作:
- 手动提交事务
- 自动提交事务
手动提交事务使用过程:
- 执行成功的情况: 开启事务-->执行多条 SQL 语句-->成功提交事务
- 执行失败的情况: 开启事务-->执行多条 SQL 语句-->事务的回滚
3. 银行转账Java代码案例:
package com.qf;
import com.qf.utils.JdbcUtils; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.SQLException;
public class Demo12Transaction {
//没有异常,提交事务,出现异常回滚事务
public static void main(String[] args) {
//1) 注册驱动
Connection connection = null;
PreparedStatement ps = null;
try {
//2) 获取连接
connection = JdbcUtils.getConnection();
//3) 开启事务
connection.setAutoCommit(false);
//4) 获取到 PreparedStatement
//从 jack 扣钱
ps = connection.prepareStatement("update account set balance = balance - ? where name=?");
ps.setInt(1, 500);
ps.setString(2,"Jack");
ps.executeUpdate();
//出现异常
System.out.println(100 / 0);
//给 rose 加钱
ps = connection.prepareStatement("update account set balance = balance + ?where ps.setInt(1, 500); ps.setString(2,"Rose");
ps.executeUpdate();
//提交事务
connection.commit();
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
try {
//事务的回滚
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("转账失败");
}finally {
//7) 关闭资源
JdbcUtils.close(connection,ps);
}
}