MyBatis 调用Oracle存储函数,使用Map传递参数

1:编写简单函数:(通过return关键字返回结果集)

create or replace function fun_add(p1 number ,p2 number)
  return number
  as
begin
    return p1+p2;
end;

2.MyBatis的xml文件(对于返回值为一般数据类型的函数)

复杂类型用:  

<parameter property="result"jdbcType="ORACLECURSOR"  javaType="java.sql.ResultSet" mode="OUT "resultMap="auditselect_resultList" />

	<parameterMap id="parameterInoutTypeNum"  
	    class="java.util.Map">  
	    <parameter property="p3" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT" />  
	    <parameter property="p1" jdbcType="INTEGER" javaType="java.lang.Integer" mode="IN" />  
	    <parameter property="p2" jdbcType="INTEGER" javaType="java.lang.Integer" mode="IN" />  
	</parameterMap>	
	<procedure id="inoutTypeNum_Oracle" parameterMap="parameterInoutTypeNum">
		 {? = call fun_add(?,?)}  
	</procedure>

3.dao层

        //查询函数的方法
        public void callFunction(Map map);

4.service实现类

    //调用函数
    public void funTest(){
        SqlSession session=getSession();
        CallMapper cm=session.getMapper(CallMapper.class);
        Map map=new HashMap();
        map.put("p1", 100);
        map.put("p2", 400);
        cm.callFunction(map);
        System.out.println(map.get("p3"));
    }

 

 

