JDBC中使用PreparedStatement执行SQL语句并管理结果集

基本说明

1、使用PreparedStatement在对反复操作多条结构相似的SQL语句时效率更高,并且可以使用参数替代变量,可以防止SQL注入。

2、PreparedStatement也提供了 execute()  、 executeUpdate()  、 executeQuery()  三个方法来执行crud操作,这三个方法无需传递参数,因为PreparedStatsments已经存储了预编译的SQL语句。

3、推荐使用PreparedStatement。


代码示例,简单PreparedStatement操作工具类。本例使用连接SqlServer 08 R2为例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PreparedStatementUtils {
	private String url;
	private String user;
	private String password;
	

	public PreparedStatementUtils(String urlString,String userString,String pasString){
		this.url = urlString;
		this.user = userString;
		this.password = pasString;
	}
	
	static{
		try {
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/***
	 * 对输入SQL进行查询
	 * @param sql
	 * @throws SQLException
	 */
	public void queryResult(String sql)throws SQLException{
		try(
				//获取数据库连接
				Connection connection = DriverManager.getConnection(this.url, this.user, this.password);
				//使用conntection来创建一个PreparedStatement对象
				PreparedStatement preparedStatement =connection.prepareStatement(sql);
				)
		{
			ResultSet rSet=  preparedStatement.executeQuery();
			while(rSet.next())
			{
				System.out.println("Id=" + rSet.getLong(1) + ";ProductName=" + rSet.getString(2));
			}
		}
	}
	
	/***
	 * 对输入SQL进行新增、更新操作
	 * @param sql
	 * @return
	 * @throws SQLException
	 */
	public int updateResult(String sql)throws SQLException{
		try(
				Connection connection = DriverManager.getConnection(this.url, this.user, this.password);
				PreparedStatement preparedStatement = connection.prepareStatement(sql);				
				)
		{
			return preparedStatement.executeUpdate();
		}
	}
	
	/**
	 * 使用PreparedStatement进行批量
	 * @throws SQLException
	 */
	public void updateResult()throws SQLException{
		long stat = System.currentTimeMillis();
		try(
				Connection connection = DriverManager.getConnection(this.url, this.user, this.password);
				PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO dbo.Product( ProductName ,IsEffective ,Remark ,UnitId)VALUES  (?,'Y',?,1)");
				)
		{
			for (int i = 0; i < 10; i++) {
				preparedStatement.setString(1, "测试名字" + i);
				preparedStatement.setString(2, "测试备注" + i);
				preparedStatement.executeUpdate();
			}
		}
		long end = System.currentTimeMillis();
		System.out.println("使用PreparedStatement进行费时:" +  (end-stat));
	}
}

 


可滚动可更新的结果集 

1、ResultSet定位记录指针的方法由absolute()、previous()、last()、afterLast()等方法。可以对结果集进行滚动操作。

2、以默认的方式打开的结构集ResultSet是不能更新的。如果希望更新,可以在创建Statement或者PreparedStatement时传入额外的参数。

 

resultSetType:控制ResultSet的类型,该参数有如下三个值:

1、ResultSet.TYPE_FORWARD_ONLY:该常量控制记录指针只能向前移动。

2、ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制记录指针可以自由移动(可滚动结果集),但是底层数据的改变不会影响ResultSet里的内容。(sqlserver 可能不支持此操作,会报错:不支持此游标类型/并发组合)

3、ResultSet.TYPE_SCROLL_SENSITIVE:常量控制记录指针可以自由移动(可滚动结果集),但是底层数据的改变会影响ResultSet里的内容。

 

resultSetConcurrency:控制ResultSet的并发类型,该参数可以接受如下两个值:

1、ResultSet.CONCUR_UPDATABLE:该常量指示ResultSet是可更新的并发模式。

      这里有两个条件:1、所有数据来自同个表。2、选出的数据必须包含主键列

2、ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)。

 

代码举例说明,在上述代码中再增加一个方法:

	/**
	 * 查询并修改指定结果集数据
	 * @param sql
	 * @throws SQLException
	 */
	public void queryAndUpdata(String sql)throws SQLException{
		try(
				Connection connection = DriverManager.getConnection(this.url, this.user, this.password);
				PreparedStatement preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
				ResultSet rSet = preparedStatement.executeQuery();
				)
		{			
			rSet.last();//移动到最后一行
			int rowCount = rSet.getRow();//获得最后一行的行号
			for (int i = rowCount; i > 0; i--) {
				rSet.absolute(i);//移动指针到指定行
				System.out.println("Id=" + rSet.getLong(1) + ";ProductName=" + rSet.getString(2));
				rSet.updateString(2, rSet.getString(2) + "X");//修改查询结果第二列的值
				rSet.updateRow();//提交修改
			}
		}
	}

 


使用ResultSetMetaData分析结果集 

如果程序不知道ResultSet里面有哪些数据列,以及每个数据列的数据类型,那么可以通过ResultSetMetaData来获取关于ResultSet里的描述信息。

ResultSet里包含了一个getMetaData()方法,该方法返回该ResultSet对应的ResultSetMetaData对象。通过ResultSetMetaData对象里的方法可以获取信息。常用的方法由如下三个:

1、int getColumnCount():返回该ResultSet的列的数量。

2、String getColumnName(int column):返回指定索引的列名。

3、int getColumnType(int column):返回指定索引的列类型。

 

代码举例说明,在上述代码中再增加一个方法:

	/***
	 * 查询显示结果列
	 * @param sql
	 * @throws SQLException
	 */
	public void queryAndCheck(String sql)throws SQLException{
		try(
				Connection connection = DriverManager.getConnection(this.url, this.user, this.password);
				PreparedStatement preparedStatement = connection.prepareStatement(sql);
				ResultSet resultSet = preparedStatement.executeQuery();
				)
		{
			ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
			int colCount = resultSetMetaData.getColumnCount();
			for (int i = 1; i <= colCount; i++) {
				System.out.println("第" + i + "列列名是" + resultSetMetaData.getColumnName(i) + ";类型是" + resultSetMetaData.getColumnType(i));
			}
		}
	}

 

你可能感兴趣的:(Java)