sql >> Databasteknik >  >> RDS >> Oracle

Gör massuppdateringar med MyBatis och Oracles lagrade procedurer

En procedur kan ta tabelltypsparametrar och du kan skriva en anpassad typhanterare som utför konverteringen.

Det kan vara lättare att förklara med konkreta objekt.
Istället för MY_TYPE , jag använder S_USER_OBJ ...

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

...ett bord...

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

...och en POJO.

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

Här är den nya typen som är en samling av S_USER_OBJ .

create or replace type S_USER_OBJ_LIST as table of S_USER_OBJ;

Proceduren kan ta tabelltypen som parametrar. t.ex.

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;

Mapper skulle se ut så här:

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 är en anpassad typhanterare som konverterar List<User> till/från en ARRAY av 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;
  }
  ...
}

Koden som använder metoden skulle se ut ungefär så här.

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

För OUT parameter, det finns också ett annat sätt att använda refcursor och resultatkarta.
I mapper-satsen, specificera OUT-parametern enligt följande.

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

Resultatkartan är ganska enkel.

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

I proceduren, deklarera OUT-parametern som 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;

Här är en körbar demo:
https://github .com/harawata/mybatis-issues/tree/master/so-56834806




  1. SqlDeveloper:rensa nätverksaliaslista

  2. Duplicera/kopiera poster i samma MySQL-tabell

  3. VÄLJ Från MySQL-vy med HAVING-sats Returnerar tom resultatuppsättning

  4. Hur du säkerhetskopierar din Moodle MariaDB-databas