jdbc中的Statement和PreparedStatement接口对象

1、Statement
该对象用于执行静态的 SQL 语句,并且返回执行结果
通过调用 Connection 对象的 createStatement 方法创建该对象
Statement 接口中定义了下列方法用于执行 SQL 语句
查询:ResultSet excuteQuery(String sql)——返回查询结果的封装对象ResultSet.

    ResultSet对象:
    通过调用 Statement 对象的 excuteQuery() 方法创建该对象
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现,其中维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行

修改、删除、增加:int excuteUpdate(String sql)——返回影响的数据表记录数.

示例代码:
@Override
	public void add(Student student) {
		// 1. 获取连接
		Connection connection = DBUtil.getConnection();
		Statement statement = null;
		try {

			//>2.获取执行语句的对象——静态的sql语句
			statement = connection.createStatement();
			StringBuilder sql = new StringBuilder(
					"insert into student  values(null,'");
			sql.append(student.getName()).append("','");
			sql.append(student.getSex()).append("',");
			sql.append(student.getAge()).append(",'");
			sql.append(dateFormat.format(student.getBirthday())).append("')");

			System.out.println(sql);

			// 3.执行静态sql
			statement.executeUpdate(sql.toString());
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtil.close(connection, statement, null);
		}

	}


2、PreparedStatement
public interface PreparedStatemen textends Statement表示预编译的 SQL 语句的对象,即实现了动态的SQL。

SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

    可以通过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXXX() 方法来设置这些参数. setXXX() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值,注意用setXXX方式设置时,需要与数据库中的字段类型对应,例如mysql中字段为varchar,就需要使用setString方法,如果为Date类型,就需要使用setDate方法来设置具体sql的参数.

注:用于设置 IN 参数值的设置方法(setShort、setString 等等)必须指定与输入参数的已定义 SQL 类型兼容的类型。例如,如果 IN 参数具有 SQL 类型 INTEGER,那么应该使用 setInt 方法。

如果需要任意参数类型转换,使用 setObject 方法时应该将目标 SQL 类型作为其参数。

代码示例:


@Override
	public void add(Student stu) {
		// 连接数据库
		Connection connection = DbUtils.getConnection();

		PreparedStatement preparedStatement = null;
		String sql = "INSERT INTO student VALUES (null,?,?,?,?)";
		try {
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, stu.getName());
			preparedStatement.setString(2, stu.getSex());
			preparedStatement.setInt(3, stu.getAge());

			// 第二参数为java.sql.Date类型,为java.util.Date的子类,需要处理
			preparedStatement.setDate(4, new Date(stu.getBirthday().getTime()));

			preparedStatement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			DbUtils.close(connection, preparedStatement);
		}
	}


两者的区别:
1、代码的可读性和可维护性.
    PreparedStatement 能最大可能提高性能:
    DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次. 
2、PreparedStatement能保证安全性:statement中,我们需要对静态sql语句进行拼接,可能用户输入的内容参与了拼接,容易出现安全性问题.
例如:
@Test
	public void testLoginByStatement() {
		// >>1. 接受客户端在登录页面上输入的用户名和密码
		String username = "zhangsan"; // request.getParameter('username')
		String password = "zhangsan1111' or 1=1 or ''=' "; // request.getParameter('password')  //如果or 1=1 or ''=' "为用户输入的内容的话,会影响到整个sql语句的执行结果.

		Connection connection = DBUtil.getConnection();
		ResultSet resultSet = null;
		Statement statement = null;
		try {
			statement = connection.createStatement();
			// >>2. 根据用户输入的用户名和密码 到用户表中找有同时存在的记录
			String sql = "select * from userinfo where username='" + username
					+ "' and password='" + password + "'";
			System.out.println(sql);

			resultSet = statement.executeQuery(sql);
			// >>3, 如果根据用户和密码通过执行sql查询出来有结果的话,说明 该用户和密码在数据库中存在, 登录成功
			if (resultSet.next()) {
				System.out.println("登录成功");
				// 把数据库中的对应的用户数据查询出来封装到user对象中.. 然后把user放在sessoin中

			} else {
				System.out.println("登录失败");
			}

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtil.close(connection, statement, resultSet);
		}

	}


而PreparedStatement不会存在这样的安全性问题,利用?通配符来预编译sql语句,程序员只需要动态设置sql语句中的?通配符内容,保证了安全性.
测试代码:
@Test
	public void testLoginByPreparedStatement() {
		// >>1. 接受客户端在登录页面上输入的用户名和密码
		String username = "zhangsan"; // request.getParameter('username')
		String password = "zhangsan"; // request.getParameter('password')

		Connection connection = DBUtil.getConnection();

		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			String sql = "select * from userinfo where username=? and password=?";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, username);
			preparedStatement.setString(2, password);
			resultSet = preparedStatement.executeQuery();

			if (resultSet.next()) {
				System.out.println("登录成功");
			} else {
				System.out.println("登录失败");
			}

		} catch (SQLException e) {
			e.printStackTrace();
		}

	}



总结:在实际应用中,我们通常需要使用PreparedStatement来保证程序的安全、高效.

猜你喜欢

转载自dendy.iteye.com/blog/1676198