使用存储过程处理SQLEXCEPTION时没有触发锁等待直接跳过

【 使用环境 】生产环境
【 OB or 其他组件 】ob Java
【 使用版本 】5.7.25-OceanBase_CE-v4.2.1.2
【问题描述】使用存储过程处理SQLEXCEPTION时没有触发锁等待直接跳过
【复现路径】存储过程中有更新ieai_id表操作,我写了段程序先锁住这个表,随后执行存储过程,存储过程没有锁等待,而是直接返回结果。
【附件及日志】存储过程内容:
CREATE DEFINER = root@% PROCEDURE dgns1015.PROC_GET_NEXT_PK(IN AV_CLASSNAME VARCHAR(100), OUT AD_NEXT_ID NUMERIC(19,0))
MODIFIES SQL DATA
BEGIN
DECLARE LN_PK NUMERIC(19,0);
DECLARE LN_USED_PK NUMERIC(19,0);
DECLARE LV_COLNAME VARCHAR(60);
DECLARE LV_COLTYPE VARCHAR(40);
DECLARE LV_USER VARCHAR(40);
DECLARE LI_COUNT INTEGER;
DECLARE LS_SQL VARCHAR(500);
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE RETSQLCODE INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND
SET RETSQLCODE = SQLCODE;
UPDATE IEAI_ID
SET IVALUE = IVALUE + 1
WHERE ICLASSNAME = AV_CLASSNAME;

	SET LI_COUNT = ROW_COUNT();

-- insert into ieai_ymx values('update ieai_id',LI_COUNT);

	IF	LI_COUNT = 0	THEN
		INSERT	INTO	IEAI_ID
			(
				ICLASSNAME,
				IVALUE
			)
		VALUES	(
				AV_CLASSNAME,
				1
			);
			COMMIT;
		-- insert into ieai_ymx values('insert ieai_id',LI_COUNT);
	END	IF;

	SELECT	IVALUE
	INTO	LN_PK
	FROM	IEAI_ID
	WHERE	ICLASSNAME = AV_CLASSNAME;

-- insert into ieai_ymx values('SELECT ieai_id',LN_PK);

	IF	RETSQLCODE = 0 OR RETSQLCODE = 100	THEN
		COMMIT	WORK;
		SET	AD_NEXT_ID = LN_PK;
	ELSE
		ROLLBACK WORK;
		SET	AD_NEXT_ID = NULL;
	END	IF;
	COMMIT;
END

代码内容:
public static void insert(){

    // 组织数据插入语句
    long start = System.currentTimeMillis();
    Connection conn = null;
    PreparedStatement itemStat = null;
    long id = 894245;
    try
    {
        BasicDataSource jdbcDataSource = new BasicDataSource();

        jdbcDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        jdbcDataSource.setUrl("jdbc:mysql://192.168.4.239:2881/dgns1015?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&autoReconnect=true&failOverReadOnly=false");
        jdbcDataSource.setUsername("root");
        jdbcDataSource.setPassword("Ideal.123"); 

        jdbcDataSource.setInitialSize(200);
        jdbcDataSource.setMaxActive(1800);
        jdbcDataSource.setMaxIdle(100);
        jdbcDataSource.setMinIdle(50);

// jdbcDataSource.setMaxWait(30000);
conn = jdbcDataSource.getConnection();
conn.setAutoCommit(false);

// for (int i = 0; i < 10000; i++)
// {
// id ++;
itemStat = conn.prepareStatement(
“update ieai_id set ivalue = 333370 where ICLASSNAME = ‘com.ideal.ieai.server.repository.activity.RepActivityRuntime’”);
// itemStat.setLong(1, id);
// itemStat.setLong(2, 233);
// itemStat.setLong(3, 527478);
// itemStat.setLong(4, 521851);
// itemStat.setLong(5, 1727982);
// itemStat.setLong(6, 492922);
// itemStat.setLong(7, 1);
// itemStat.setLong(8, 1);
// itemStat.setLong(9, 1);
// itemStat.setLong(10, 0);
itemStat.executeUpdate();
Thread.sleep(3600000);
conn.commit();
// }
// conn.rollback();
} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally
{
try
{
if (null != itemStat)
{
itemStat.close();
itemStat = null;
}
if (null != conn && !conn.isClosed())
{
conn.close();
}
conn = null;
} catch (SQLException e)
{
e.printStackTrace();
}
}

}

