Statement PreparedStatement CallableStatement 之间的相同和差异

相同点

首先要知道Statement  PreparedStatement  CallableStatement均为接口(interface)	
JDBC用这三种方式执行查询语句

不同点

  1. 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. 代码的可读性和可维护性。

  1. 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();   
                        }   
                }   
        }   
}

由于博主本人技术不行,本篇博客借鉴了很多大佬的博客
谢谢各位大佬


版权声明:本文为qq_43741153原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。