<think>好的,我现在要帮用户解决使用Java MyBatis调用Oracle存储过程的问题。首先,我需要确认用户的需求是什么。他们可能需要在Java应用中通过MyBatis框架来调用Oracle数据库中的存储过程,可能是为了执行某些业务逻辑,处理数据,或者获取结果。 首先,我应该回忆一下MyBatis调用存储过程的基本步骤。通常,这涉及到在Mapper XML文件中定义对应的SQL语句,使用<select>、<insert>、<update>或<delete>标签,但具体标签可能根据存储过程的操作类型来选择。不过,对于存储过程,通常使用<select>或者专门的<procedure>标签?或者可能使用<update>?这里需要确认一下。 另外,存储过程可能有输入参数、输出参数,或者同时有输入输出参数。在MyBatis中处理这些参数,需要使用参数类型的定义,比如parameterType,以及通过#{paramName, mode=IN, jdbcType=...}这样的语法来指定参数的模式和类型。可能还需要使用jdbcType来指定数据库类型,特别是对于OUT参数,必须指定jdbcType,因为MyBatis需要知道如何将结果映射到Java对象。 接下来,用户可能需要一个实际的例子来说明如何配置XML和调用代码。例如,假设有一个存储过程名为add_employee,它接收员工的信息作为输入参数,并返回生成的员工ID作为输出参数。那么,在Mapper XML中,应该怎么写这个调用语句? 可能的步骤是: 1. 在Oracle中创建存储过程。用户可能需要知道存储过程的定义,所以提供一个简单的例子会有帮助。例如: CREATE OR REPLACE PROCEDURE add_employee ( p_name IN VARCHAR2, p_age IN NUMBER, p_id OUT NUMBER ) AS BEGIN INSERT INTO employees(name, age) VALUES (p_name, p_age); SELECT employee_seq.CURRVAL INTO p_id FROM dual; END; 这里,存储过程接受姓名和年龄作为输入,插入到employees表中,然后通过序列获取生成的ID,赋值给p_id输出参数。 2. 在MyBatisMapper XML文件中定义调用存储过程的语句。这里需要使用<insert>或者<update>标签?或者使用<select>?其实,存储过程本身可能不返回结果集,而是通过输出参数返回值,所以可能需要使用<select>标签并设置statementType为CALLABLE,因为调用存储过程需要使用CallableStatement。 例如: <select id="callAddEmployee" statementType="CALLABLE" parameterType="map"> {call add_employee( #{name, mode=IN, jdbcType=VARCHAR}, #{age, mode=IN, jdbcType=INTEGER}, #{id, mode=OUT, jdbcType=INTEGER} )} </select> 这里,statementType设置为CALLABLE表示这是一个可调用的语句,即存储过程。参数类型可能使用Map或者一个JavaBean,这里假设使用Map传递参数参数模式分为IN、OUT、INOUT,根据存储过程的参数定义。 3. 在Java的Mapper接口中定义对应的方法,例如: void callAddEmployee(Map<String, Object> params); 或者如果使用注解的方式,可能用@Options或者@Select注解,但通常更常见的是在XML中配置。 4. 在Service层调用这个方法,传递包含参数Map,执行后从Map中获取输出参数的值。 例如: Map<String, Object> params = new HashMap<>(); params.put("name", "张三"); params.put("age", 30); employeeMapper.callAddEmployee(params); Integer generatedId = (Integer) params.get("id"); 这样,调用存储过程后,生成的ID会被放到params的"id"键中。 需要注意的是,存储过程的参数顺序必须与XML中调用时的顺序一致,否则可能导致错误。另外,jdbcType需要正确设置,特别是对于OUT参数,否则MyBatis可能无法正确识别类型,导致映射错误。 可能还需要处理异常,比如数据库访问异常,参数不匹配等问题。此外,如果存储过程返回结果集,可能需要使用ResultMap来处理,但上述例子中没有涉及结果集,只有输出参数。 另一个需要注意的点是,在Oracle中,存储过程的调用语法是{call procedure_name(...)},而如果存储过程有返回参数,可能需要使用?作为占位符。但上面的例子中参数直接通过#{...}的方式引用,这在MyBatis中是允许的,因为它会自动替换成占位符并处理参数模式。 另外,如果参数是INOUT类型,需要在mode中指定mode=INOUT,并且确保Java代码中传递参数是可变的,比如使用Map或者一个对象,这样MyBatis可以回写输出值到参数中。 可能还需要提到使用实体类作为参数的情况,而不仅仅是Map。例如,可以定义一个Employee类,包含name、age和id属性,然后在parameterType中指定该类,并在调用传递该对象,MyBatis会自动映射参数名称。例如: public class Employee { private String name; private int age; private Integer id; // getters and setters } 然后在XML中: <select id="callAddEmployee" statementType="CALLABLE" parameterType="com.example.Employee"> {call add_employee( #{name, mode=IN, jdbcType=VARCHAR}, #{age, mode=IN, jdbcType=INTEGER}, #{id, mode=OUT, jdbcType=INTEGER} )} </select> 然后在Mapper接口中: void callAddEmployee(Employee employee); 调用时: Employee employee = new Employee(); employee.setName("张三"); employee.setAge(30); employeeMapper.callAddEmployee(employee); Integer generatedId = employee.getId(); 这样,输出参数id会被设置到employee对象的id属性中。这比使用Map更类型安全,也更清晰。 此外,可能还需要处理存储过程返回的游标,即结果集。例如,Oracle存储过程可能返回一个SYS_REFCURSOR类型的参数,这时在MyBatis中需要指定对应的结果映射。例如: 假设存储过程: CREATE OR REPLACE PROCEDURE get_employees ( p_dept_id IN NUMBER, p_employees OUT SYS_REFCURSOR ) AS BEGIN OPEN p_employees FOR SELECT * FROM employees WHERE dept_id = p_dept_id; END; 在MyBatis中处理这种情况,需要在XML中声明该OUT参数为jdbcType=CURSOR,并指定resultMap: <select id="callGetEmployees" statementType="CALLABLE" parameterType="map"> {call get_employees( #{deptId, mode=IN, jdbcType=INTEGER}, #{employees, mode=OUT, jdbcType=CURSOR, javaType=java.sql.ResultSet, resultMap=employeeResultMap} )} </select> 然后在调用后,可以从参数中获取结果集。这时可能需要使用不同的方式处理,比如将结果集映射到List中。不过,处理游标可能需要更复杂的配置,比如在resultMap中定义列到属性的映射。 不过,用户的问题主要是调用存储过程的基本步骤,可能不需要深入游标的处理,但如果有需要的话,应该简要提及。 总结步骤: 1. 定义存储过程:确保存储过程在Oracle中存在,并且参数模式(IN、OUT)正确。 2. 在MyBatisMapper XML中编写调用存储过程的语句,使用{call ...}语法,指定statementType="CALLABLE",正确设置每个参数的mode和jdbcType。 3. 在Mapper接口中定义对应的方法,参数类型可以是Map或JavaBean。 4. 在业务代码中调用该方法,并处理输出参数。 可能遇到的常见问题: - 参数顺序错误:存储过程参数和XML中的顺序不一致,导致参数传递错误。 - 未指定jdbcType:特别是OUT参数,必须指定jdbcType,否则MyBatis可能无法正确处理。 - 没有设置statementType="CALLABLE",导致MyBatis将其视为普通SQL语句执行,引发错误。 - 使用错误的方法类型:比如应该使用<select>却用了<update>,但其实标签类型可能不影响,因为存储过程可能没有返回结果集,但为了明确,最好根据操作类型选择标签,或者统一使用<select>并设置statementType。 另外,需要提醒用户注意事务管理,如果存储过程执行了DML操作(如INSERT、UPDATE),需要确保在事务中调用,以便在出错时回滚。 最后,提供一个完整的示例,包括存储过程定义、MyBatis配置、Java代码,可以帮助用户更好地理解。可能还需要提到使用注解的方式,但通常XML配置更灵活,尤其是对于复杂的存储过程调用。</think>以下是使用Java MyBatis调用Oracle存储过程的详细步骤: --- ### 一、Oracle存储过程定义 假设存储过程`ADD_EMPLOYEE`实现插入员工记录并返回生成的ID: ```sql CREATE OR REPLACE PROCEDURE ADD_EMPLOYEE ( p_name IN VARCHAR2, p_age IN NUMBER, p_id OUT NUMBER ) AS BEGIN INSERT INTO employees(name, age) VALUES (p_name, p_age); SELECT employee_seq.CURRVAL INTO p_id FROM dual; END; ``` --- ### 二、MyBatis配置步骤 #### 1. Mapper XML文件配置 在Mapper XML中定义调用存储过程的SQL,使用`statementType="CALLABLE"`: ```xml <!-- 使用Map传参 --> <select id="callAddEmployee" statementType="CALLABLE" parameterType="map"> {call ADD_EMPLOYEE( #{name, mode=IN, jdbcType=VARCHAR}, #{age, mode=IN, jdbcType=INTEGER}, #{id, mode=OUT, jdbcType=INTEGER} )} </select> <!-- 或使用JavaBean传参 --> <select id="callAddEmployee" statementType="CALLABLE" parameterType="com.example.Employee"> {call ADD_EMPLOYEE( #{name, mode=IN, jdbcType=VARCHAR}, #{age, mode=IN, jdbcType=INTEGER}, #{id, mode=OUT, jdbcType=INTEGER} )} </select> ``` #### 2. Mapper接口定义 ```java public interface EmployeeMapper { void callAddEmployee(Map<String, Object> params); // Map方式 // 或 void callAddEmployee(Employee employee); // JavaBean方式 } ``` --- ### 三、Java代码调用 #### 1. 使用Map传参 ```java Map<String, Object> params = new HashMap<>(); params.put("name", "张三"); params.put("age", 30); employeeMapper.callAddEmployee(params); Integer generatedId = (Integer) params.get("id"); ``` #### 2. 使用JavaBean传参 ```java Employee employee = new Employee(); employee.setName("张三"); employee.setAge(30); employeeMapper.callAddEmployee(employee); Integer generatedId = employee.getId(); ``` --- ### 四、关键注意事项 1. **参数模式与类型**: - 必须明确指定`mode=IN/OUT/INOUT`和`jdbcType`(如`jdbcType=VARCHAR`)。 - **OUT参数必须指定`jdbcType`**,否则可能映射失败。 2. **标签选择**: - 使用`<select>`标签并设置`statementType="CALLABLE"`,无论存储过程是否返回值。 3. **事务控制**: - 若存储过程执行写操作(INSERT/UPDATE/DELETE),确保方法在事务中调用。 --- ### 五、处理游标结果集 若存储过程返回游标(如`SYS_REFCURSOR`),需配置`resultMap`: ```xml <select id="getEmployees" statementType="CALLABLE" parameterType="map"> {call GET_EMPLOYEES( #{deptId, mode=IN, jdbcType=INTEGER}, #{employees, mode=OUT, jdbcType=CURSOR, javaType=java.sql.ResultSet, resultMap=employeeMap} )} </select> <resultMap id="employeeMap" type="com.example.Employee"> <result property="id" column="employee_id"/> <result property="name" column="name"/> <result property="age" column="age"/> </resultMap> ``` --- ### 六、常见错误排查 - **参数顺序不一致**:确保XML中参数顺序与存储过程定义一致。 - **缺少jdbcType**:OUT参数必须指定`jdbcType`。 - **事务未提交**:写操作后需提交事务,或通过注解`@Transactional`管理。 --- 通过以上步骤,即可在MyBatis中高效调用Oracle存储过程,实现灵活的数据操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值