1. 之前还有一个大问题没有解决:为什么ResultSet时刻都保持着跟Connection的绑定(Connection关闭ResultSet也被关闭)
1) 其实你可能猜到了,ResultSet还有我们之前没有用到的功能,ResultSet肯定是时刻(实时)跟Connection保持着连接的,也许数据库相应数据的改变也能及时地更新ResultSet中相应的内容;
2) 答案是正确的,实际上如果ResultSet的功能全部开启的话不仅会实时保持跟Connection的连接(数据库中数据改变也会自动及时更新ResultSet中的内容),而且对ResultSet中内容的修改也可以反过来更新数据库中的内容!!!
!!也就是说ResultSet其实是一种直接跟数据库交互的通道(注意!是直接交互!),因此这条通道必然会被同不监视、和Connection同生死!!
3) ResultSet可以开启的全部三大功能:
a. 滚动:在JDK1.4之前默认打开的ResultSet默认只能使用next一个方法移动记录指针,这种就是不可滚动的,而可滚动的是指可以使用全部的指针移动方法来定位记录指针(previous、last、afterlast等);
b. 敏感:即底层数据库中相应数据的更新会实时同步到相应的ResultSet,如果没有这项功能则是不敏感的;
c. 并发:并发有两种,一种是只读并发(即ResultSet中的记录只读不能修改,默认),另一种是可更新并发(即ResultSet中的记录可以修改,并且修改后还可以直接更新相应数据库中的记录);
!!如果开启了可更新并发,那么ResultSet即使可更新的;
2. 开启ResultSet的功能:
1) 在使用conn的createStatement、prepareStatment时可以开启ResultSet的功能,毕竟ResultSet是从属于Connection的;
2) 这两个方法的重载版本:
i. PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency);
ii. Statement createStatement(int resultSetType, int resultSetConcurrency);
3) resultSetType用于开启滚动和敏感功能,resultSetConcurrency用于开启并发功能;
4) 这些功能在ResultSet中定义了静态常量:
滚动/敏感:TYPE_FORWARD_ONLY(不可滚动,即什么功能都不开启,JDK1.4之前是默认的)、TYPE_SCROLL_INSENSITIVE(滚动但不敏感,现在默认的)、TYPE_SCROLL_SENSITIVE(滚动且敏感)
并发:CONCUR_READ_ONLY(只读并发,默认的)、CONCUR_UPDATABLE(可更新并发,开启后就可以通过修改ResultSet中的内容来达到修改数据库中数据的目的了);
!!注意:TYPE_SCROLL_INSENTIVE和TYPE_SCROLL_SENSITIVE需要数据库驱动的支持,对于大多数数据库这两种开关作用上没有区别(MySQL)就是,默认是敏感的!
5) 使用可更新功能的前提!!!
i. 必须查询得到的所有数据都来自同一张表;
ii. 所选数据集中必须包含主键列;
!!两者缺一不可,这是JDBC的实现上的局限性,如果有任意一个规则不符合就会拒绝修改直接抛出异常;
3. 如何通过ResultSet更新数据库中的数据?
1) 当然首先必须开启并发更新的功能;
2) 更新分两步,第一步是修改ResultSet中的值(只是该对象中的值),然后再提交更新(将ResultSet中数据的修改以SQL语句形式提交给数据库实现真正的更新);
3) 首先必须要把记录指针定位到要更新的记录位置处;
4) 接着调用ResultSet的updateXxx方法修改ResultSet对象中值:两个版本,用列名和索引(从1计)来定位要修改的列
i. void ResultSet.updateXxx(int columnIndex, Xxx x);
ii. void ResultSet.updateXxx(String columnLabel, Xxx x);
5) 最后将修改提交实现真正的更新,调用updateRow方法即可(即将修改后的行更新到真实数据库的表中):void ResultSet.updateRow();
!!实际上它会把这种修改转化成SQL语句提交给数据库执行(以为数据库只认识SQL查询);
4. 示例:可滚动、可更新的结果集
public class Test {
private String driver;
private String url;
private String user;
private String pass;
public void init() throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("mysql.ini"));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
pass = props.getProperty("pass");
try (
Connection conn = DriverManager.getConnection(url, user, pass);
PreparedStatement pstmt = conn.prepareStatement("select * from student_table",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); // 可滚动可更新
ResultSet rs = pstmt.executeQuery();
) {
rs.afterLast(); // 可滚动
int i = 0;
while (rs.previous()) { // 按照逆序修改
rs.updateString(2, "Peter" + i++);
rs.updateRow();
}
}
}
public static void main(String[] args) throws Exception {
new Test().init();
}
}
!!运行后可以看到数据可表中的名字都变成了Peter + i了,并且i是逆序的;