mybatis oracle:批量操做(增刪改查)

此文主要是講mybatis在鏈接oracle數據庫時的一些批量操做,請各位對號入座java

(最後回來補充一下,全部都是在Spring+MVC的框架下實現的)sql

不廢話,上代碼:數據庫

一、批量插入(網上不少,是針對MySQL的,被坑慘!oracle mybatis裏面只能用如下這種配置)數組

(1)DAO:mybatis

int autoFullPass(@Param("listAutoData")List<SatisfactionSurvey> listAutoData, @Param("evaluate")String evaluate);

XML:oracle

<insert id="autoFullPass" parameterType="java.util.List" useGeneratedKeys="false">
INSERT ALL
<foreach collection="listAutoData" item="item" index="index">
into SATISFACTION_SURVEY 
(PROJECT_NO, EVALUATE, EMPLOYEE_NO, SUBMIT_TIME, as_side)
values
(#{item.projectNo}, #{evaluate}, #{item.employeeNo}, sysdate, 0)
</foreach>
SELECT 1 FROM DUAL
</insert>

補充說明:一、foreach外包了一層sql,解決核心;二、注意foreach裏面的屬性配置,沒有通常的begin、end、分隔符等;框架

三、useGeneratedKeys="false"  筆者也不清楚是否是必須加這句,你們能夠不加試下dom

(2)後面又發現的一種方法,很好理解也很符合oracleide

DAO:學習

int insertCircle(@Param("year")int year, @Param("quarter")int quarter, 
        @Param("monthAry")int[] monthAry, @Param("weekAry")int[] weekAry);
//爲了你們理解,特別附上service的代碼:
public int insertCircle(int year, int quarter) {
   int beginMonth = quarter * 3 - 2;
   int[] monthAry = {beginMonth, beginMonth + 1, beginMonth + 2};
   int[] weekAry = {1, 2, 3, 4};
   return testDao.insertCircle(year, quarter, monthAry, weekAry);
}

上XML代碼前先介紹一下在oracle裏面,批量插入語句的sql樣式是這樣的

INSERT INTO TABLE_TEST (ID,NAME,PASSWORD,USERAGE)
     SELECT 'id1','zhangsan','123',20 FROM DUAL
      UNION ALL SELECT 'id2','lisi','321',30 FROM DUAL
      UNION ALL SELECT 'id3','wang','123456',40 FROM DUAL

有了這個模板,咱們就很容易結合Mybatis標籤,拼接出數據庫能夠執行sql

=====>補充一個簡單的例子,方便copy(於2018-04-02日補充)

<insert id="createExamRecord" parameterType="java.util.List">
      insert into CAIM_EXAM 
      (ID, OPEN_ID, QUESTION_ID)
      <foreach collection="randomQus" item="item" index="index" separator="UNION ALL">
          SELECT
          sys_guid(),
          #{openId},
          #{item.questionId}
          FROM dual
      </foreach>
  </insert>

補:上面 openId 爲另外一個string的入參,item.questionId 爲遍歷對象的一個屬性值

 

下面是一個以前的例子,不是很直白

XML:

<insert id="insertCircle" parameterType="java.util.List">
 INSERT INTO SALES_WEEKLY
        (ID, SUB_TYPE, 
        DISTRICT_CODE, REGION_CODE, SUB_AREA_CODE,
        YEAR, QUARTER, 
        MONTH, WEEK, 
        CREATE_USER, CREATE_TIME, WEEK_TYPE)
            <foreach collection="monthAry" item="item" index="index" separator="UNION ALL">
               <foreach collection="weekAry" item="val" index="seq" separator="UNION ALL">
                    SELECT
                    sys_guid() id,9 SUB_TYPE,
                    12 DISTRICT_CODE,12345 REGION_CODE,66666 SUB_AREA_CODE,
                    #{year} YEAR,#{quarter} QUARTER,
                    #{item} MONTH, 
                    #{val} WEEK,
                    'ZZ123' CREATE_USER, sysdate CREATE_TIME, 6 WEEK_TYPE
                    FROM dual
               </foreach>
            </foreach>
  </insert>

補充說明:這個insert語句是沒有values字段的;

筆者這個sql嵌套了雙層foreach,實現了一次生成一個季度12周的12條不一樣記錄,是參考Mybatis如何實現多重循環的參考例子

有一點須要說明,foreach裏面的字段,最好用別名和數據庫字段對應一下,

二、批量刪除

DAO:

int deleteByListSon(@Param("listSon")List<String> listSon);

XML:

<delete id="deleteByListSon" parameterType="java.util.List">
delete from WECHAT_MENU where id in
<foreach collection="listSon" item="listSon" index="index" separator="," open="(" close=")">
#{listSon}
</foreach>
</delete>

補充說明:這個沒啥好說的,基本sql格式,比較簡單

三、批量更新

(1)DAO:

int changeOnlineByListSon(@Param("listSon")List<String> listSon, @Param("deleted")int deleted);

XML:

<update id="changeOnlineByListSon">
update WECHAT_MENU
<set>
<if test="deleted == 0" >
DELETED = 2,
</if>
<if test="deleted == 2" >
DELETED = 0,
</if>
PUBLISH = 0,
UPDATE_DATE = sysdate,
</set>
where ID in
<foreach collection="listSon" item="item" index="index" separator="," open="(" close=")">
#{item}
</foreach>
</update>

補充說明:這種還算簡單的,是list<string>類型,foreach比較容易,筆者這個sql功能在於切換某菜單的上、下線狀態,因此有deleted(沒用status有緣由、勿噴)這個值(0:上線;2下線)

(2)DAO:

public int saveRegionKpi(@Param("updateToDB")List<HwRegionWeekly> updateToDB, @Param("employeeNo")String employeeNo);

XML:

<update id="updateRole" parameterType="java.util.List">
    <foreach collection="updateToDB" item="record" index="index" open="begin" close=";end;" separator=";">
        update SSM_ROLE
        <set>
            <if test="record.updateUser != null">
                UPDATE_USER = #{employeeNo},
            </if>
            <if test="record.updateTime != null">
                UPDATE_TIME = sysdate,
            </if>
            <if test="record.annualHosKpi != null">
                ANNUAL_HOS_KPI = #{record.annualHosKpi,jdbcType=DECIMAL},
            </if>
            <if test="record.ytdPlanHos != null">
                YTD_PLAN_HOS = #{record.ytdPlanHos,jdbcType=DECIMAL},
            </if>
            <if test="record.status == 1">
                STATUS = 1,
                SUBMIT_USER = #{employeeNo},
                SUBMIT_TIME =
                sysdate,
            </if>
            <if test="record.manageMeeting != null">
                MANAGE_MEETING =
                #{record.manageMeeting,jdbcType=DECIMAL},
            </if>
            <if test="record.remark != null">
                REMARK = #{record.remark}
            </if>
        </set>
        where ID = #{record.id}
    </foreach>
  </update>

補充說明:首先,注意比較和(1)的區別,(1)裏面全部更新的行中,每一個字段更改的值都是同樣的;

其次,(2)更新的多行裏面。一樣的字段也可能更新不一樣的值,其實(2)就是多條並行執行的更新語句,只不過用了mybatis的特性,

最後,主要仍是要注意,(2)這種狀況,foreach標籤的正確寫法

四、批量查詢

DAO:

List<SatisfactionSurvey> listJointData(@Param("listProNo")List<Project> listProNo);

XML:

<select id="listJointData" resultMap="BaseMap">
select r.project_no as PROJECT_NO, r.party_a_manager_no as employee_no, 0 as as_side
from requirement r
where r.project_no in
<foreach collection="listProNo" index="index" item="val" separator="," open="(" close=")">
#{val.projectNo}
</foreach>
</select>

補充說明:這種沒啥好說的,主要是foreach裏面的配置,也是拼接出數據庫能識別的sql語句

(特別新加)關於集合和數組的foreach的配置區別,筆者(2017/10/31)親自遇到了一個例子,DAO層代碼以下

public List<HWList> getAdxSub(@Param("listAdxSub")String[] listAdxSub);//最簡單的字符數組
and c.sub_area_code in 
          <foreach collection="listAdxSub" index="index" item="val" separator="," open="(" close=")">
             #{val}<!--也能夠寫成to_number(${val},999999)  這種只能用$符,外面那種#$均可以,固然  ${val} === ${listAdxSub[index]}  -->
          </foreach>

數組的foreach配置,並不像網上好多說的那樣,collection要配成array(反而這樣會直接報錯),而是和集合的如出一轍,只是取值的方式,有不一樣於集合的方法(如上===)

只是在config裏面的配置,一開始先後多加了一對雙引號:ADXSubarea = 「60109,60110,60111,60116「;致使split()處理後的數據異常,致使錯誤(配置文件裏面的都是默認string類型的,不須要用「」包起來)

==》》以上方法Mybatis會幫咱們進行sql注入攔截,Mybatis若是採用#{xxx}的形式設置參數,Mybatis會進行sql注入的過濾。若是採用的是${xxx},Mybatis不會進行sql注入過濾,而是直接將參入的內容輸出爲sql語句。

五、總結比較

(1)、批量操做,重點在foreach的配置,不熟悉的夥伴能夠先多去了解一下mybatis  foreach標籤的屬性和用法

(2)、上面的例子還摻雜了其餘不少,能夠學習和借鑑的點,仔細看,多發現(以上例子都是,從已上線的項目中抽出來的,絕對是經過測試的

(3)、以上的例子傳入mybatis的參數,基本都是list集合(項目上用到的也幾乎全是list),實際狀況也多是map,這裏特別附上一例(map的批量查詢,加UNION ALL)

附:批量查詢--map參數

DAO:

List<ShowEvaluateList> getListShowInfo(@Param("allProNo")Map<String, List<String>> allProNo, @Param("limit")int limit, @Param("page")int page, 
@Param("beginDate")String beginDate, @Param("endDate")String endDate,
@Param("keyProName")String keyProName, @Param("keyPartyA")String keyPartyA, @Param("keyPartyB")String keyPartyB);//(後面的參數都是條件過濾和分頁用的<貌似分頁功能沒實現>)

Map<String, List<String>> allNoEva = new HashMap<>();
allNoEva.put("A", allNoEvaA);
allNoEva.put("B", allNoEvaB);

//說明:allNoEvaA、allNoEvaB都是List<String>類型的集合(也就是作爲甲方和乙方時,未評價的項目的projectNo的集合)

XML:

<select id="getListShowInfo" resultMap="ListShowMap">

<foreach collection="allProNo.keys" index="k" item="ent" separator="UNION ALL">
select row_number() over(order by 1) as rowIndex,
r.project_name as PRO_NAME, r.project_no as PRO_NO, 
<choose>
<when test='ent == "A"'>
r.party_a_manager as PER, r.party_a_manager_no as PER_ID,
p.actual_online as ACTUAL_END, 0 as WHICH_PARTY
</when>
<otherwise>
r.party_b_manager as PER, r.party_b_manager_no as PER_ID,
p.actual_online as ACTUAL_END, 1 as WHICH_PARTY
</otherwise>
</choose>
FROM requirement r
left join project p on p.project_no = r.project_no
where (p.status = 3 or p.status = 4)
<include refid="filterSql"></include>
<choose>
<when test="allProNo[ent].size() != 0">
and r.project_no in 
<foreach collection="allProNo[ent]" index="v" item="val" separator="," open="(" close=")">
#{val}
</foreach>
</when>
<otherwise>
and r.project_no = 'sssssssssssss'
</otherwise>
</choose>
</foreach>

</select>

補充說明:(1)主要是參考map參數,在mybatis裏面怎麼循環取健和取值

(2)map的話要結合union all使用(關於和union的區別,貌似是union all不去重,union會去重且有些狀況會排序取出的數據順序)

最後,特別加上條件過濾用的sql:<include refid="filterSql"></include>,以供參考,以下:

<sql id="filterSql">
and 1 = 1
<if test="beginDate != null and beginDate != ''">
and p.ACTUAL_ONLINE > to_date(#{beginDate}, 'YYYY/MM/DD')
</if>
<if test="endDate != null and endDate != ''">
and to_date(#{endDate}, 'YYYY/MM/DD') > p.ACTUAL_ONLINE
</if>
<if test="keyProName != null and keyProName != ''">
and p.name like '%${keyProName}%'
</if>
<if test="keyPartyA != null and keyPartyA != ''">
and r.party_a_manager like '%${keyPartyA}%'
</if>
<if test="keyPartyB != null and keyPartyB != ''">
and r.party_b_manager like '%${keyPartyB}%'
</if>
</sql>
相關文章
相關標籤/搜索