传智博客---JDBC之使用 PreparedStatement

/**
* PreparedStatement:
*/
@Test
public void testPreparedStatement(){
//先声明要用到的对象:
Connection connection = null;
PreparedStatement preparedStatement = null;
//写一个大的try……catch……finally:
try {
//获得连接:
connection = JdbcTools.getConnection();
//准备一个SQL语句:
String sql = "INSERT INTO customers (name,email,birthday)"
             +"VALUES (?,?,?)";
//创建PreparedStatement对象:
preparedStatement = connection.prepareStatement(sql);
//然后我需要调用setXxx(int index,Object value)方法进行赋值吧:
preparedStatement.setString(1, "情剑莫邪_2");
preparedStatement.setString(2, "[email protected]");
preparedStatement.setDate(3,new java.sql.Date(new java.util.Date().getTime()));
 /**
   * 这里传一个new Date() 会出一点问题,这里用的是sql.Date,那sql.Date如何来创建呢?
   * new java.sql.Date(new java.util.Date().getTime())
   */
//执行:
preparedStatement.executeUpdate(); //这个时候SQL不再需要传入;
} catch (Exception e) {
            e.printStackTrace();
}finally{
/**
* 为什么可以传preparedStatement,因为preparedStatement是不是Statement的子接口啊;
*/
JdbcTools.release(preparedStatement, connection);
}
}

