個人電腦操做系統版本爲Win7旗艦版(ServicePack1),Oracle版本爲Oracle11gjava
程序使用的jar包有:mybatis-3.2.2.jar、ojdbc14-10.2.0.2.0.jarsql
本例中使用的配置文件mybatis-config.xml,能夠參見個人另外一篇Blog《一個簡單的MyBatis鏈接Oracle數據庫的例子》(http://my.oschina.net/Tsybius2014/blog/626206)數據庫
先說下本文中描述的場景。apache
現有一些產品,每一個產品都有一些相關聯的崗位,這些崗位可能由不一樣的人擔任。人員信息表(person_info)表中記錄了每一個人的代碼(person_code)和名稱(person_name),人員任職表(time_on_duty)記錄了每一個產品的產品代碼(item_code)、崗位類型(duty_type)、相關人(person_code&person_name)、在崗狀況(is_on_duty),對於已離職的人,還須要記錄離職的日期和時間。產品相關人員的變更、增減是從另外一個系統推送來的,每次推送的數據,只有產品代碼(item_code)、崗位1任職人、崗位2任職人、崗位3任職人……等等。瀏覽器
建表語句(init_data.sql)以下所示,time_on_duty的主鍵(id)使用序列(seq_time_on_duty)來賦值:session
-- 人員信息表 create TABLE PERSON_INFO ( id number(12,0) PRIMARY KEY, person_code varchar2(20), person_name varchar2(50) ); -- 插入人員信息基礎數據 insert into person_info (id, person_code, person_name) values (1, '10001', 'Tsybius'); insert into person_info (id, person_code, person_name) values (2, '10002', 'Galatea'); insert into person_info (id, person_code, person_name) values (3, '10003', 'Gaius'); insert into person_info (id, person_code, person_name) values (4, '10004', 'Quintus'); insert into person_info (id, person_code, person_name) values (5, '10005', 'Atia'); commit; -- 人員任職表 create TABLE TIME_ON_DUTY ( id number(12,0) PRIMARY KEY, item_code varchar2(20), person_code varchar2(20), person_name varchar2(50), duty_type varchar2(20), is_on_duty varchar2(5), exit_date number(10,0) DEFAULT 0, exit_time number(10,0) DEFAULT 0, input_date number(10,0) DEFAULT to_number(to_char(sysdate,'yyyymmdd')), input_time number(10,0) DEFAULT to_number(to_char(sysdate,'hh24miss')), update_date number(10,0) DEFAULT to_number(to_char(sysdate,'yyyymmdd')), update_time number(10,0) DEFAULT to_number(to_char(sysdate,'hh24miss')) ); -- 建立人員信息表序列 CREATE SEQUENCE SEQ_TIME_ON_DUTY INCREMENT BY 1 START WITH 1 MAXVALUE 999999999999999999999999999 CYCLE CACHE 20;
創建存儲過程,對於每個崗位的輪替,僞代碼以下:mybatis
if (對應崗位人員 != null) { bool 是否已更新 = false for (人員 : 當前產品同一崗位中全部的歷史任職人員) { if (老數據當前已離職 && 老數據的人 == 新數據的人) { 老人員從新上崗 是否已更新 = true } else if (老數據當前有效&&老數據的人 != 新數據的人) { 老人下崗,更新離職時間 } else if (老數據當前有效&&老數據的人 == 新數據的人) { 更新下更新日期 是否已更新 = true } } if (!是否已更新) { 新人上崗 是否已更新 = true } } else { 當前產品對應崗位全部的歷史任職人員,如還在職,所有標爲離職,同時更新離職時間 }
寫出的Oracle存儲過程(refresh_new_data.sql)代碼以下:app
-- 創建存儲過程 - 更新項目相關人 CREATE OR REPLACE PROCEDURE refresh_new_data(p_item_code IN VARCHAR2, p_duty_1 IN VARCHAR2, --p_duty_2 IN VARCHAR2, --p_duty_3 IN VARCHAR2, -- 若有更多相關人在此繼續加入 p_error_no OUT NUMBER, -- 錯誤號 p_error_info OUT VARCHAR2, -- 錯誤提示 p_error_id OUT NUMBER, -- 錯誤序號 p_error_sysinfo OUT VARCHAR2 -- 系統錯誤信息 ) AS c_duty_type_1 CONSTANT VARCHAR2(2) := '1'; --c_duty_type_2 CONSTANT VARCHAR2(2) := '2'; --c_duty_type_3 CONSTANT VARCHAR2(2) := '3'; -- 若有更多相關人在此繼續加入 c_exit CONSTANT VARCHAR2(3) := '0'; c_on_duty CONSTANT VARCHAR2(3) := '1'; v_duty_1_is_refresh VARCHAR2(5); --v_duty_2_is_refresh VARCHAR2(5); --v_duty_3_is_refresh VARCHAR2(5); -- 若有更多相關人在此繼續加入 v_id_tmp time_on_duty.id % TYPE; v_item_code_tmp time_on_duty.item_code % TYPE; v_person_code_tmp time_on_duty.person_code % TYPE; v_duty_type_tmp time_on_duty.duty_type % TYPE; v_is_on_duty_tmp time_on_duty.is_on_duty % TYPE; CURSOR c_duty_1 IS SELECT id, item_code, person_code, duty_type, is_on_duty FROM time_on_duty WHERE item_code = p_item_code AND duty_type = c_duty_type_1; --CURSOR c_duty_2 IS -- SELECT id, item_code, person_code, duty_type, is_on_duty -- FROM time_on_duty -- WHERE item_code = p_item_code AND -- duty_type = c_duty_type_2; --CURSOR c_duty_3 IS -- SELECT id, item_code, person_code, duty_type, is_on_duty -- FROM time_on_duty -- WHERE item_code = p_item_code AND -- duty_type = c_duty_type_3; -- 若有更多相關人在此繼續加入 -- 當前日期&當前時間 v_curr_date NUMBER(10, 0) := TO_NUMBER(TO_CHAR(SYSDATE, 'yyyymmdd')); v_curr_time NUMBER(10, 0) := TO_NUMBER(TO_CHAR(SYSDATE, 'hh24miss')); BEGIN dbms_output.put_line('----------- PROCUDURE START -----------'); -- ITEM CODE 不能爲空 IF p_item_code IS NULL THEN BEGIN dbms_output.put_line('ITEM CODE IS NULL'); p_error_no := 101; p_error_info := 'ITEM CODE IS NULL'; p_error_id := SQLCODE; p_error_sysinfo := 'CUSTOM DEFECT TYPE'; RETURN; END; END IF; -- 相關人更新 START -- -- -- 更新 duty_1 -- IF p_duty_1 IS NOT NULL THEN BEGIN -- 若是傳入的新人不爲空,須要作進一步判斷 dbms_output.put_line('CHECK DUTY_1'); v_duty_1_is_refresh := 'no'; -- 使用遊標遍歷相同產品相同職務的人 OPEN c_duty_1; LOOP FETCH c_duty_1 INTO v_id_tmp, v_item_code_tmp, v_person_code_tmp, v_duty_type_tmp, v_is_on_duty_tmp; EXIT WHEN c_duty_1 % NOTFOUND; dbms_output.put_line('==ITEM FOUND=='); dbms_output.put_line('id : ' || v_id_tmp); dbms_output.put_line('item_code : ' || v_item_code_tmp); dbms_output.put_line('person_code : ' || v_person_code_tmp); dbms_output.put_line('duty_type : ' || v_duty_type_tmp); dbms_output.put_line('is_on_duty : ' || v_is_on_duty_tmp); IF v_is_on_duty_tmp = c_exit AND p_duty_1 = v_person_code_tmp THEN -- 老人當前失效且老人與新人是同一人的狀況:從新啓用老人 UPDATE time_on_duty SET is_on_duty = c_duty_type_1, update_date = v_curr_date, update_time = v_curr_time WHERE id = v_id_tmp; v_duty_1_is_refresh := 'yes'; ELSIF v_is_on_duty_tmp = c_on_duty AND p_duty_1 <> v_person_code_tmp THEN -- 老人當前有效且老人與新人不是同一人的狀況:老人離職 UPDATE time_on_duty SET is_on_duty = c_exit, exit_date = v_curr_date, exit_time = v_curr_time, update_date = v_curr_date, update_time = v_curr_time WHERE id = v_id_tmp; ELSIF v_is_on_duty_tmp = c_exit AND p_duty_1 = v_person_code_tmp THEN -- 老人當前有效且老人與新人是同一人的狀況:更新下更新時間字段便可 UPDATE time_on_duty SET update_date = v_curr_date, update_time = v_curr_time WHERE id = v_id_tmp; v_duty_1_is_refresh := 'yes'; END IF; END LOOP; CLOSE c_duty_1; -- 遊標使用結束,關閉遊標 -- 如新人之前未擔任過本產品的對應職務則插入一條新記錄 IF v_duty_1_is_refresh = 'no' THEN INSERT INTO time_on_duty (id, item_code, person_code, person_name, duty_type, is_on_duty, exit_date, exit_time, input_date, input_time, update_date, update_time) SELECT seq_time_on_duty.NEXTVAL, a.item_code, a.person_code, b.person_name, a.duty_type, a.is_on_duty, a.exit_date, a.exit_time, a.input_date, a.input_time, a.update_date, a.update_time FROM (SELECT p_item_code AS item_code, p_duty_1 AS person_code, c_duty_type_1 AS duty_type, c_on_duty AS is_on_duty, 0 AS exit_date, 0 AS exit_time, v_curr_date AS input_date, v_curr_time AS input_time, v_curr_date AS update_date, v_curr_time AS update_time FROM dual) a LEFT JOIN (SELECT person_code, person_name FROM person_info) b ON a.person_code = b.person_code; v_duty_1_is_refresh := 'yes'; END IF; END; ELSE -- 若是傳入的新人爲空,則認爲老人離職,無人補缺 UPDATE time_on_duty SET is_on_duty = c_exit, exit_date = v_curr_date, exit_time = v_curr_time, update_date = v_curr_date, update_time = v_curr_time WHERE is_on_duty = c_on_duty AND item_code = p_item_code AND duty_type = c_duty_type_1; END IF; -- 若有更多相關人在此繼續加入 -- 相關人更新 FINISH -- dbms_output.put_line('----------- PROCUDURE END -----------'); p_error_no := 0; p_error_info := 'EXECUTE SUCCESS'; p_error_id := SQLCODE; p_error_sysinfo := SQLERRM; EXCEPTION WHEN OTHERS THEN p_error_no := 999; p_error_info := '存儲過程執行錯誤'; p_error_id := SQLCODE; p_error_sysinfo := SQLERRM; END refresh_new_data; /
在PL/SQL中使用命令窗口創建存儲過程時,若是存儲過程寫得有問題,就會報錯:函數
這種狀況下,能夠經過下面的方式查看存在哪裏:測試
一、找到PL/SQL中的「瀏覽器」窗口,在存儲過程當中找到咱們新創建的存儲過程(上面標記了紅色的×,說明腳本執行出錯了),在右鍵菜單中找到「查看」
二、在「查看」界面中,出錯的行會用黃色標記,下面有詳細的報錯信息
準備工做完成後,創建文件MyBatisTestMapper.java:
import java.util.Map; public interface MyBatisTestMapper { void refreshNewData(Map<String, Object> paramMap); }
創建對應的Mapper文件MyBatisTestMapper.xml,調用存儲過程:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="MyBatisTestMapper"> <parameterMap id="paramMap4NewData" type="java.util.Map"> <parameter property="itemCode" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> <parameter property="duty1" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> <!-- 若有更多相關人在此繼續加入 --> <!-- <parameter property="duty2" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> --> <!-- <parameter property="duty3" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> --> <parameter property="errorNo" javaType="java.lang.Long" jdbcType="NUMERIC" mode="OUT"/> <parameter property="errorInfo" javaType="java.lang.String" jdbcType="VARCHAR" mode="OUT"/> <parameter property="errorId" javaType="java.lang.Long" jdbcType="NUMERIC" mode="OUT"/> <parameter property="errorSysInfo" javaType="java.lang.String" jdbcType="VARCHAR" mode="OUT"/> </parameterMap> <select id="refreshNewData" statementType="CALLABLE" parameterMap="paramMap4NewData"> { call refresh_new_data(?, ?, ?, ?, ?, ?) } </select> </mapper>
main函數的實現以下:
import java.io.InputStream; import java.text.MessageFormat; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * MyBatis使用測試 * @author Tsybius2014 * @date 2016年3月26日 * @time 上午12:29:10 * @remark * */ public class MyBatisTest { public static void main(String[] args) { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); try { MyBatisTestMapper mapper = session.getMapper(MyBatisTestMapper.class); Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("itemCode", "item00X"); paramMap.put("duty1", "10001"); paramMap.put("duty2", "10001"); paramMap.put("duty3", "10002"); mapper.refreshNewData(paramMap); long errorNo = (Long) paramMap.get("errorNo"); String errorInfo = (String) paramMap.get("errorInfo"); long errorId = (Long) paramMap.get("errorId"); String errorSysInfo = (String) paramMap.get("errorSysInfo"); System.out.println(errorNo); System.out.println(errorInfo); System.out.println(errorId); System.out.println(errorSysInfo); } finally { session.commit(); session.close(); } } catch (Exception ex) { ex.printStackTrace(); } } }
輸出結果以下,存儲過程執行成功:
0 EXECUTE SUCCESS 0 ORA-0000: normal, successful completion
END