Một thủ tục có thể nhận các tham số kiểu bảng và bạn có thể viết một trình xử lý kiểu tùy chỉnh để thực hiện chuyển đổi.
Có thể dễ dàng giải thích hơn bằng cách sử dụng các đối tượng cụ thể.
Thay vì MY_TYPE
, Tôi sẽ sử dụng S_USER_OBJ
...
create or replace type S_USER_OBJ as object (
id integer,
name varchar(20)
);
... một bảng ...
create table users (
id integer,
name varchar(20)
);
... và một POJO.
public class User {
private Integer id;
private String name;
// setter/getter
}
Đây là kiểu mới là tập hợp của S_USER_OBJ
.
create or replace type S_USER_OBJ_LIST as table of S_USER_OBJ;
Thủ tục có thể lấy kiểu bảng làm tham số. ví dụ:
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;
Người lập bản đồ sẽ trông như sau:
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
là một trình xử lý kiểu tùy chỉnh chuyển đổi List<User>
đến / từ một ARRAY
của 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;
}
...
}
Mã sử dụng phương thức sẽ trông giống như thế này.
Map<String, ?> outParam = new HashMap<>();
mapper.doUpdate(userList, outParam);
List<User> outUsers = outParam.get("outUsers");
Đối với OUT
tham số, cũng có một cách khác là sử dụng con trỏ và ánh xạ kết quả.
Trong câu lệnh ánh xạ, chỉ định tham số OUT như sau.
#{outParam.outUsers,jdbcType=CURSOR,javaType=java.sql.ResultSet,mode=OUT,resultMap=userRM}
Bản đồ kết quả khá đơn giản.
<resultMap type="test.User" id="userRM">
<id property="id" column="id" />
<result property="name" column="name" />
</resultMap>
Trong thủ tục, khai báo tham số OUT là 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;
Đây là bản trình diễn có thể thực thi:
https://github .com / harawata / mybatis-Problem / tree / master / so-56834806