----------------------------------------------------------------------------------------------------------------------------------------------------
JdbcTools工具类:
package com.zhou.jdbc;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
/**
* 版本1:后面这些方法还可以升级,比方说我们不能每次操作都获取一个数据库连接,比方说后面会学数据库连接池;
*
* 操作JDBC的工具类:其中封装了一些工具方法:
*
* 1.获取连接的方法;
*
* @author Administrator
*
*/
public class JdbcTools {
/**
* 1.获取连接的方法:这个方法在前面已经写过了,只是这个是工具方法,需要加上static: ---通过读取配置文件从数据库服务器获取一个连接;
*
* 用DriverManager来把之前那个通用的方法写一遍:
*
* @throws Exception
*/
public static Connection getConnection() throws Exception {
// 1.准备连接数据库的四个字符串:
// 1).创建Properties对象:
Properties properties = new Properties();
// 2).获取jdbc.properties对应的输入流:
InputStream in = JdbcTools.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 3).加载2) 对应的输入流:
properties.load(in);
// 4).具体决定user、password、jdbcUrl、driverClass四个字符串:
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String jdbcUrl = properties.getProperty("jdbcUrl");
String driverClass = properties.getProperty("dirver");
// 2.加载数据库驱动程序(实际上这一步应该叫:注册驱动,对应的Driver实现类中有注册驱动的静态代码块):
Class.forName(driverClass);
// 3.获取数据库的连接:
// Connection connection = DriverManager.getConnection(jdbcUrl, user,
// password);
// return connection;
return DriverManager.getConnection(jdbcUrl, user, password);
}
/**
* 2.关闭数据库资源的方法: 它关闭一个Statement,再关闭一个Connection:
*/
public static void release(Statement statement, Connection connection) {
if (statement != null) {
try {
statement.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 3.关闭数据库资源的方法: 它关闭三个:ResultSet、Statement、Connection:
*/
public static void release_2(ResultSet resultSet ,Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (Exception e3) {
e3.printStackTrace();
}
}
}
/**
* 4.执行SQL的方法:
*    SQL:INSERT、UPDATE、DELETE,而不包含SELECT;
*/
public static void update(String sql){
Connection connection = null;
Statement statement = null;
try {
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally { // 关闭连接:这里不再写那个嵌套的try……catch……finally了
release(statement, connection);
}
}
/**
*
* 执行SQL语句,使用PreparedStatement:
*
* 写一个使用PreparedStatement的update方法:
* 这个方法我除了传一个sql以外,我还需要传入什么?我还需要传入
* 这个SQL语句中一个一个占位符的值吧,传多少个呢,各个sql语句
* 都可能传的值的个数不一样吧;
*   所以说第二个参数是个什么为好啊?是一个可变参数为好;
*   刚好和上面的那个public static void update(String sql)可以构成方法的重载;
*
* @param sql
* @param args:填写sql占位符的可变参数;
*/
public static void update(String sql,Object ... args){
/**
* 这个方法体跟上面那个update方法体过程差不多,
*/
//声明Connection和PreparedStatement:
Connection connection = null;
PreparedStatement preparedStatement = null;
//写一个大的try……catch……finally:
try {
//获得连接:
connection = JdbcTools.getConnection();
//创建PreparedStatement:
preparedStatement = connection.prepareStatement(sql);
//这一步比较关键:我是不是要从里面传参数啊,Object ... args这个我也不知道吧,这是不是一个数组啊,我使用一个for循环:
for(int i = 0;i < args.length; i++){
preparedStatement.setObject(i+1, args[i]); //所有的索引是不是从1开始啊,而数组的索引是不是从0开始啊;
}
//执行SQL语句:
preparedStatement.executeUpdate(); //注意,SQL语句已经在创建PreparedStatement的时候已经传进去了,这里不要再传SQL语句了;
} catch (Exception e) {
            e.printStackTrace();
}finally{
JdbcTools.release_2(null, preparedStatement, connection);
}
}
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------
用PreparedStatement来改写用Statement的方式拼写SQL语句麻烦、容易出错的缺点:
 /**
* 写完public void addNewStudent_2(Student student)之后呢,我们可以来写这样一个测试的方法
*/
@Test
public void testAddNewStudent() {
// 首先获取一个Student对象,从控制台的输入中获取:
Student student = getStudentFromConsole();
// 然后调用addNewStudent(Student student)方法添加一个学生信息:
//addNewStudent(student);
addNewStudent_2(student);
}
/**
* 创建用从控制台获取Student对象的方法:getStudentFromConsole()
*
* @return
*/
private Student getStudentFromConsole() {
// 创建一个Scanner类的对象;
Scanner scanner = new Scanner(System.in);
// 然后呢?创建一个Student类的对象:
Student student = new Student();
// 然后怎么整啊?一个一个输入啊:
System.out.print("flowId:");
student.setFlowId(scanner.nextInt());
System.out.print("type:");
student.setType(scanner.nextInt());
System.out.print("idCard:");
student.setIdCard(scanner.next());
System.out.print("examCard:");
student.setExamCard(scanner.next());
System.out.print("studentName:");
student.setStudentName(scanner.next());
System.out.print("Location:");
student.setLocation(scanner.next());
System.out.print("Grade:");
student.setGrade(scanner.nextInt());
// 把对象进行返回;
return student;
}
/**
* 第一个我们叫什么呢?叫addNewStudent 这样就写成了一个方法,我要添加一个学生进来,我们当然可以硬写,怎么写呢?
* 就是真的从控制台逐步读入那些信息,然后把这些信息插入到数据库里面;
*/
public void addNewStudent(Student student) {
/**
* 这个方法基本在写流程的时候已经写过了:
*/
// 1.准备一条SQL语句:
// String sql = “INSERT INTO examstudent”+" VALUES(1,4,’’,’’,’’,’’,90)”;
String sql = "INSERT INTO examstudent" + " VALUES("
+ student.getFlowId() + "," + student.getType() + ",'"
+ student.getIdCard() + "','" + student.getExamCard() + "','"
+ student.getStudentName() + "','" + student.getLocation()
+ "'," + student.getGrade() + ")";
// 我打印一下这个SQL语句:
System.out.println(sql);
// 2.调用JdbcTools工具类的update(sql)方法执行插入操作;
JdbcTools.update(sql);
}
/**
* 用PreparedStatement来改写:public void addNewStudent(Student student)这个方法:
* 改写这个方法的话是因为我在JdbcTools工具类里面有update()方法吧,这个update()方法用的是谁啊?用的是不是
* Statement啊,这个时候我需要把这个JdbcTools工具类里面的这个update()方法进行升级,升级成使用
* PreparedStatement,因为你再用这个Statement写的update()方法肯定不行了啊,
*
*/
public void addNewStudent_2(Student student){
//我需要来预写一个SQL语句:
String sql = "INSERT INTO examstudent (flowid,type,idcard,"
     + "examcard,studentname,location,grade)" +
             "VALUES(?,?,?,?,?,?,?)"; //把列名写上后面就会清楚了写什么:
//然后我要去调JdbcTools的update方法,这个时候我只传一个SQL不够吧?我还需要传入这一个一个占位符的值;
   JdbcTools.update(sql, student.getFlowId(),student.getType(),
        student.getIdCard(),student.getExamCard(),
        student.getStudentName(),student.getLocation(),
        student.getGrade());
  /*
                  * 这个时候我不用拼这个字符串了,但是我传参是必须的,写的时候的确是比前一个方便了;
                  * 拼串确实比较辛苦,但是我写这样一个带问号占位符的sql语句的话缺容易得多,然后把
                  * 这个值一个一个的传了;
                  */
}

总结:
使用PreparedStatement

 1). 为什么要使用PreparedStatement呢?有几点:

.使用Statement需要拼写SQL语句,很辛苦,而且容易出错;

. 可以有效的禁止 SQL 注入 l; 就是说我们在写代码的时候,我们的这个 sql 语句都是拼写起来的,我就利用这个 SQL 语句是拼起来的,我往里面在插值的时候我可以达到我的一些目的,这就是叫 SQL 注入:
. 可以最大可能的提高性能;因为特别是我们在批量插入的时候,如果批量插入要使用 Statement 的话,每次都需要传一个 SQL ,而使用 PreparedStatement 的话,那个 SQL 已经编译好了,那这个时候的话,我直接往里面放值就可以,这个时候这个效率就会提高;

    2).使用PreparedStatement:是Statement的子接口,这意味着PreparedStatement可以用到Statement的所有方法;可以传入带占位符的SQL语句,并且提供了补充占位符变量的方法;

.创建PreparedStatement

如何去创建呢?当然是使用Connection

              PreparedStatement ps =connection.preparedStatement(sql);

不过,在我创建这个 PreparedStatement 的同时,我必须传入这个 sql ;必须这么写;

.调用PreparedStatementsetXxx(intindex,Object value);方法来设置占位符的值;

看看这个 setXxx(intindex,Object value) 方法中的 setString(intindex,Object value) 方法:

.执行SQL语句:executeQuery()executeUpdate(),注意:执行时不再需要传入SQL语句;

因为现在的话呢,我是一个 PreparedStatement ,我这块是不是已经放 SQL 语句了啊,我已经放 SQL 了,然后第②步我已经为每个占位符已经赋值了,然后我执行的时候,还需要传入 SQL 吗?不需要了吧,我们写 Statement 的时候是不是需要穿入一个 SQL 啊,但是在这个时候不需要穿 SQL 了,比方说方法:是执行或者说是查询都可以,但我不需要传 SQL 了:


本文出自 “IT技术JAVA” 博客,转载请与作者联系!

你可能感兴趣的:(使用)