例外処理の注意点
OceanBaseでは、例外処理プログラムは以下の状況でのみ使用することを推奨します:
例外が発生する可能性があり、それを処理したい場合。
例えば、最後のSELECT INTOステートメントが空行を返す可能性があり、その結果、OceanBaseが事前定義された例外
NO_DATA_FOUNDを報告することを予想している場合です。サブルーチンやSTORED PROCEDUREブロックを使用してこの例外(これはエラーではありません)を処理し、プログラムを継続実行させたい場合です。例:create or replace procedure select_dept( num_deptno in number,--inモード変数を定義します。部門番号の入力が必要です。 var_dname out dept.dname%type,--outモード変数を定義します。部門名を格納し出力できます。 var_loc out dept.loc%type) is begin select dname,loc into var_dname,var_loc from dept where deptno = num_deptno;--特定の部門番号の部門情報を検索します。 exception when no_data_found then --selectステートメントでレコードが返されない場合 dbms_output.put_line('該当する部門番号は存在しません');--情報を出力します。 end select_dept;リソースを放棄または閉じる必要がある場合。例:
... file := UTL_FILE.OPEN ... BEGIN statement statement]... EXCEPTION WHEN OTHERS THEN UTL_FILE.FCLOSE(file); -- その後、ファイルを閉じたい場合。 RAISE; -- 例外を継続して報告します。 END; UTL_FILE.FCLOSE(file); ...サブルーチンコードのトップレベルで、エラーログを記録する必要がある場合。例:
BEGIN proc(...); -- 他のサブルーチンを呼び出します。 EXCEPTION WHEN OTHERS THEN log_error_using_autonomous_transaction(...); -- 自律トランザクションを使用してログを記録します。 RAISE; -- 例外を継続してスローします。 END; /
例外処理の例
OceanBaseは2種類の例外処理メカニズムを提供しています。1つはSQL文を作成する際に、PL内のexceptionを用いて例外をキャッチする方法です。もう1つはアプリケーション層のコード開発時に、使用するドライバーに応じた対応する例外処理方式を利用する方法です。
PL例外処理
PL例外エラーには、システム内部例外、定義済み例外、ユーザー定義例外の3種類があります。これら3種類について、それぞれ例を示します。
システム内部例外。
例:名前付けキャプチャによりシステム内部例外をキャッチする。
obclient>CREATE TABLE dept( dept_id NUMBER(10,0), dname VARCHAR(15), loc VARCHAR(20), CONSTRAINT pk_dept PRIMARY KEY(dept_id) ); Query OK, 0 rows affected (0.07 sec) obclient>INSERT INTO dept VALUES (100,'ACCOUNTING','Los Angeles'),(110,'OPERATIONS','CHICAGO'), (111,'SALES','NEW YORK'); obclient>DECLARE DUPLICATED_DEPT_ID EXCEPTION; PRAGMA EXCEPTION_INIT(DUPLICATED_DEPT_ID, -5024); BEGIN UPDATE dept SET dept_id=110 where dept_id=100; EXCEPTION WHEN DUPLICATED_DEPT_ID THEN DBMS_OUTPUT.PUT_LINE('Duplicated Department ID!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END; / Query OK, 0 rows affected (0.03 sec) Duplicated department id!定義済み例外。
obclient>CREATE TABLE employees( empno NUMBER(4,0), empname VARCHAR(10), job VARCHAR(10), deptno NUMBER(2,0), salary NUMBER(7,2), CONSTRAINT PK_emp PRIMARY KEY (empno) ); Query OK, 0 rows affected (0.07 sec) obclient>INSERT INTO employees VALUES (200,'Jennifer','AD_ASST',1,15000), (202,'Pat','MK_REP',3,12000),(113,'Karen','PU_CLERK', 4,null),(201,'Michael','MK_MAN',3,9000); Query OK, 4 rows affected (0.06 sec) Records: 4 Duplicates: 0 Warnings: 0 obclient>DECLARE v_empid employees.empno%TYPE; v_sal employees.salary%TYPE; BEGIN v_empid := 100; SELECT salary INTO v_sal FROM employees WHERE empno=v_empid; IF v_sal<=10000 THEN UPDATE employees SET salary=salary+100 WHERE empno=v_empid; DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' updated'); ELSE DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' ignored'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN -- 従業員番号 v_empid が存在しない場合、NO_DATA_FOUND 例外を発生させる DBMS_OUTPUT.PUT_LINE('Employee id '||v_empid||' not found'); WHEN TOO_MANY_ROWS THEN -- 従業員番号 v_empid が複数存在する場合、TOO_MANY_ROWS 例外を発生させる DBMS_OUTPUT.PUT_LINE('Duplicated id: '||v_empid); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END; / Query OK, 0 rows affected (0.06 sec) Employee id 100 not foundユーザー定義例外は、ユーザー定義例外とユーザー定義エラーコードに分類されます。
ユーザー定義例外。
obclient>DECLARE v_empid employees.empno%TYPE; v_sal employees.salary%TYPE; -- 1.例外名 SALARY_NOT_SET を定義する SALARY_NOT_SET EXCEPTION; BEGIN v_empid := 113; SELECT salary INTO v_sal FROM employees WHERE empno=v_empid; IF v_sal<=10000 THEN UPDATE employees SET salary=salary+100 WHERE empno=v_empid; DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' updated'); ELSIF v_sal is NULL THEN -- 2. v_sal がNULLの場合、この例外を発生させる RAISE SALARY_NOT_SET; ELSE DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' ignored'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee id '||v_empid||' not found'); -- 3. SALARY_NOT_SET 例外を処理する WHEN SALARY_NOT_SET THEN DBMS_OUTPUT.PUT_LINE('Salary not set: '||v_empid); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END; / Query OK, 0 rows affected (0.07 sec) Salary not set: 113ユーザー定義エラーコード。
obclient>DECLARE v_empid employees.empno%TYPE; v_sal employees.salary%TYPE; BEGIN v_empid := 103; SELECT salary INTO v_sal FROM employees WHERE empno=v_empid; IF v_sal is NULL THEN -- エラー20999をスローする RAISE_APPLICATION_ERROR(-20999, 'The salary of employee is not found'); ELSIF v_sal<=1500 THEN UPDATE employees SET salary=salary+100 WHERE empno=v_empid; DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' updated'); ELSE DBMS_OUTPUT.PUT_LINE('Employee '||v_empid||' ignored'); END IF; END; / OBE-20999: The salary of employee is not found
PL例外処理の詳細については、公式サイトの「PLリファレンス」にある「PL例外処理」の章を参照してください。
OceanBase JDBCドライバーの使用例
基盤となるドライバーのエラータイプに直接依存するSQLステートメントについては、ORMフレームワークで標準的な JDBCTemplate / SqlMapClientTemplate(SqlMapClientDaoSupport) などの標準テンプレートクラスを統一的に使用することを推奨します。これらの実装は、基盤となるエラーをSpringフレームワークの標準例外タイプに変換します。標準テンプレートクラスを使用している場合、基盤となるドライバータイプ com.alipay.oceanbase.obproxy.mysql.exceptions.jdbc4.MySQLIntegrityConstraintViolationException を直接認識する必要はありません。以下の例を参照してください。
try {
// 業務ロジック
} catch (Exception e) {
if (e instanceof DataIntegrityViolationException
&& ((DataIntegrityViolationException) e).contains(DuplicateKeyException.class)) {
// 一意性制約違反エラー処理
}
}
また、他のドライバーの例外 com.alipay.oceanbase.obproxy.mysql.exceptions.* も確認する必要があります。使用している場合も、対応するSpring標準例外に調整する必要があります。
説明
MySQLモードでは、MySQLデータベースのネイティブJDBCドライバーの使用を推奨します。
ここでは、OceanBase JDBCドライバーを例に説明します。その他のさまざまなドライバーの例外処理方法については、対応するドライバーの公式Webサイトで学習してください。