Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Wykonywanie zbiorczych aktualizacji za pomocą procedur składowanych MyBatis i Oracle

Procedura może przyjmować parametry typu tabeli i możesz napisać niestandardowy program obsługi typu, który wykona konwersję.

Wyjaśnienie może być łatwiejsze przy użyciu konkretnych obiektów.
Zamiast MY_TYPE , użyję S_USER_OBJ ...

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

...stół...

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

...i POJO.

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

Oto nowy typ, który jest zbiorem S_USER_OBJ .

create or replace type S_USER_OBJ_LIST as table of S_USER_OBJ;

Procedura może przyjąć typ tabeli jako parametry. np.

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 wyglądałby następująco:

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 to niestandardowy program obsługi typów, który konwertuje List<User> do/z ARRAY z 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;
  }
  ...
}

Kod używający tej metody wyglądałby mniej więcej tak.

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

Dla OUT parametr, istnieje również inny sposób użycia refcursora i mapy wyników.
W instrukcji mapper określ parametr OUT w następujący sposób.

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

Mapa wyników jest dość prosta.

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

W procedurze zadeklaruj parametr OUT jako 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;

Oto wersja demonstracyjna:
https://github .com/harawata/mybatis-issues/tree/master/so-56834806




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle PL/SQL:Eksportuj dane z tabeli do CSV

  2. Jak powtórzyć zapytanie w Oracle

  3. Błąd adaptera protokołu Oracle

  4. Metoda gromadzenia:procedura EXTEND w bazie danych Oracle

  5. Jak usunąć określoną wartość z ciągu oddzielonego przecinkami w Oracle?