执行存储过程代码:
– 定义输入参数和输出参数
SET @input_param = ‘com.ideal.ieai.server.repository.activity.RepActivityRuntime’;
SET @output_param = 0;

– 调用存储过程
CALL PROC_GET_NEXT_PK(@input_param, @output_param);

– 查看输出参数的值
SELECT @output_param;

我先执行代码,更新ieai_id表但不提交,睡眠一小时,随后手动执行存储过程,存储过程中的UPDATE IEAI_ID SET IVALUE = IVALUE + 1 WHERE ICLASSNAME = AV_CLASSNAME;并没有进行锁等待,而是直接返回了结果,请问各位大神,ob为什么会出现这种情况

2 个赞

存储过程内容没粘全,详情情况以下:
CREATE DEFINER = root@% PROCEDURE dgns1015.PROC_GET_NEXT_PK(IN AV_CLASSNAME VARCHAR(100), OUT AD_NEXT_ID NUMERIC(19,0))
MODIFIES SQL DATA
BEGIN
DECLARE LN_PK NUMERIC(19,0);
DECLARE LN_USED_PK NUMERIC(19,0);
DECLARE LV_COLNAME VARCHAR(60);
DECLARE LV_COLTYPE VARCHAR(40);
DECLARE LV_USER VARCHAR(40);
DECLARE LI_COUNT INTEGER;
DECLARE LS_SQL VARCHAR(500);
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE RETSQLCODE INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND
SET RETSQLCODE = SQLCODE;
UPDATE IEAI_ID
SET IVALUE = IVALUE + 1
WHERE ICLASSNAME = AV_CLASSNAME;

	SET LI_COUNT = ROW_COUNT();

-- insert into ieai_ymx values('update ieai_id',LI_COUNT);

	IF	LI_COUNT = 0	THEN
		INSERT	INTO	IEAI_ID
			(
				ICLASSNAME,
				IVALUE
			)
		VALUES	(
				AV_CLASSNAME,
				1
			);
			COMMIT;
		-- insert into ieai_ymx values('insert ieai_id',LI_COUNT);
	END	IF;

	SELECT	IVALUE
	INTO	LN_PK
	FROM	IEAI_ID
	WHERE	ICLASSNAME = AV_CLASSNAME;

-- insert into ieai_ymx values('SELECT ieai_id',LN_PK);

	IF	RETSQLCODE = 0 OR RETSQLCODE = 100	THEN
		COMMIT	WORK;
		SET	AD_NEXT_ID = LN_PK;
	ELSE
		ROLLBACK WORK;
		SET	AD_NEXT_ID = NULL;
	END	IF;
	COMMIT;
END
2 个赞

你能把存储过程 完整的保存在一个文本里 发一下 具体看看

2 个赞

pk.txt (1.0 KB)

我不是很理解 为什么更新ieai_id表操作会锁住这个表?

不是锁表 是我在并发操作同一行记录的时候不应该会锁等待吗 但是存储过程里并没有触发锁等待 直接向下执行了

我测试了一下把存储过程中处理异常DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND的这个去掉 确实就会等 但是看起来好像是无限等 没有抛出锁超时报错

1、 SQLEXCEPTION条件,存储程序在引发条件的语句处终止,就像存在EXIT 处理程序一样
2、 对于SQLWARNING条件,程序将继续执行,就像有一个 CONTINUE处理
3、对于未找到的异常,如果条件正常执行,则操作为CONTINUE处理
应该是和处理异常有关 我记是处理异常是这样的

我的问题是如果不同事务同时更新同一条记录不应该是会产生锁吗 我这存储过程执行update并没有锁 而且也没更新成功 :joy: 很奇怪啊

应该是和处理异常有关系 我记得mysql 存储过程不是原子性 obmysql应该是保持一致