JDBC(2)
- JDBC接口
接口 |
应用场景 |
Statement |
当在运行时使用静态 SQL 语句时(Statement接口不能接受的参数) |
PrepareStatement | 当计划多次使用 SQL 语句时(PreparedStatement 接口接收在运行时输入参数) |
CallableStatement |
当要访问数据库中的存储过程时(CallableStatement对象的接口还可以接受运行时输入参数) |
- Statement接口
1、boolean execute(String SQL)
如果 ResultSet 对象可以被检索返回布尔值 true,否则返回 false。使用这个方法来执行 SQL DDL 语句,或当需要使用真正的动态 SQL
2、int executeUpdate(String SQL)
用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQLDDL(数据定义语言)语句。返回值是一个整数,指示受影响的行数(即更新计数)
3、ResultSet executeQuery(String SQL)
返回 ResultSet 对象。用于产生单个结果集的语句,例如 SELECT 语句
- PrepareStatement接口
PreparedStatement 接口扩展了 Statement 接口,有利于高效地执行多次使用的 SQL 语句
import java.sql.*;
public class JdbcTest {
// JDBC 驱动器的名称和数据库地址
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";
static final String USER = "root";
static final String PASS = "";
public static void main(String[] args) {
Connection conn = null;
PreparedStatement stmt = null;
try{
//注册 JDBC 驱动器
Class.forName("com.mysql.jdbc.Driver");
//打开连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
//执行查询
System.out.println("Creating statement...");
//这里我们要更改一个同学的年龄,参数待定
String sql = "UPDATE Students set age=? WHERE id=?";
stmt = conn.prepareStatement(sql);
//将值绑定到参数,参数从左至右序号为1,2...
stmt.setInt(1, 22); // 绑定 age 的值(序号为1)
stmt.setInt(2, 1); // 绑定 ID 的值
// 更新 ID 为1的同学的年龄
int rows = stmt.executeUpdate();
System.out.println("被影响的行数 : " + rows );
// 查询所有记录,并显示.
sql = "SELECT id, name, age FROM Students";
ResultSet rs = stmt.executeQuery(sql);
//处理结果集
while(rs.next()){
//检索
int id = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
//显示
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
System.out.println();
}
//清理
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}
- CallableStatement接口
CallableStatement 对象为所有的 DBMS 提供了一种以标准形式调用存储过程的方法。存储过程储存在数据库中。对储存过程的调用是 CallableStatement 对象所含的内容。三种类型的参数有:IN,OUT和INOUT。
CallableStatement cstmt = null;
try {
String SQL = "{call getEXAMPLEName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
cstmt.close();
}
- ResultSet结果集
结果集通常是通过执行查询数据库的语句生成,表示数据库查询结果的数据表。ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。光标可以方便我们对结果集进行遍历。默认的 ResultSet 对象不可更新,仅有一个向前移动的光标。因此,只能迭代它一次,并且只能按从第一行到最后一行的顺序进行。
ResultSet接口的方法可分为三类:
1、导航方法:用于移动光标
2、获取方法:用于查看当前行的光标所指向的列中的数据
3、更新方法:用于更新当前行的列中的数据
JDBC 提供下列连接方法来创建所需的ResultSet语句:
createStatement(int RSType, int RSConcurrency);
prepareStatement(String SQL, int RSType, int RSConcurrency);
prepareCall(String sql, int RSType, int RSConcurrency);
RSType 表示 ResultSet 对象的类型,RSConcurrency 是 ResultSet 常量,用于指定一个结果集是否为只读或可更新。
ResultSet 的类型,如果不指定 ResultSet 类型,将自动获得一个是 TYPE_FORWARD_ONLY。
类型(RSType) |
描述 |
ResultSet.TYPE_FORWARD_ONLY |
游标只能向前移动的结果集 |
ResultSet.TYPE_SCROLL_INSENTITIVE | 游标可以向前和向后滚动,但不及时更新,就是如果数据库里的数据修改过, 并不在ResultSet中反应出来 |
ResultSet.TYPE_SCROLL_SENTITIVE |
游标可以向前和向后滚动,并及时跟踪数据库的更新,以便更改ResultSet中的数据 |
并发(RSConcurrency) |
描述 |
ResultSet.CONCUR_READ_ONLY |
创建结果集只读。默认 |
ResultSet.CONCUR_READ_UPDATABLE |
创建一个可更新的结果集 |
比如初始化一个 Statement 对象来创建一个双向、可更新的ResultSet对象:
try {
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
}
catch(Exception ex) {
....
}
finally {
....
}
- 导航方法(用于光标的移动)
ResultSet接口中以下方法涉及游标的移动:
实例代码:
import java.sql.*;
public class JdbcTest {
// JDBC 驱动器名称 和数据库地址
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
//数据库的名称为 EXAMPLE
static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";
// 数据库用户和密码
static final String USER = "root";
static final String PASS = "";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
//注册JDBC 驱动程序
Class.forName("com.mysql.jdbc.Driver");
//打开连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
System.out.println("Creating statement...");
//创建所需的ResultSet,双向,只读
stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
String sql;
sql = "SELECT id, name, age FROM Students";
ResultSet rs = stmt.executeQuery(sql);
// 将光标移到最后一行
System.out.println("Moving cursor to the last...");
rs.last();
//处理结果集
System.out.println("Displaying record...");
int id = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
//显示
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
System.out.println();
// 将光标移到第一行
System.out.println("Moving cursor to the first row...");
rs.first();
System.out.println("Displaying record...");
id = rs.getInt("id");
age = rs.getInt("age");
name = rs.getString("name");
//显示
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
//将光标移至下一行
System.out.println("Moving cursor to the next row...");
rs.next();
System.out.println("Displaying record...");
id = rs.getInt("id");
age = rs.getInt("age");
name = rs.getString("name");
// 显示
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}
- 获取方法(获取结果集的某填数据)
方法 |
说明 |
public int getInt(String columnName) throws SQLException |
获取当前行中名为 ColumnName 列的值 |
public int getInt(int columnIndex) throws SQLException |
获取当前行中指定列的索引的值。列索引从1开始, 意味着一个行的第一列是1,行的第二列是2。 |
getString等方式类似。
- 更新方法
1、更新结果集
方法 |
说明 |
public void updateString(String columnName,String s) throws SQLException |
修改当前行中名为 ColumnName 列的值为s |
public void updateString (int columnIndex,String s)) throws SQLException |
修改当前行中指定列中索引的值为s |
updateDouble()等方式类似。
2、更新数据库(在更新结果集之后)
方法 |
说明 |
public void updateRow() |
将当前行记录更新到数据库 |
public void deleteRow() |
从数据库删除当前行 |
public void refreshRow() |
用数据库中的最近值刷新当前行 |
public void cancelRowUpdates() |
取消对 ResultSet 对象中的当前行所作的更新。此方法在调用更新方法之后,但在调用 updateRow 方法之前调用才可以回滚对行所作的更新。如果没有进行任何更新或者已经调用 updateRow 方法,则此方法无效 |
public void insertRow() |
将当前行记录插入到数据库 |
代码示例:
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String sql = "SELECT id, name, age FROM Students";
ResultSet rs = stmt.executeQuery(sql);
//将光标移动到一个特殊的行,可以用来插入新行到结果集。当前光标位置被记住
rs.moveToInsertRow();
//结果集中插入新行
rs.updateInt("id",5);
rs.updateString("name","John");
rs.updateInt("age",21);
//将插入结果集的新行插入到数据库中
rs.insertRow();
//将光标返回到当前行(返回到moveToInsertRow() 方法中被记住的光标位置)
rs.moveToCurrentRow();
- JDBC事务
默认情况下,JDBC连接是自动提交模式的,每条SQL语句执行完后自动提交到数据库。
事务是一条或者多条SQL语句作为一个逻辑单元,并且如果事务中任何语句执行失败,则整个事务失败。
自己管理和控制事务可以:
1、提高程序的运行性能
2、保持业务流程的完整性
3、采用分布式事务管理方式
事务的四大特性:(ACID)
1、原子性(Atomicity)
2、一致性(Consistency)
3、隔离性(Isolation)
4、持久性(Durability)
开启JDBC事务需要关闭自动提交:
Connection conn = null;
conn = DriverManager.getConnection(URL);
//关闭自动提交
conn.setAutoCommit(false);
事务的提交:
conn.commit();
事务的回滚:
conn.rollBack();
代码示例:
import java.sql.*;
public class JdbcTest {
// JDBC 驱动器名称 和数据库地址
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
//数据库的名称为 EXAMPLE
static final String DB_URL = "jdbc:mysql://localhost/EXAMPLE";
// 数据库用户和密码
static final String USER = "root";
static final String PASS = "";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
//注册JDBC 驱动程序
Class.forName("com.mysql.jdbc.Driver");
//打开连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
conn.setAutoCommit(false);
//执行查询
System.out.println("Creating statement...");
stmt = conn.createStatement();
//插入
String sql = "INSERT INTO Students " +
"VALUES (5, 20, 'Rose')";
stmt.executeUpdate(sql);
//查找
sql = "SELECT id, name, age FROM Students";
ResultSet rs = stmt.executeQuery(sql);
//提交事务
conn.commit();
//得到和处理结果集
while(rs.next()){
//检索
int id = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
//显示
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
System.out.println();
}
//清理环境
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
// JDBC 操作错误
se.printStackTrace();
// conn.rollback();
try{
if(conn!=null)
conn.rollback();
}catch(SQLException se2){
se2.printStackTrace();
}
}catch(Exception e){
// Class.forName 错误
e.printStackTrace();
}finally{
//这里一般用来关闭资源的
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}
- JDBC批处理
批量处理允许将相关的SQL语句分组到批处理中,并通过对数据库的一次调用来提交它们,一次执行完成与数据库之间的交互。
不需要JDBC驱动程序来支持此功能。应该使用DatabaseMetaData.supportsBatchUpdates()方法来确定目标数据库是否支持批量更新处理。如果JDBC驱动程序支持此功能,该方法将返回true。
- 使用Statement对象进行批处理
1、使用createStatement()方法创建一个Statement对象
2、设置使用自动提交为 false
3、添加任意多个SQL 语句到批量处理,使用addBatch()方法
4、使用executeBatch()方法,将返回一个整数数组,数组中的每个元素代表了各自的更新语句的更新计数
5、最后,提交使用commit()方法的所有更改
//创建 statement 对象
Statement stmt = conn.createStatement();
//关闭自动提交
conn.setAutoCommit(false);
//创建 SQL 语句
String SQL = "INSERT INTO Students (id, name, age) VALUES(6,'Mike', 21)";
//将 SQL 语句添加到批处理中
stmt.addBatch(SQL);
//创建更多的 SQL 语句
String SQL = "INSERT INTO Students (id, name, age) VALUES(7, 'Angle', 23)";
//将 SQL 语句添加到 批处理中
stmt.addBatch(SQL);
//创建整数数组记录更新情况
int[] count = stmt.executeBatch();
//提交更改
conn.commit()
- 使用prepareStatement对象进行批处理
String SQL = "INSERT INTO Employees (id, name, age) VALUES(?, ?, ?)";
//创建 PrepareStatement 对象
PreparedStatemen pstmt = conn.prepareStatement(SQL);
//关闭自动连接
conn.setAutoCommit(false);
//绑定参数
pstmt.setInt( 1, 8 );
pstmt.setString( 2, "Cindy" );
pstmt.setInt( 3, 17 );
//添入批处理
pstmt.addBatch();
//绑定参数
pstmt.setInt( 1, 9 );
pstmt.setString( 2, "Jeff" );
pstmt.setInt( 3, 22 );
//添入批处理
pstmt.addBatch();
//创建数组记录更改
int[] count = pstmt.executeBatch();
//提交更改
conn.commit();