相同点
首先要知道Statement PreparedStatement CallableStatement均为接口(interface)
JDBC用这三种方式执行查询语句
不同点
- Statement
接口:public interface Statement extends Wrapper
Statement继承自Wrapper,Statement接口提供了执行语句和获取结果的基本方法
普通的不带参的查询SQL;支持批量更新,批量删除;
Statement statement = conn.createStatement(); //不用传入参数
Statement每次执行sql语句,数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形
Statement每次执行sql语句,数据库都要执行sql语句的编译 ,
最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement
作用:代表SQL语句对象。可以向数据库发送任何的SQL语句
2. PreparedStatement
接口:public interface PreparedStatement extends Statement
PreparedStatement继承自Statement,需要传参
PerparedStatement pre = conn.prepareStatement(sql); //这里必须传入参数
可变参数的SQL,编译一次,执行多次,效率高; 安全性好,有效防止Sql注入等问题;支持批量更新,批量删除
支持SQL的预编译 得到该对象时,就必须给他SQL语句
支持参数占位符:? 一个问号代表着一个参数
PreparedStatement是预编译的,使用PreparedStatement有几个好处 :
1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
4. 安全性好,有效防止Sql注入等问题。
5. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
6. 代码的可读性和可维护性。
- CallableStatement
继承自PreparedStatement,支持带参数的SQL操作;
支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持
主要实例:
1.statement:
在默认情况下,同一时间每个 Statement 对象只能打开一个 ResultSet 对象。因此,如果读取一个 ResultSet 对象与另一个交叉,则这两个对象必须是由不同的 Statement 对象生成的。如果存在某个语句的打开的当前 ResultSet 对象,则 Statement 接口中的所有执行方法都会隐式关闭它。
如以下操作:创建statement对象
Statement stat=conn.createStatement();
String sql=“insert into lover values(6,‘suxingxing’,to_date(‘21-9-2016’,‘dd-mm-yyyy’))”;
stat.execute(sql);//这里提交时应该有sql语句,不同于PreparedStatment
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.cj.xdevapi.Statement;
public class EmployAdd {
public static void main(String[] args) {
select();
}
public static void select() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8";
String user = "root";
String password = "1234556";
Connection connection = DriverManager.getConnection(url,user,password);
Statement statement = (Statement) connection.createStatement();
ResultSet resultSet = ((java.sql.Statement) statement).executeQuery("select * from qqq");
while(resultSet.next()){
String id = resultSet.getString("id");
String userName = resultSet.getString(2);
String passWord = resultSet.getString(3);
System.out.print(id+"--");
System.out.print(userName+"--");
System.out.print(passWord);
System.out.println();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.PreparedStatement
SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
注:用于设置 IN 参数值的设置方法(setShort、setString 等等)必须指定与输入参数的已定义 SQL 类型兼容的类型。例如,如果 IN 参数具有 SQL 类型 INTEGER,那么应该使用 setInt 方法,问号的位置也是应该注意的,因为第一个问好的位置为1,第二个问号的位置为2.以此类推。
如果需要任意参数类型转换,使用 setObject 方法时应该将目标 SQL 类型作为其参数。
在以下设置参数的示例中,con 表示一个活动连接:
PreparedStatement pstmt = con.prepareStatement(“UPDATE EMPLOYEES SALARY = ? WHERE ID = ?”);
pstmt.setBigDecimal(1, 1533.00)
pstmt.setInt(2, 1102)
pstmt.execute()//注意提交时这里不能再有sql语句,不同于Statment
实例如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class PreparedStatementTest {
public static void main(String[] args) {
test_autoCommit();
}
public static void test_autoCommit()
{
String driver="oracle.jdbc.driver.OracleDriver";
String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String user="briup";
String password="briup";
Connection conn=null;
PreparedStatement ps=null;
try {
//1、注册驱动
Class.forName(driver);
//2、获取连接
conn= DriverManager.getConnection(url, user, password);
//System.out.println(conn);
//3、创建prepareStatement对象
String sql="insert into lover values(?,?,?)";
ps=conn.prepareStatement(sql);
//4、执行sql语句
ps.setInt(1,21);//代表设置给第一个?号位置的值为Int类型的21
ps.setString(2,"suwu150");//代表设置给第二个?号位置的值为String类型的suwu150
java.util.Date utilDate=new java.util.Date();//进行类型转换,由util类型的date转化为sql类型的
ps.setDate(3, new java.sql.Date(utilDate.getTime()));
//ps.execute();//执行
System.out.println(ps.execute());//执行表输出返回的结果,结果为false,因为没有返回的结果集
//5、处理结果集
} catch (Exception e) {
e.printStackTrace();
}
finally{
//6、关闭资源
try {
if(ps!=null)ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null)conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.CallableStatement
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class TestCallableStatement {
//调用简单的存储过程
public static void call1(){
Connection conn = new ConnectionUtil().openConnection();
try {
CallableStatement cstmt = conn.prepareCall("{call all_user()}");
ResultSet rs = cstmt.executeQuery();
while(rs.next()){
int id = rs.getInt(1);
String user = rs.getString(2);
String password = rs.getString(3);
int age = rs.getInt(4);
System.out.println(id+":"+user+":"+password+":"+age);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//调用有输入参数的存储过程
public static void call2(){
Connection conn = new ConnectionUtil().openConnection();
try {
CallableStatement cstmt = conn.prepareCall("{call insert_user(?,?,?)}");
cstmt.setString(1, "test1");
cstmt.setString(2, "test2");
cstmt.setInt(3, 3);
cstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//调用有输入输出参数的存储过程
public static void call3(){
Connection conn = new ConnectionUtil().openConnection();
try {
CallableStatement cstmt = conn.prepareCall("{call getAgeByName(?,?)}");
cstmt.setString(1, "redking");
//注册输出参数
cstmt.registerOutParameter(2, Types.INTEGER);
cstmt.execute();
int age = cstmt.getInt(2);
System.out.println(age);
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
由于博主本人技术不行,本篇博客借鉴了很多大佬的博客
谢谢各位大佬