Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Melakukan pembaruan massal dengan prosedur tersimpan MyBatis dan Oracle

Prosedur dapat mengambil parameter jenis tabel dan Anda dapat menulis penangan jenis khusus yang melakukan konversi.

Mungkin lebih mudah untuk menjelaskan menggunakan objek konkret.
Daripada MY_TYPE , saya akan menggunakan S_USER_OBJ ...

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

...sebuah meja...

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

...dan sebuah POJO.

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

Berikut adalah tipe baru yang merupakan kumpulan dari S_USER_OBJ .

create or replace type S_USER_OBJ_LIST as table of S_USER_OBJ;

Prosedur dapat mengambil tipe tabel sebagai parameter. misalnya

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 akan terlihat sebagai berikut:

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 adalah penangan tipe khusus yang mengonversi List<User> ke/dari ARRAY dari 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;
  }
  ...
}

Kode yang menggunakan metode akan terlihat seperti ini.

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

Untuk OUT parameter, ada juga cara lain menggunakan refcursor dan result map.
Dalam pernyataan mapper, tentukan parameter OUT sebagai berikut.

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

Peta hasil cukup mudah.

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

Dalam prosedur, nyatakan parameter OUT sebagai 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;

Berikut adalah demo yang dapat dieksekusi:
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. Memetakan bidang ORACLE TIMESTAMP(9) ke java.util.Date

  2. Dapatkan panjang nilai kolom, bukan panjang nilai maksimum kolom

  3. Cara Menghitung Perbedaan Antara Dua Timestamp di Oracle

  4. Pilih yang berbeda pada gumpalan

  5. cara mengubah status blok untuk dimasukkan dalam 10g menggunakan pemicu tombol