1、JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即可,数据库驱动由数据库厂商提供。
2、使用 JDBC 的好处:
1) 程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。
2) 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库
3、JDBC 的核心 API
DriverManager 类 1) 管理和注册数据库驱动 2) 得到数据库连接对象
Connection 接口 一个连接对象,可用于创建 Statement 和 PreparedStatement 对象
Statement 接口 一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器。
PreparedStatemen 接口 一个 SQL 语句对象,是 Statement 的子接口
ResultSet 接口 用于封装数据库查询的结果集,返回给客户端 Java 程序
4、DriverManager 类
4.1类中的方法:
DriverManager 类中的静态方法
|
描述
|
Connection getConnection (String url, String user, String password)
|
通过连接字符串,用户名,密码来得到数据
库的连接对象
|
Connection getConnection (String url, Properties info)
|
通过连接字符串,属性对象来得到连接对象
|
4.2使用 JDBC 连接数据库的四个参数:
JDBC 连接数据库的四个参数
|
说明
|
用户名
|
登录的用户名
|
密码
|
登录的密码
|
连接字符串 URL
|
不同的数据库 URL 是不同的,mysql 的写法
jdbc:mysql://localhost:3306/数据库[?参数名=参数值]
|
驱动类的字符串名
|
com.mysql.jdbc.Driver
|
4.4 MySQL 中可以简写:
6、Statement 接口
前提:必须是本地服务器,端口号是 3306
简写:jdbc:mysql:///数据库名
4.5 乱码的处理
如果数据库出现乱码,可以指定参数: ?characterEncoding=utf8,表示让数据库以 UTF-8 编码来处理数据。
jdbc:mysql://localhost:3306/数据库?characterEncoding=utf8
5 、Connection 接口:
5.1 Connection 作用: Connection 接口,具体的实现类由数据库的厂商实现,代表一个连接对象。
5.2 Connection 方法:
Connection 接口中的方法
|
描述
|
Statement createStatement()
|
创建一条 SQL 语句对象
|
6.2 Statement 作用: 代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。
6.3 Statement 中的方法:
Statement 接口中的方法
|
描述
|
int executeUpdate(String sql)
|
用于发送 DML 语句,增删改的操作,insert、update、delete
参数:SQL 语句
返回值:返回对数据库影响的行数
|
ResultSet executeQuery(String sql)
|
用于发送 DQL 语句,执行查询的操作。select
参数:SQL 语句
返回值:查询的结果集
|
6.4 释放资源
1) 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
2) 释放原则:先开的后关,后开的先关。ResultSet -> Statement -> Connection
3) 放在哪个代码块中:finally 块
6.5 示例
需求:使用 JDBC 在 MySQL 的数据库中创建一张学生表
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * 创建一张学生表 */ public class Demo4DDL { public static void main(String[] args) { //1. 创建连接 Connection conn = null; Statement statement = null; try { conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root"); //2. 通过连接对象得到语句对象 statement = conn.createStatement(); //3. 通过语句对象发送 SQL 语句给服务器 //4. 执行 SQL statement.executeUpdate("create table student (id int PRIMARY key auto_increment, " + "name varchar(20) not null, gender boolean, birthday date)"); //5. 返回影响行数(DDL 没有返回值) System.out.println("创建表成功"); } catch (SQLException e) { e.printStackTrace(); } //6. 释放资源 finally { //关闭之前要先判断 if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
7、ResultSet 接口:
7.1作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
7.2接口中的方法:
ResultSet 接口中的方法
|
描述
|
boolean next()
|
1) 游标向下移动 1 行
2) 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false
|
数据类型 getXxx()
|
1) 通过字段名,参数是 String 类型。返回不同的类型
2) 通过列号,参数是整数,从 1 开始。返回不同的类型
|
7.3、常用数据类型转换表
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 。
7.4需求:确保数据库中有 3 条以上的记录,查询所有的学员信息
步骤:
1) 得到连接对象
2) 得到语句对象
3) 执行 SQL 语句得到结果集 ResultSet 对象
4) 循环遍历取出每一条记录
5) 输出的控制台上
6) 释放资源
import java.sql.*; /** * 查询所有的学生信息 */ public class Demo6DQL { public static void main(String[] args) throws SQLException { //1. 创建连接 Connection conn = null; Statement statement = null; try { String url = "jdbc:mysql://localhost:3306/test02"; conn =DriverManager.getConnection(url,"root","123456"); //2. 通过连接对象得到语句对象 statement=conn.createStatement(); //3. 通过语句对象发送 SQL 语句给服务器 //4. 执行 SQL ResultSet rs= statement.executeQuery("select * FROM app08_publisher"); while (rs.next()){ int i= rs.getInt("id"); String publish=rs.getString("name"); System.out.println("编号:"+i+",出版社名称:"+publish); } } catch (SQLException e) { e.printStackTrace(); } finally { //关闭之前要先判断 if(statement != null){ try { statement.close(); } catch (SQLException e){ e.printStackTrace(); } } if(conn != null){ try{ conn.close(); } catch (SQLException e){ e.printStackTrace(); } } } } } }
8、PreparedStatement 接口
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句。
8.1、PreparedSatement 的执行原理
1) 因为有预先编译的功能,提高 SQL 的执行效率。
2) 可以有效的防止 SQL 注入的问题,安全性更高。
8.2、Connection 创建 PreparedStatement 对象
Connection 接口中的方法
|
描述
|
PreparedStatement prepareStatement(String sql)
|
指定预编译的 SQL 语句,SQL 语句中使用占位符?
创建一个语句对象
|
8.3、PreparedStatement 接口中的方法:
PreparedStatement 接口中的方法
|
描述
|
int executeUpdate()
|
执行 DML,增删改的操作,返回影响的行数。
|
ResultSet executeQuery()
|
执行 DQL,查询的操作,返回结果集
|
8.4、PreparedSatement 的好处
1、prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。
2、安全性更高,没有 SQL 注入的隐患。
3、提高了程序的可读性 。
8.5、使用 PreparedStatement 的步骤:
1) 编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
2) 获得 PreparedStatement 对象
3) 设置实际参数:setXxx(占位符的位置, 真实的值)
4) 执行参数化 SQL 语句
5) 关闭资源
PreparedStatement 中设置参数的方法
|
描述
|
void setDouble(int parameterIndex, double x)
|
将指定参数设置为给定 Java double 值。
|
void setFloat(int parameterIndex, float x)
|
将指定参数设置为给定 Java int 值。
|
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 值。
|
8.6、示例
import com.itheima.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Scanner; /** * 使用 PreparedStatement */ public class test { //从控制台上输入的用户名和密码 public static void main(String[] args) throws SQLException { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String name = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); login(name, password); } private static void login(String name, String password) throws SQLException { Connection connection = JdbcUtils.getConnection(); //写成登录 SQL 语句,没有单引号 String sql = "select * from user where name=? and password=?"; //得到语句对象 PreparedStatement ps = connection.prepareStatement(sql); //设置参数 ps.setString(1, name); ps.setString(2,password); ResultSet resultSet = ps.executeQuery(); if (resultSet.next()) { System.out.println("登录成功:" + name); } else { System.out.println("登录失败"); } //释放资源,子接口直接给父接口 JdbcUtils.close(connection,ps,resultSet); } }
9、JDBC 事务的处理
9.1、API 介绍
Connection 接口中与事务有关的方法
|
说明
|
void setAutoCommit(boolean autoCommit)
|
参数是 true 或 false
如果设置为 false,表示关闭自动提交,相当于开启事务
|
void commit()
|
提交事务
|
void rollback()
|
回滚事务
|
9.2、开发步骤
1) 获取连接
2) 开启事务
3) 获取到 PreparedStatement
4) 使用 PreparedStatement 执行两次更新操作
5) 正常情况下提交事务
6) 出现异常回滚事务
7) 最后关闭资源
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class test { //没有异常,提交事务,出现异常回滚事务 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 name=?"); 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); } } }