SE高階(14):JDBC—②增刪改查操作、ResultSet的運用

JDBC執行SQL語句的兩種方式:Statement和PreParedStatement,它們用於發送SQL語句給數據庫執行。在開發過程中,通常會把增刪改查語句封裝在DAO層(數據庫訪問層)中,接下來的使用案例會以Dao層封裝JDBC操作的形式來演示Stament和PreparedStatement。

用於測試的表,可根據個人需求更改
create table t_user(
	u_id int identity(1,1) not null,
	u_name varchar(16) not null,
	u_psw varchar(16) not null,
	u_age int not null,
	u_sex varchar(2) not null,
	primary key(u_id),
)
//用戶類,與測試表進行對應
public class User {
	private String name;
	private String psw;
	private int age;
	private String sex;
	
	public User(String name, String psw, int age, String sex) {
		this.name = name;
		this.psw = psw;
		this.age = age;
		this.sex = sex;
	}
      //省略getter 和 setter
}


Statement案例代碼

executeUpdate()執行插入語句演示

	public int insert(User u) {
		Connection con  = JdbcUtils.getConnection();
		Statement stmt = null;
		int count = 0; //影響行數
		String sql = "insert into t_user values('" +u.getName() +"','" +u.getPsw()+"',"+ u.getAge()+",'"+ u.getSex()+"');";
		System.out.println("插入的sql語句:  " + sql);
		try {
			stmt = con.createStatement();
			 count = stmt.executeUpdate(sql);
			 stmt.close();
			 con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return count;
	}

executeQuery()執行查詢語句演示

//根據姓名查詢
	public void select(User u) {
		Connection con  = JdbcUtils.getConnection();
		Statement stmt = null;
		ResultSet rs = null;
		String sql = "select * from t_user where u_name ='" + u.getName() +"';";
		System.out.println("執行的sql語句:  " + sql);
		try {
			stmt = con.createStatement();
			rs = stmt.executeQuery(sql);
			while(rs.next()) {
				System.out.print(rs.getString("u_name") +"\t"+ rs.getString("u_psw"));
				System.out.println("\t"+ rs.getString("u_age") +"\t"+ rs.getString("u_sex"));
			}
			stmt.close();
			con.close();
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

execute()執行任意語句演示

	public void delete(User u) {
		Connection con  = JdbcUtils.getConnection();
		Statement stmt = null;
		boolean flag = false;
		String sql = "delete from t_user where u_name = '"+ u.getName()+"';";
		System.out.println("執行的刪除語句:  " + sql);
		try {
			stmt = con.createStatement();
			flag = stmt.execute(sql);
			if(flag) {//true,則返回結果集
				ResultSet rs = stmt.getResultSet();
				while(rs.next()) {
					System.out.println("說明結果集有值");
			}		
			}else {//false,返回更新次數(影響行數)
				int num = stmt.getUpdateCount();
				System.out.println("更新次數:" + num);
			}			
			
			stmt.close();
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

  • 使用說明:execute()可以執行任意SQL語句,根據返回值得到不同的結果,如果返回true,則是結果集;返回false,則執行的是DDL語句,返回更新次數。
  • 使用execute()方法之後,應馬上使用getResultSet()或者getUpdateCount()來獲取execute()返回的結果。
  • 相較於executeQuery()和executeUpdate(),execute()一般很少用到,瞭解該用法即可。



PreparedStatement案例代碼

/**
 * 提取出連接數據庫方法和關閉連接對象的方法,類似Hibernate.
 * 讓每一個Dao方法只專門執行SQL語句.
 * 執行SQL語句改用PreparedStatement來執行.
 */
public class UserDao2 {
	private Connection conn = null;
	private PreparedStatement psmt = null;
	private ResultSet rs = null;

	public int insert(User u) {
		String sql = "insert into t_user values(?, ?, ?, ?)";//帶佔位符的sql語句
		int result = 0;//影響行數
		try {
			psmt = conn.prepareStatement(sql);//預編譯SQL
			//設置參數
			psmt.setString(1, u.getName());
			psmt.setString(2, u.getPsw());
			psmt.setInt(3, u.getAge());
			psmt.setString(4, u.getSex());
			System.out.println("執行的預編譯語句:  " + sql);
			result = psmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}		
		return result;
	}
	
	//根據姓名查詢
	public void select(User u) {
		String sql = "select * from t_user where u_name = ?";
		try {
			psmt = conn.prepareStatement(sql);
			psmt.setString(1, u.getName());
			rs = psmt.executeQuery();//執行查詢語句
			while(rs.next()) {
				System.out.print(rs.getString("u_name") +"\t"+ rs.getString("u_psw"));
				System.out.println("\t"+ rs.getString("u_age") +"\t"+ rs.getString("u_sex"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	//根據id刪除對應列
	public int delete(int id) {
		String sql = "delete from t_user where u_id = ?";
		int result = 0;
		try {
			psmt = conn.prepareStatement(sql);
			psmt.setInt(1, id);
			result = psmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return result;
	}
	//開啓連接
	public void begin() {
		conn = JdbcUtils.getConnection();//獲得連接對象
	}
	//關閉連接
	public void close() {
		if(rs != null)
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		if(psmt != null)
			try {
				psmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		if(conn != null)
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
	}
}

Statement和PreparedStatement的對比

  • Statement執行的SQL語句採用拼接字符串形式,極容易寫錯寫漏,而且拼接代碼不容易閱讀。最重要一點就是Statement容易被SQL注入。
  • PreparedStatement採用預編譯sql語句,通過爲每一個佔位符?來設置參數,代碼簡潔明瞭,方便閱讀和修改。
  • PreparedStatement執行多條語句時效率高,並且可以有效防止SQL注入。所以推薦使用預編譯語句。


ResultSet使用詳解

案例一(不可回滾結果集)

public class ResultSetTest {
	private static Connection conn = null;
	private static PreparedStatement psmt = null;
	private static ResultSet rs = null;
	static {
		conn = JdbcUtils.getConnection();
	}
	public static void main(String[] args) throws SQLException {
		String sql = "select * from t_user";
		//常規的預編譯對象
		psmt = conn.prepareStatement(sql);
		rs = psmt.executeQuery();
		System.out.println("+-----+--------+-----+---+");
		while(rs.next()) {
			System.out.print(rs.getString("u_name")+"\t"+rs.getString("u_psw")+"\t");
			System.out.print(rs.getString("u_age")+"\t"+rs.getString("u_sex"));
			System.out.println("\t遊標指向行數:"+rs.getRow());	
		}
		rs.beforeFirst();//移動光標引發異常
數據庫數據請自行插入,或者用上面的Dao層方法來完成都均可。輸出結果如下:


  • 案例一代碼分析:ResultSet有一個類似於數據庫的遊標指向結果集中的每一行,默認從1開始,而且不支持回滾,默認只能迭代下去。所以當使用移動遊標的方法時會引發異常。在下面的案例中,將會改成支持回滾的結果集。

案例二(可回滾的結果集)

public static void main(String[] args) throws SQLException {
		String sql = "select * from t_user";
		//									結果集可回滾						可更新的結果集併發模式
		psmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
		rs = psmt.executeQuery();
		System.out.println("+-----+--------+-----+---+");
		while(rs.next()) {
			System.out.print(rs.getString("u_name")+"\t"+rs.getString("u_psw")+"\t");
			System.out.print(rs.getString("u_age")+"\t"+rs.getString("u_sex"));
			System.out.println("\t遊標指向行數:"+rs.getRow());
			rs.afterLast();//移動遊標到最後一行之後
			//下一個循環next()無法移動遊標到下一行,所以只輸出張三的數據。
		}
		System.out.println("+-----+--------+-----+---+");
		while(rs.previous()) {//讓遊標向上移動一行。因爲此時遊標在最後一行之後,所以結果是倒序輸出
			System.out.print(rs.getString("u_name")+"\t"+rs.getString("u_psw")+"\t");
			System.out.println(rs.getString("u_age")+"\t"+rs.getString("u_sex"));
		}
		/*+-----+--------+-----+---+
		張三	123456	15	男	遊標指向行數:1
		+-----+--------+-----+---+
		清風	343454	35	男
		阿水	115286	19	女
		一號	123456	5	男
		小六	115286	19	男
		小二	123456	25	男*/
	} 
除了上面代碼中使用的afterLast()和previous()方法來移動遊標,還有以下方法:
		rs.first();//移動遊標到第一行
		System.out.println(rs.isFirst());//判斷遊標是否位於ResultSet對象第一行
		rs.last();//移動遊標到最後一行
		System.out.println(rs.isLast());//判斷遊標是否位於ResultSet對象最後一行
		//絕對定位到指定行,如果超出結果集行數,則操作無效,獲取的行數爲0
		rs.absolute(9);//超出結果集行數時,使用previous()會自動找到上一行
		System.out.println(rs.getRow());//0
		//......不再詳述別的移動遊標方法,請自行查看JDK文檔,或單獨測試。

案例二(ResultSet中執行刪改操作)


	/** 對結果集執行刪除操作 */
		String sql = "select * from t_user";
		//									結果集可回滾						可更新的結果集併發模式
		psmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
		rs = psmt.executeQuery();
		System.out.println("+-----+--------+-----+---+");
		while(rs.next()) {
			System.out.print(rs.getString("u_name")+"\t"+rs.getString("u_psw")+"\t");
			System.out.print(rs.getString("u_age")+"\t"+rs.getString("u_sex"));
			System.out.println("\t遊標指向行數:"+rs.getRow());
		}
		rs.absolute(4);//定位到第4行
		System.out.println(rs.getRow());
		rs.deleteRow();//刪除當前遊標指向的行,即第4行
		//...請自行進行迭代操作,會發現剛纔的4行的數據已被刪除,這裏不再演示。
	/** 對結果集中游標指向的行執行更新操作 */
		rs.absolute(2);//定位到2行
		System.out.println(rs.getRow());
		rs.updateObject("u_name", "小二更新");//更新指定列名的數據
		rs.updateRow();//更新到底層數據
		//...省略輸出的結果
  • 使用說明:ResultSet更新列的數據有很多方法,例如updateXxx(),如果知道該列是什麼類型就可以指定對應的數據類型,但也可以使用updateString()和updateObject()來更新列,最後還需要使用updateRow()方法更新底層數據庫。 





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章