Statement与PreparedStatement

Statement

  Statement:Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。具体步骤:

1.首先导入java.sql.*;这个包。
2.然后加载驱动,创建连接,得到Connection接口的的实现对象,比如对象名叫做conn。
3.然后再用conn对象去创建Statement的实例,方法是:
Statement stmt = conn.creatStatement("SQL语句字符串");

  Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和CallableStatement(它从 PreparedStatement 继承而来)。它们都专用于发送特定类型的 SQL 语句:

Statement 对象用于执行不带参数的简单 SQL 语句;
PreparedStatement 对象用于执行带或不带参数的预编译 SQL 语句;
CallableStatement 对象用于执行对数据库已存储过程的调用。

  综上所述:Statement每次执行sql语句,数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。但存在sql注入风险。PreparedStatement是预编译执行的。在执行可变参数的一条SQL时,PreparedStatement要比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率高。安全性更好,有效防止SQL注入的问题。对于多次重复执行的语句,使用PreparedStatement效率会更高一点。执行SQL语句是可以带参数的,并支持批量执行SQL。由于采用了Cache机制,则预编译的语句,就会放在Cache中,下次执行相同的SQL语句时,则可以直接从Cache中取出来。

PreparedStatement pstmt  =  con.prepareStatement("UPDATE EMPLOYEES  SET name= ? WHERE ID = ?");
pstmt.setString(1, "李四");
pstmt.setInt(2, 1);
pstmt. executeUpdate();

  那么CallableStatement扩展了PreparedStatement的接口,用来调用存储过程,它提供了对于输入和输出参数的支持,CallableStatement 接口还有对 PreparedStatement 接口提供的输入参数的sql查询的支持。

  PreparedStatement: 数据库会对sql语句进行预编译,下次执行相同的sql语句时,数据库端不会再进行预编译了,而直接用数据库的缓冲区,提高数据访问的效率,如果sql语句只执行一次,以后不再复用。PreparedStatement通过?来传递参数,避免了拼sql而出现sql注入的问题,所以安全性较好。

  其实这俩干的活儿都一样,就是创建了一个对象然后去通过对象调用executeQuery方法来执行sql语句。

String sql = "select * from users where  username= '"+username+"' and userpwd='"+userpwd+"'";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);

  而下面则是使用了PrepareStatement方法创建了pstmt对象,再通过这个对象查询的一部分语句片段。

String sql = "select * from users where  username=? and userpwd=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, userpwd);
rs = pstmt.executeQuery();

PrepareStatement跟Statement对比

  PrepareStatement跟Statement的主要区别就是把上面sql语句中的变量抽出来了。这就是我要说的第一大优点,PrepareStatement可以提高代码的可读性。

Statement 可以批量执行多条不一样类型的SQL语句

conn = DbUtils.getConnection();
Statement sts = conn.createStatement();
sql1 = "insert into t_user(userid,username,password)values(seq_t_user.nextval,'a','b')";
sql2 = "update t_user set password='111' where userid=43";
// 添加批处理的sql语句
sts.addBatch(sql1);
sts.addBatch(sql2);
sts.executeBatch();

PreparedStatement:可以批量执行多条相同类型变化参数的SQL语句

conn = DbUtils.getConnection();
sql = "insert into t_user(userid,username,password)values(seq_t_user.nextval,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for(int i = 0 ; i < 10 ; i++){
	ps.setString(1, "a"+i);
	ps.setString(2, "b"+i);
	ps.addBatch();
}
ps.executeBatch();

ParperStatement提高了代码的灵活性和执行效率
  PrepareStatement接口是Statement接口的子接口,他继承了Statement接口的所有功能。它主要是拿来解决我们使用Statement对象多次执行同一个SQL语句的效率问题的。ParperStatement接口的机制是在数据库支持预编译的情况下预先将SQL语句编译,当多次执行这条SQL语句时,可以直接执行编译好的SQL语句,这样就大大提高了程序的灵活性和执行效率。

String sql = "select * from user where username= '"+varname+"' and userpwd='"+varpasswd+"'";
stmt = conn.createStatement();
rs = stmt.executeUpdate(sql);

  这是验证用户名密码的,对吧。但要是我们把’or ‘1’ = 1’当作密码传进去,你猜猜会发生啥。

select * from user where username = 'user' and userpwd = '' or '1' = '1';
String sql = "select * from user where username= '"+varname+"' and userpwd='"+varpasswd+"'";
stmt = conn.createStatement();
rs = stmt.executeUpdate(sql);

  对数据库进行增删改查的过程中的通用的流程:

(1)、创建Connection对象、SQL查询命令字符串;
(2)、对Connection对象传入SQL查询命令,获得PreparedStatement对象;
(3)、对PreparedStatement对象执行executeUpdate()或executeQurey()获得结果;
(4)、先后关闭PreparedStatement对象和Connection对象。

CallableStatement

存储过程:
  是一组为了完成特定功能的SQL 语句,类似一门程序设计语言,也包括了数据类型、流程控制、输入和输出和它自己的函数库(就是一组SQL语句构成的集合)。存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。

 Class.forName(driver_class_name);
 Connection connection = DriverManager.getConnection(url, username, password);
 /**
  * 存储过程语法
  * 带参数:{call 存储过程名称 [参数1,参数2,.......]}
  * 不带参数:{call 存储过程名称}
  */
 String sql = "{call storage_name(?,?,?......)}";
 CallableStatement callableStatement = connection.prepareCall(sql);
 /**
  * 前两个参数是in,后一个参数是out
  * 类似于执行该语句:select name from user where id = x and sex = y
  * in x int,out name varchar(20)
  * 但是此时没有结果集,取查询的数据不能通过getResultSet()获取,而是通过 String name = callableStatement.getString(3); 获取
  */
 callableStatement.setString(1, "aaa");
 callableStatement.setInt(2, 2);
 callableStatement.registerOutParameter(3, java.sql.Types.VARCHAR);
 
 // 返回的是一个boolean值
 boolean execute = callableStatement.execute();
 // 如果一个存储过程中包含多条语句,返回结果集可能有多个,此时需要逐个取出结果
 do {
     ResultSet resultSet = callableStatement.getResultSet();
     while (resultSet.next()) {
         for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
             System.out.print(resultSet.getString(i) + "\t");
         }
         System.out.println();
     }
     System.out.println("=====================================");
     // 如果直接用while循环,则会忽略第一个结果集,故需要采用 do{}while()
 } while (callableStatement.getMoreResults());
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值