Java学习笔记-Day31 Java JDBC(一)
一、JDBC的API
Java数据库连接 JDBC(Java Database Connectivity),是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
1、Driver类
Driver:驱动程序,会将自身加载到 DriverManager 中去,处理相应的请求并返回相应的数据库连接(Connection)。
- com.mysql.jdbc.Driver的字节码文件
Driver 为 com.mysql.jdbc.Driver
,在 mysql-connector-java-xxxxx.jar
文件中。该文件的下载地址为:https://downloads.mysql.com/archives/c-j/
。
如果想要使用Driver,就必须添加 mysql-connector-java-xxxxx.jar
到项目的 Referenced Libraries中。Referenced Libraries 是存放第三方的 jar 包,也就是存放个人导入的 jar 包。
添加 mysql-connector-java-xxxxx.jar
到 Referenced Libraries 的步骤:
(1)将 mysql-connector-java-xxxxx.jar
文件添加到项目的 src 文件夹中。
(2)选择 mysql-connector-java-xxxxx.jar
文件,右键点击,选择 Build Path -> Add to Build Path。
(3)此时,项目中会出现 Referenced Libraries,在Referenced Libraries中会存放 mysql-connector-java-xxxxx.jar
文件。
- 加载驱动到虚拟机
Class.forName("com.mysql.jdbc.Driver");
2、DriverManager类
DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。
DriverManager 为 java.sql.DriverManager 。
- 通过DriverManager.getConnection得到一个数据库连接对象
Connection conn = DriverManager.getConnection(url, user, password);
- 部分方法
static Connection getConnection(String url, String user, String password)
:尝试建立与给定数据库URL的连接。
① url是统一资源定位符,这里的url是数据库的地址,如:String url = "jdbc:mysql://localhost:3306/schooldb";
② user是数据库的用户名,如:String user = "root";
③ password是数据库的用户的密码,如:String password = "root";
3、Connection接口
Connection:数据库连接,负责与数据库进行通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。Connection可以产生用以执行SQL的Statement。
Connection为 java.sql.Connection。
- 部分方法
(1) 创建一个Satement对象
Statement createStatement()
:创建一个 Statement对象,用于将SQL语句发送到数据库。
Statement stmt = conn.createStatement();
(2)创建一个PreparedSatement对象
PreparedStatement prepareStatement(String sql)
:创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。
sql是sql语句
String sql = "SELECT * FROM grade";
prepareStatement ps = conn.prepareStatement(sql);
(3)事务相关的方法
① void commit() throws SQLException
:提交事务。
② void rollback() throws SQLException
:撤销在当前事务中所做的所有更改。
③ void setAutoCommit(boolean autoCommit) throws SQLException
:将此连接的自动提交模式设置为给定状态。
4、Statement接口
Statement:用于执行单次的静态SQL语句并返回其生成的结果的对象。
Statement为 java.sql.Statement。
(1)执行查询的SQL语句,获得结果集
ResultSet executeQuery(String sql)
:执行给定的SQL语句,该语句返回单个 ResultSet对象。
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
注意:
executeQuery方法返回该查询生成数据的ResultSet对象,不管是否有查到数据,rs 都不为 null。如果 rs 有值,则rs.next()方法返回值为true。如果 rs 没有值,则rs.next()方法返回值为false。
(2)执行增加、修改、删除的SQL语句
int executeUpdate(String sql)
:执行给定的SQL语句,这可能是 INSERT、UPDATE 或 DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。返回值为SQL数据操作语句的行数。
Statement stmt = conn.createStatement();
int n = stmt.executeUpdate(sql);
5、PreparedStatement接口
PreparedStatement:用以执行包含动态参数的SQL查询和更新。
PreparedStatement可以使用占位符,是可以预编译的。PreparedStatement比Statement 更安全,能防止 SQL 注入攻击(在拼接SQL语句时,使用条件为真)。
PreparedStatement为 java.sql.PreparedStatement。
- 部分方法
(1)setXxx方法
通过调用Connection对象的prepareStatement方法(传递的参数是sql语句),将会获取到一个PreparedStatement对象。在传递的sql语句可以使用问号 ?代替一个值,之后再调用PreparedStatement对象的setXxx方法为sql语句的问号 ?赋值。
void setInt(int parameterIndex,int x) throws SQLException
:将指定的参数设置为给定的Java int值。 当驱动程序将其发送到数据库时,将其转换为SQL INTEGER值。
void setString(int parameterIndex,String x) throws SQLException
:将指定的参数设置为给定的Java String值。 当它发送到数据库时,驱动程序将其转换为SQL VARCHAR或LONGVARCHAR值。
String sql = "UPDATE grade SET gradename = ? WHERE gradeid = ?;";
ps = conn.prepareStatement(sql);
ps.setString(1, grade.getGradeName());
ps.setInt(2, grade.getGradeInt());
(2)执行查询的SQL语句,获得结果集
ResultSet executeQuery() throws SQLException
:执行此 PreparedStatement对象中的SQL查询,并返回查询 PreparedStatement的 ResultSet对象。
ResultSet rs = ps.executeQuery();
(3)执行增加、修改、删除的SQL语句
int executeUpdate() throws SQLException
:执行在该SQL语句PreparedStatement对象,它必须是一个SQL数据操纵语句,如 INSERT 、UPDATE 或 DELETE,或不返回任何内容的SQL语句,例如DDL语句。
int n = ps.executeUpdate();
6、ResultSet接口
ResultSet 接口表示数据库结果集的数据表,通常通过查询语句生成。ResultSet 是一个存储查询结果的对象,同时这个对象还具有操纵数据的功能。
ResultSet 是非离线读取,ResultSet 在数据库连接关闭之后就不能使用了,必须要在一直保持连接的状态才能使用,否则需要使用到Rowset离线结果集。
ResultSet 只能读取一次。在执行 Statement 的executeQuery方法的时候,会自动关闭上一次调用 Statement 的executeQuery方法的结果集。
ResultSet 是 java.sql.ResultSet 。
- 处理结果集
while (rs.next()) {
int id = rs.getInt("gradeid");
String name = rs.getString("gradename");
System.out.println(id + "\t" + name);
}
(1)next()方法
一个 ResultSet 对象具有一个光标指向当前行的结果集。调用 next()
会将光标从当前位置向下移动一行。ResultSet的光标最初位于第一行之前,第一次调用 next()
方法会使第一行成为当前行,第二次调用next()
方法会使第二行成为当前行,依此类推。当光标位于最后一行之后,也就是 ResultSet 集合中已经没有下一行了,此时调用 next()
方法将会返回 false。 所以可以在 while 循环中使用 next()
来迭代结果集。
boolean next() throws SQLException
:将光标从当前位置向下移动一行。
(2)getXxx方法
ResultSet 提供用于从当前行获取列值的获取方法,可以使用列的索引编号或列的名称来获取列的值。一般情况下,使用列索引较为高效,列的编号从1开始。为了获得最大的可移植性,应该按从左到右的顺序读取每行中的结果集列, 每列只能读取一次。用作获取方法的输入的列名称不区分大小写。
调用 getXxx(int fieldIndex)
或者 getXxx(String columnName)
方法获取数据库的表中的字段值。
int getInt(int columnIndex) throws SQLException
:以Java编程语言中的 int此 ResultSet对象当前行中指定列的值。 参数columnIndex是列的编号,如数据库表的第一列是1,第二列是2,依此类推。返回的结果是列的值,如果值为SQL NULL ,则返回的值为0。
int getInt(String columnLabel) throws SQLException
:这个检索的当前行中指定列的值 ResultSet作为对象 int在Java编程语言。参数columnLabel 是使用SQL AS子句指定的列的标签。 返回的结果是列的值,如果值为SQL NULL ,返回值为0 。
- ResultSet接口的继承关系
二、JDBC的使用步骤
(1)通过 Class.forName("com.mysql.jdbc.Driver")
加载驱动。
(2)通过DriverManager的静态方法 getConnection(url,user,passsword)
获取数据库连接。
(3)通过 Connection 的 prepareStatement 方法获取 PreparedStatement 对象。
(4)通过 PreparedStatement 预编译对象执行SQL语句,获取结果。① 查询:调用 executeQuery 方法获取 ResultSet 结果集。② 增加、删除、修改:调用 executeUpdate 方法获取int值。
(5)处理结果:① ResultSet:通过 next() 方法遍历 ResultSet 。 ② int值表示的是受到影响的行数。
(6)通过 close() 方法释放资源。
- 实体类 grade
public class Grade {
private int gradeInt;
private String gradeName;
public int getGradeInt() {
return gradeInt;
}
public void setGradeInt(int gradeInt) {
this.gradeInt = gradeInt;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public Grade(int gradeInt, String gradeName) {
super();
this.gradeInt = gradeInt;
this.gradeName = gradeName;
}
public Grade() {
super();
}
}
1、查询数据
- 查询全部年级信息
/** 查询全部年级信息 */
public static List<Grade> ListGrade() {
List<Grade> list = new ArrayList<Grade>();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/schooldb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "SELECT * FROM grade;";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
Grade grade = new Grade(rs.getInt("gradeid"), rs.getString("gradename"));
list.add(grade);
grade = null;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
- 根据年级编号查询年级信息
/** 根据年级编号查询年级信息 */
public static Grade getGradeById(int gradeid) {
Grade grade = null;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/schooldb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "SELECT * FROM grade WHERE gradeid = ?;";
ps = conn.prepareStatement(sql);
ps.setInt(1, gradeid);
rs = ps.executeQuery();
if (rs.next()) {
grade = new Grade(rs.getInt("gradeid"), rs.getString("gradename"));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return grade;
}
2、增加数据
- 添加年级信息
/** 添加年级信息 */
public static int addGrade(String gradename) {
int result = -1;
Connection conn = null;
PreparedStatement ps = null;
String url = "jdbc:mysql://localhost:3306/schooldb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO grade(gradeid,gradename) VALUES(DEFAULT,?);";
ps = conn.prepareStatement(sql);
ps.setString(1, gradename);
result = ps.executeUpdate();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
3、删除数据
- 删除年级信息
/** 删除年级信息 */
public static int deleteGrade(int gradeid) {
int result = -1;
Connection conn = null;
PreparedStatement ps = null;
String url = "jdbc:mysql://localhost:3306/schooldb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "DELETE FROM grade WHERE gradeid = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, gradeid);
result = ps.executeUpdate();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
4、修改数据
- 修改年级信息
/** 修改年级信息 */
public static int updateGrade(Grade grade) {
int result = -1;
Connection conn = null;
PreparedStatement ps = null;
String url = "jdbc:mysql://localhost:3306/schooldb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "UPDATE grade SET gradename = ? WHERE gradeid = ?;";
ps = conn.prepareStatement(sql);
ps.setString(1, grade.getGradeName());
ps.setInt(2, grade.getGradeInt());
result = ps.executeUpdate();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
三、JDBC的相关知识
1、Statement 和 PreparedStatement的区别
(1)PreparedStatement 继承自 Statement,二者都是接口。
(2)PreparedStatement 表示预编译的 SQL 语句的对象,SQL 语句被预编译并存储在 PreparedStatement 对象中,可以使用此对象多次高效地执行该语句。
(3)Statement 用于执行静态 SQL 语句并返回它所生成结果的对象,不能使用占位符。
(4)PreparedStatement 极大地提高了安全性,由于支持了占位符的写法,所以避免了sql语句的注入。
2、关于JDBC中的加载驱动
在 com.mysql.jdbc.Driver 的源码中有一段静态代码段是用来注册驱动的,当加载Driver类时,就会执行这段静态代码段,所以可以通过 Class.forName("com.mysql.jdbc.Driver");
或者 new com.mysql.jdbc.Driver();
来加载驱动。
低版本的 mysql 驱动包需要通过 Class.forName("com.mysql.jdbc.Driver");
或者 new com.mysql.jdbc.Driver();
来加载驱动。例如:mysql-connector-java-5.1.5.jar
。
高版本的 mysql 驱动包不需要通过 Class.forName("com.mysql.jdbc.Driver");
或者 new com.mysql.jdbc.Driver();
来加载驱动。例如:mysql-connector-java-5.1.18.jar
。
mysql驱动包的高版本和低版本有些不同,在高版本的 mysql 驱动包中多了一个service文件夹。在该文件夹中有个 java.sql.Driver 文件,在该文件中包含 com.mysql.jdbc.Driver。
在 JDK 中有个特性:SPI(服务提供接口)在Jar 包的 JVM 会将在 Meta-Inf\service\某个接口 中定义的那个类 自动加载到 JVM 中。