IDEA中对某远程MYSQL进行入表操作时,利用select结果记录集进行rs.insertRow();却报错:java.sql.SQLException: Not on insert row.

原study表中已经有两条记录,希望新增一条记记录。

study表字段分别是id,username,password,name,sex,age,level,mobile。其中id是主键(自动增值)其余均可空值,因此本次测试只对username,password,name,sex,age字段进行新增记录测试。

源码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class RegisterAccount {
    public static void main(String[] args) {
        // 创建一个 BufferedReader 对象,它将从 System.in 读取数据
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        try {
            // 提示用户输入信息
            System.out.println("请输入您要注册的用户名:");
            // 从标准输入读取一行文本
            String input_username = reader.readLine();

            // 提示用户输入信息
            System.out.println("请输入您的密码:");
            // 从标准输入读取一行文本
            String input_password = reader.readLine();

            // 提示用户输入信息
            System.out.println("请输入您的姓名:");
            // 从标准输入读取一行文本
            String input_name = reader.readLine();

            // 提示用户输入信息
            System.out.println("请输入您的性别:");
            // 从标准输入读取一行文本
            String input_sex = reader.readLine();

            // 提示用户输入信息
            System.out.println("请输入您的年龄:");
            // 从标准输入读取一行文本
            int input_age = Integer.parseInt(reader.readLine());

            // 调用入表操作
            DatabaseInsert(input_username, input_password, input_name, input_sex, input_age);
            // 输出用户输入的信息
            System.out.println("你的用户名是:" + input_username);
            System.out.println("你的密码是:" + input_password);
            System.out.println("你的姓名是:" + input_name);
            System.out.println("你的性别是:" + input_sex);
            System.out.println("你的年龄是:" + input_age);
        } catch (IOException e) {
            // 处理可能出现的异常
            e.printStackTrace();
        }
    }

    public static void DatabaseInsert(String tmp_username, String tmp_password, String tmp_name, String tmp_sex, int tmp_age) {
        String url = "jdbc:mysql://localhost:3306/study";
        String user = "username";            //连接数据库的用户名
        String password = "password";        //连接数据库的用户名对应密码
        try {
            // 1. 加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 打开连接
            Connection conn = DriverManager.getConnection(url, user, password);

           // 3. 创建PrepareStatement
            String query = "SELECT username,password,name,sex,age FROM study where id is null LIMIT 1 FOR UPDATE";

            PreparedStatement tmpstmt = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

            // 4. 执行语句
            ResultSet rs = tmpstmt.executeQuery(query);

            rs.insertRow();
            rs.updateString("username", tmp_username);
            rs.updateString("password", tmp_password);
            rs.updateString("name", tmp_name);
            rs.updateString("sex", tmp_sex);
            rs.updateInt("age", tmp_age);
            rs.updateRow();
            rs.moveToInsertRow();
            rs.refreshRow();
            rs.moveToCurrentRow();
            // 获取结果集中的数据
            System.out.println("userName: " + tmp_username);
            System.out.println("Password: " + tmp_password);
            System.out.println("Name: " + tmp_name);
            System.out.println("Sex: " + tmp_sex);
            System.out.println("Age: " + tmp_age);
            // ... 更多的列
            System.out.println();
            // 6. 关闭资源
            tmpstmt.close();
            conn.close();

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

}

报错信息如下:

java.sql.SQLException: Not on insert row.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:68)
    at com.mysql.cj.jdbc.result.UpdatableResultSet.insertRow(UpdatableResultSet.java:733)
    at RegisterAccount.DatabaseInsert(RegisterAccount.java:75)
    at RegisterAccount.main(RegisterAccount.java:43)
 

排查及解决方案路径:

1、查看数据库的用户权限是否具有insert和update权限。在mysql中使用以下语句,

 SELECT Insert_priv  FROM mysql.user  WHERE User = '你的用户名'@'主机' ;

结果截图如下:

发现该用户并没Insert_priv权限,需要执行以下语句修改其具有Insert_priv的权限。

GRANT INSERT ON study.study TO '你的用户名'@'主机';

如下图所示:显示赋予权限成功。

然后回到IDEA中执行原程序,发现仍未解决问题。

2、重新排查源程序,特别是链接数据库后的query查询字串

        发现query查询字串语句也没有问题。

3、时间关系,换个实现思路。

        此时回归到条条大路通罗马,换个思路,编程的目的在于实现功能,我的功能只是希望在表中增加一条记录,无论是否对查询结果记录集进行游标操作来用InsertRow来新增一条记录,还是不用查询 结果的记录集,而是直接对表进行insert into操作来解决,都是一样的功能,因此,直接改代码为Insert into来解决。对核心部分的函数进行全部修改如下(方式一):

 public static void DatabaseInsert(String tmp_username, String tmp_password, String tmp_name, String tmp_sex, int tmp_age) {
        String url = "jdbc:mysql://localhost:3306/study";
        String user = "username";        //连接数据库的用户名
        String password = "password";    //连接数据库的密码
        try {
            // 1. 加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 打开连接
            Connection conn = DriverManager.getConnection(url, user, password);
  
//          String query = "SELECT username,password,name,sex,age FROM study where id is null LIMIT 1 FOR UPDATE";
            // 改用insert into实现对表新增记录
            String query="insert into study (username,password,name,sex,age) value (?,?,?,?,?)";
            
            // 3. 创建Statement
            // 4. 执行语句
            PreparedStatement tmpstmt = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            // 插入一条新记录
                tmpstmt.setString(1, tmp_username);
                tmpstmt.setString(2, tmp_password);
                tmpstmt.setString(3, tmp_name);
                tmpstmt.setString(4, tmp_sex);
                tmpstmt.setInt(5, tmp_age);
                tmpstmt.executeUpdate();
                // 获取结果集中的数据
                System.out.println("userName: " + tmp_username);
                System.out.println("Password: " + tmp_password);
                System.out.println("Name: " + tmp_name);
                System.out.println("Sex: " + tmp_sex);
                System.out.println("Age: " + tmp_age);
                // ... 更多的列
                System.out.println();
                // 6. 关闭资源

                tmpstmt.close();
                conn.close();


//以上方式为直接用insert处理

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

编译执行之,完美解决问题。

在navicat查看远程mysql,查询全部发现user3记录,已经成功新增如下:

4、总结经验:所有编程原则,回归本质,“大道至简”。在时间紧迫关系下,用最直接简单的方式实现功能是最要紧的,难题的排查可以放在未来进行补充,希望这种思路能给一些朋友得到启发。

5、事后分析:

解决思路:

  1. 执行查询语句,该查询语句可能会返回一个空的结果集。
  2. 对这个空的结果集使用 rs.updateRow 来插入新行,这里存在问题,因为 rs.updateRow 是用于更新当前结果集中的行,而不是插入新行。
  3. 对于插入新行,应该使用 PreparedStatement 的 executeUpdate 方法。

错误分析:

  • rs.updateRow 用于更新从数据库中检索出来的结果集中的现有行的数据,而不是插入新行。当结果集为空时,没有行可供更新,并且使用 rs.updateRow 进行插入操作是错误的用法。因此只能使用之前的insert into 语句及executeUpdate方法。
  • 因过往多年.net+mssql运行环境经验,现这java+mysqll方式有所区别,需要注意。

改进源码的另一种方式,如下: 

 将原来DatabaseInsert函数进行少许变化,如下(方式二):

public static void DatabaseInsert(String tmp_username, String tmp_password, String tmp_name, String tmp_sex, int tmp_age) {
        String url = "jdbc:mysql://localhost:3306/study";
        String user = "username";            //连接数据库的用户名
        String password = "password";        //连接数据库的用户名对应密码
        try {
            // 1. 加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 打开连接
            String query = "SELECT username,password,name,sex,age FROM study where id is not null LIMIT 1 FOR UPDATE";
            String insert = "INSERT INTO study (username,password,name,sex,age) VALUES (?,?,?,?,?)";

            Connection conn = DriverManager.getConnection(url, user, password);
            // 3. 创建PrepareStatement
            PreparedStatement tmpstmt = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            PreparedStatement tmpinsert = conn.prepareStatement(insert, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            // 4. 执行语句
            ResultSet rs = tmpstmt.executeQuery(query);
            if(rs.next()) {
                tmpinsert.setString(1,tmp_username);
                tmpinsert.setString(2,tmp_password);
                tmpinsert.setString(3,tmp_name);
                tmpinsert.setString(4,tmp_sex);
                tmpinsert.setInt(5,tmp_age);
                tmpinsert.executeUpdate();
                System.out.println("生成记录成功");
            }
            else
            {
                System.out.println("生成记录失败");
            }

            // 获取结果集中的数据
            System.out.println("userName: " + tmp_username);
            System.out.println("Password: " + tmp_password);
            System.out.println("Name: " + tmp_name);
            System.out.println("Sex: " + tmp_sex);
            System.out.println("Age: " + tmp_age);
            // ... 更多的列
            System.out.println();
            // 6. 关闭资源
            tmpstmt.close();
            tmpinsert.close();
            conn.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

其中重点改进地方是在,方式二与方式一中的区别在于增加一个对表状态的判断,空表给不给新增行而已。根本也是利用Insert into语句实现新增记录:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值