200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 【Java学习笔记】55:JDBC-MySQL基本使用 游标控制 CONCUR_UPDATABLE 更新/添加/删除

【Java学习笔记】55:JDBC-MySQL基本使用 游标控制 CONCUR_UPDATABLE 更新/添加/删除

时间:2020-06-10 11:10:26

相关推荐

【Java学习笔记】55:JDBC-MySQL基本使用 游标控制 CONCUR_UPDATABLE 更新/添加/删除

配置了这么久终于可以学习JDBC了,在这之前,给刚刚的表多插入一些表项:

mysql> USE newDB;Database changedmysql> INSERT INTO NewUsr -> (id,name,age) -> VALUES -> (1,'lzh',20), -> (3,'sb',17), -> (2,'奥特曼',9), -> (7,'起诉面包',3);Query OK, 4 rows affected (0.00 sec)Records: 4 Duplicates: 0 Warnings: 0mysql> SELECT * FROM NewUsr;+----+--------------+------+| id | name | age |+----+--------------+------+| 6 | 红色青蛙| NULL || 1 | lzh| 20 || 3 | sb | 17 || 2 | 奥特曼 | 9 || 7 | 起诉面包| 3 |+----+--------------+------+5 rows in set (0.00 sec)

表项在表中逻辑上是没有顺序的,既不能认为按照id的大小,也不能认为是时间先后的顺序(虽然不使用ORDER BY时查询出来就是这个顺序)。

基本流程

画张图记录一下,竖线表示影响的范围:

