sql >> データベース >  >> RDS >> Oracle

MyBatisおよびOracleストアドプロシージャを使用した一括更新の実行

    プロシージャはテーブルタイプパラメータを受け取ることができ、変換を実行するカスタムタイプハンドラを作成できます。

    具体的なオブジェクトを使用して説明する方が簡単な場合があります。
    MY_TYPEの代わりに 、S_USER_OBJを使用します ...

    create or replace type S_USER_OBJ as object (
      id integer,
      name varchar(20)
    );
    

    ...テーブル...

    create table users (
      id integer,
      name varchar(20)
    );
    

    ...そしてPOJO。

    public class User {
      private Integer id;
      private String name;
      // setter/getter
    }
    

    これがS_USER_OBJのコレクションである新しいタイプです 。

    create or replace type S_USER_OBJ_LIST as table of S_USER_OBJ;
    

    プロシージャは、テーブルタイプをパラメータとして受け取ることができます。例:

    create or replace procedure doUpdate(
      user_list in S_USER_OBJ_LIST,
      user_out out S_USER_OBJ_LIST
    ) is
    begin
      -- process IN param
      for i in user_list.first .. user_list.last loop
        update users
          set name = user_list(i).name)
          where id = user_list(i).id;
      end loop;
      -- set OUT param
      select * bulk collect into user_out
        from (
          select S_USER_OBJ(u.id, u.name) from users u
        );
    end;
    

    マッパーは次のようになります。

    void doUpdate(
      @Param("users") List<User> users,
      @Param("outParam") Map<String, ?> outParam);
    
    <update id="doUpdate" statementType="CALLABLE">
      {call doUpdate(
        #{users,typeHandler=pkg.UserListTypeHandler},
        #{outParam.outUsers,jdbcType=ARRAY,jdbcTypeName=S_USER_OBJ_LIST,mode=OUT,typeHandler=pkg.UserListTypeHandler}
      )}
    </update>
    

    UserListTypeHandler List<User>を変換するカスタムタイプハンドラーです ARRAYとの間 STRUCTの 。

    import java.math.BigDecimal;
    import java.sql.Array;
    import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Struct;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.ibatis.type.BaseTypeHandler;
    import org.apache.ibatis.type.JdbcType;
    
    import oracle.jdbc.driver.OracleConnection;
    
    public class UserListTypeHandler extends
        BaseTypeHandler<List<User>>{
    
      @Override
      public void setNonNullParameter(
          PreparedStatement ps, int i, List<User> parameter,
          JdbcType jdbcType) throws SQLException {
        Connection conn = ps.getConnection();
        List<Struct> structs = new ArrayList<Struct>();
        for (int idx = 0; idx < parameter.size(); idx++) {
          User user = parameter.get(idx);
          Object[] result = { user.getId(), user.getName() };
          structs.add(conn.createStruct("S_USER_OBJ", result));
        }
        Array array = ((OracleConnection) conn)
          .createOracleArray("S_USER_OBJ_LIST",
          structs.toArray());
        ps.setArray(i, array);
        array.free();
      }
    
      @Override
      public List<User> getNullableResult(
          CallableStatement cs,
          int columnIndex) throws SQLException {
        List<User> result = new ArrayList<>();
        Array array = cs.getArray(columnIndex);
        Object[] objs = (Object[]) array.getArray();
        for (Object obj : objs) {
          Object[] attrs = ((Struct) obj).getAttributes();
          result.add(new User(
            ((BigDecimal) attrs[0]).intValue(),
            (String) attrs[1]));
        }
        array.free();
        return result;
      }
      ...
    }
    

    このメソッドを使用するコードは次のようになります。

    Map<String, ?> outParam = new HashMap<>();
    mapper.doUpdate(userList, outParam);
    List<User> outUsers = outParam.get("outUsers");
    

    OUTの場合 パラメータには、refcursorと結果マップを使用する別の方法もあります。
    mapperステートメントで、OUTパラメータを次のように指定します。

    #{outParam.outUsers,jdbcType=CURSOR,javaType=java.sql.ResultSet,mode=OUT,resultMap=userRM}
    

    結果マップは非常に単純です。

    <resultMap type="test.User" id="userRM">
      <id property="id" column="id" />
      <result property="name" column="name" />
    </resultMap>
    

    プロシージャで、OUTパラメータをSYS_REFCURSORとして宣言します。

    create or replace procedure doUpdate(
      user_list in S_USER_OBJ_LIST,
      user_out out SYS_REFCURSOR
    ) is
    begin
      ...
      -- set OUT param
      open user_out for select * from users;
    end;
    

    実行可能なデモは次のとおりです。
    https:// github .com / harawata / mybatis-issues / tree / master / so-56834806




    1. 特定のSQLクエリで1または0を返す

    2. PostgreSQL9.0のバックアップとリカバリ

    3. timediffの予期しない結果

    4. 関数、プロシージャを表示する方法、postgresqlでソースコードをトリガーしますか?