import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;public class Main {public static void main(String[] args) {try {// 要求JVM查找并加载指定的类Class.forName("com.mysql.jdbc.Driver");// 声明一个sql连接对象java.sql.Connection con = null;// 连接信息字符串,MySQL数据库服务器的默认端口号是3306// jdbc:mysql://ip地址:端口号/要连接的数据库名?其它选项// useSSL参数指明数据通道是否要加密处理// characterEncoding参数指明连接编码,要和数据库编码,数据库表的编码,数据库系统的编码一致String uri = "jdbc:mysql://192.168.0.106:3306/newDB?useSSL=true&characterEncoding=utf8";String user = "root";// 用户名String password = "3838438"; // 密码// 和指定的数据库建立连接(连接信息字符串,用户名,密码)con = DriverManager.getConnection(uri, user, password);// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果java.sql.Statement sql = con.createStatement();// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句// 顺序查询方式// ResultSetd对象一次只能看到一个数据行,用next()方法移动到下一个数据行while (rs.next()) {// 在每个数据行上多次使用getXxx()方法获取这行上每个字段中的数据// 传入的参数可以是int列号,也可以是String列名// 而getXxx()中的Xxx就是获得这一字段值时采取的类型,也即返回的数据类型int id = rs.getInt(1);String name = rs.getString(2);// 实际上不论哪种类型的字段都可以使用getString(列号/列名)int age = rs.getInt(3);System.out.println(id + " " + name + " " + age);}// 最后关闭连接// 注意当Connection对象使用close()方法关闭连接后,ResultSet对象不再可用// 所以如果要使用ResultSet对象就要一直保持连接// 如果要关闭连接后还能使用数据,就要把ResultSet对象里的数据存到别的地方去con.close();} catch (SQLException e) {// SQLException异常可能发生在DriverManager.getConnection()方法获得Connection对象时// 还可能发生在Connection对象调用createStatement()方法创建SQL语句对象时// 还可能发生在SQL语句对象调用executeQuery()方法对数据库进行查询时// 还可能发生在Connection对象调用close()方法关闭连接时e.printStackTrace();} catch (ClassNotFoundException e) {// ClassNotFoundException异常可能发生在lass.forName()时,即找不到要加载的类e.printStackTrace();}}}

输出

6 红色青蛙 01 lzh 203 sb 172 奥特曼 97 起诉面包 3

游标控制

用next()方法让结果集的游标向下一行,如果成功时会返回true,在初始状态,结果集的游标总是在第一行的前面。

如果Connection对象用无参数的createStatement()方法获取SQL语句对象,那么只能进行向下的顺序查询。为它指定特定的参数以控制查询游标可以上下移动:

import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;public class Main {public static void main(String[] args) {try {// 要求JVM查找并加载指定的类Class.forName("com.mysql.jdbc.Driver");// 声明一个sql连接对象java.sql.Connection con = null;// 连接信息字符串,MySQL数据库服务器的默认端口号是3306// jdbc:mysql://ip地址:端口号/要连接的数据库名?其它选项// useSSL参数指明数据通道是否要加密处理// characterEncoding参数指明连接编码,要和数据库编码,数据库表的编码,数据库系统的编码一致String uri = "jdbc:mysql://192.168.0.106:3306/newDB?useSSL=true&characterEncoding=utf8";String user = "root";// 用户名String password = "3838438"; // 密码// 和指定的数据库建立连接(连接信息字符串,用户名,密码)// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果// ResultSet.TYPE_SCROLL_SENSITIVE使结果集可以滚动// ResultSet.CONCUR_READ_ONLY不能用结果集更新数据库中的表java.sql.Statement sql = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句/* 滚动查询方式(即可以控制游标) */rs.next();// 向下移动到第一行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));int lnth = rs.getRow();// 获取当前行号System.out.println("当前行号:" + lnth);rs.last();// 移动到最后一行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));rs.previous();// 向上移动一行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));System.out.println("是否在最后一行之后" + rs.isAfterLast());// 是否在最后一行之后System.out.println("是否在第一行之前" + rs.isBeforeFirst());// 是否在第一行之前rs.absolute(3);// 绝对移动:到第3行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));rs.absolute(-2);// 绝对移动:到倒数第2行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 最后关闭连接// 注意当Connection对象使用close()方法关闭连接后,ResultSet对象不再可用// 所以如果要使用ResultSet对象就要一直保持连接// 如果要关闭连接后还能使用数据,就要把ResultSet对象里的数据存到别的地方去con.close();} catch (SQLException e) {// SQLException异常可能发生在DriverManager.getConnection()方法获得Connection对象时// 还可能发生在Connection对象调用createStatement()方法创建SQL语句对象时// 还可能发生在SQL语句对象调用executeQuery()方法对数据库进行查询时// 还可能发生在Connection对象调用close()方法关闭连接时e.printStackTrace();} catch (ClassNotFoundException e) {// ClassNotFoundException异常可能发生在lass.forName()时,即找不到要加载的类e.printStackTrace();}}}

输出

6 红色青蛙 0当前行号:17 起诉面包 32 奥特曼 9是否在最后一行之后false是否在第一行之前false3 sb 172 奥特曼 9

CONCUR_UPDATABLE用结果集操作数据库表

Connection对象调用createStatement()方法创建SQL语句对象时,传入的第二个参数,取值为ResultSet.CONCUR_READ_ONLY时不能用结果集更新数据库中的表项。教材书这样写感觉很模糊,而且没有具体说明。学习它的对立参数ResultSet.CONCUR_UPDATABLE就能明白什么是”用结果集更新数据库中的表”了。

在该参数下使用ResultSet.TYPE_SCROLL_SENSITIVE参数

Connection对象调用createStatement()方法创建SQL语句对象时,传入的第一个参数可以有多种取值,当取ResultSet.TYPE_SCROLL_SENSITIVE时,不仅表示结果集可滚动,对数据库表的更新会更新ResultSet结果集对象。

当使用CONCUR_UPDATABLE用结果集更新数据库表时,需要先移动到要操作的行,调用ResultSet对象的updateXxx(列号,新值)方法(Xxx是类型),再调用updateRow()方法完成更新:

// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果// ResultSet.TYPE_SCROLL_SENSITIVE使结果集可以滚动,当数据变化时,结果集同步改变// ResultSet.CONCUR_UPDATABLE能用结果集更新数据库中的表java.sql.Statement sql = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句/* 滚动查询方式(即可以控制游标) */rs.absolute(3);// 绝对移动:到第3行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 用ResultSet结果集去更新数据库表项rs.updateInt(1, 11);rs.updateString(2, "皮卡丘");rs.updateInt(3, 6);rs.updateRow();// 切记要做了这一步才能完成更新!// 在ResultSet.TYPE_SCROLL_SENSITIVE参数下,对数据库表项的操作会同时更新结果集System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));

输出

3 sb 1711 皮卡丘 6

这时候数据库表项已经更新了。

如果要取消更新,注意这个取消不是把上面已经更新数据库表项这件事取消,而是把前面的updateXxx(列号,新值)方法们做的更新取消,可以在updateRow()前调用ResultSet对象的cancelRowUpdates()方法取消:

// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果// ResultSet.TYPE_SCROLL_SENSITIVE使结果集可以滚动,当数据变化时,结果集同步改变// ResultSet.CONCUR_UPDATABLE能用结果集更新数据库中的表java.sql.Statement sql = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句/* 滚动查询方式(即可以控制游标) */System.out.println("[更新前]");rs.absolute(3);// 绝对移动:到第3行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 用ResultSet结果集去更新数据库表项rs.updateInt(1, 18);rs.updateString(2, "暗夜猎手");rs.updateInt(3, 9);rs.updateRow();// 尝试更新rs.absolute(4);// 绝对移动:到第4行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 用ResultSet结果集去更新数据库表项rs.updateInt(1, 12);rs.updateString(2, "777");rs.updateInt(3, 19);rs.cancelRowUpdates();// 取消更新rs.updateRow();// 尝试更新rs.absolute(1);// 绝对移动:到第1行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 用ResultSet结果集去更新数据库表项rs.updateInt(1, 15);rs.updateString(2, "SBSB");rs.updateInt(3, 21);rs.updateRow();// 尝试更新// 在ResultSet.TYPE_SCROLL_SENSITIVE参数下,对数据库表项的操作会同时更新结果集System.out.println("[更新后]");rs.absolute(3);// 绝对移动:到第3行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));rs.absolute(4);// 绝对移动:到第4行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));rs.absolute(1);// 绝对移动:到第1行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));

输出

[更新前]13 雷丘 72 奥特曼 96 红色青蛙 0[更新后]18 暗夜猎手 92 奥特曼 915 SBSB 21

从输出可以看出,updateRow()方法和cancelRowUpdates()方法也仅仅是针对当前数据行的。这样的好处在于可以把各个数据行间的移动、更新写在前面,而把这两个方法写在最后,只要用绝对移动到各个数据行,再去抉择是否要对这行应用更新即可了。

在该参数下使用ResultSet.TYPE_SCROLL_INSENSITIVE参数

Connection对象调用createStatement()方法创建SQL语句对象时,传入的第一个参数可以有多种取值,当取ResultSet.TYPE_SCROLL_INSENSITIVE时,表示结果集可滚动,但对数据库表的更新不会更新ResultSet结果集对象。

但是,CONCUR_UPDATABLE选择的方式就是用结果集去更新数据库表项,所以在这种方式下不论用的是ResultSet.TYPE_SCROLL_INSENSITIVE还是ResultSet.TYPE_SCROLL_SENSITIVE,结果集都会改变:

// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果// ResultSet.TYPE_SCROLL_INSENSITIVE使结果集可以滚动,当数据变化时,结果集不改变!// 但是,注意在CONCUR_UPDATABLE参数下的情况!// ResultSet.CONCUR_UPDATABLE能用结果集更新数据库中的表java.sql.Statement sql = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句/* 滚动查询方式(即可以控制游标) */System.out.println("[更新前,结果集对象中的这行]");rs.absolute(4);// 绝对移动:到第4行System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));// 用ResultSet结果集去更新数据库表项rs.updateInt(1, 12);rs.updateString(2, "777");rs.updateInt(3, 19);rs.updateRow();// 更新这行// 在ResultSet.TYPE_SCROLL_INSENSITIVE参数下,对数据库表项的操作不会同时更新结果集// 但是,注意在CONCUR_UPDATABLE参数下的情况!System.out.println("[数据项更新后,当前结果集对象中的这行]");rs.absolute(4);// 绝对移动:到第4行(其实已经在第4行了)System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3));

输出

[更新前,结果集对象中的这行]2 奥特曼 9[数据项更新后,当前结果集对象中的这行]12 777 19

那么如何去看这两个参数的区别之处呢,总不能把SELECT语句前面加上UPDATE语句来看吧,这样得到的已经不是同一个结果集了,我猜想ResultSet.TYPE_SCROLL_INSENSITIVE参数提供的是多线程情形下的对数据库访问结果的保护,以后的学习中再来验证吧。

更新/添加/删除操作

除了可以用结果集去操作数据库表项,还可以直接用SQL语句去做这些操作。但是注意更新、添加、删除操作使用的是SQL语句对象的.executeUpdate()方法且返回的是一个int型的受影响的行数,而不是.executeQuery()方法返回结果集:

// 用Statement声明一个SQL语句对象,用连接对象的createStatement()方法创建之// SQL语句对象用来向数据库发送SQL语句,并返回结果// ResultSet.TYPE_SCROLL_INSENSITIVE使结果集可以滚动,当数据变化时,结果集不改变!// ResultSet.CONCUR_UPDATABLE能用结果集更新数据库中的表java.sql.Statement sql = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象ResultSet rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句System.out.println("[更新,添加,删除之前]");// 顺序查看这张表while (rs.next()) {int id = rs.getInt(1);String name = rs.getString(2);int age = rs.getInt(3);System.out.println(id + " " + name + " " + age);}System.out.println("[更新,添加,删除操作]");int num = sql.executeUpdate("UPDATE NewUsr SET name='刘知昊' WHERE id=12;");// 更新数据库表项System.out.println(num + "行受影响");num = sql.executeUpdate("DELETE FROM NewUsr WHERE name='SBSB';");// 删除数据库表项System.out.println(num + "行受影响");num = sql.executeUpdate("INSERT INTO NewUsr VALUES(22,'啊啊啊',23);");// 添加数据库表项System.out.println(num + "行受影响");// SQL语句对象调用executeQuery()方法对数据库进行查询,返回ResultSet对象rs = sql.executeQuery("SELECT * FROM NewUsr;");// 在这里指定查询语句System.out.println("[更新,添加,删除之后]");// 顺序查看这张表while (rs.next()) {int id = rs.getInt(1);String name = rs.getString(2);int age = rs.getInt(3);System.out.println(id + " " + name + " " + age);}

输出

[更新,添加,删除之前]15 SBSB 211 lzh 暗夜猎手 912 777 197 起诉面包 3[更新,添加,删除操作]1行受影响1行受影响1行受影响[更新,添加,删除之后]22 啊啊啊 231 lzh 暗夜猎手 912 刘知昊 197 起诉面包 3

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。