传出参数是游标引用

对于Oracle、PgSQL这种数据库,支持将游标引用作为传出参数。
一般来说,游标往往代表一个结果集,这样可以让存储过程传出多个查询结果集。
当传出参数是游标时,调用该存储过程时,该参数必须使用List类型的变量才能正常封装该结果集。

注意点:

  1. 必须为参数在#{}用mode指定OUT模式。
  2. 传出参数要求必须指定jdbcType,通常指定为CURSOR,PgSQL应该指定为OTHER
    javaType应该指定为ResultSet(当jdbcType=CURSOR,这一步可省略)
    resultMap:它负责将游标引用对应的结果集映射成Java对象。
  3. 当传出参数是游标引用时,该参数必须使用List类型的变量才能正常封装该结果集。
    项目0511游标引用

项目0511游标引用

主类

package lee;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.itcheng.app.dao.NewsMapper;
import org.itcheng.app.domain.News;
import org.itcheng.app.domain.NewsWrapper;

public class NewsManager
{
	// SqlSessionFactory应该是应用级别
	private static SqlSessionFactory sqlSessionFactory;
	public static void main(String[] args) throws IOException
	{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 1. 创建SqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		// 2. 打开SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		// 查询消息
		selectNews(sqlSession);	
		
		//  再次打开SqlSession
		sqlSession = sqlSessionFactory.openSession();
		
		// 查询消息
		selectNews2(sqlSession);	
	}
	
	public static void selectNews(SqlSession sqlSession)
	{
		// 此处的NewsMapper只是一个接口
		// MyBatis会使用JDK的动态代理为Mapper接口生成实现类
		NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
		System.out.println(newsMapper.getClass());
		
		Map<String, Object> map = new HashMap<>();
		map.put("id", 1);
		// 调用存储过程。游标类型的传出参数会以key-value对形式放入Map中
		newsMapper.findNewsByProc(map);  // 调用了带传出参数的存储过程
		
		// 取出传出参数对应的值(游标引用封装的结果集)
		List<News> list = (List<News>) map.get("result");
		
		list.forEach(e -> {
			System.out.println(e.getContent());
		});
	
		// 4. 提交事务
		sqlSession.commit();
		// 5. 关闭资源
		sqlSession.close();	
	}
	
	public static void selectNews2(SqlSession sqlSession)
	{
		// 此处的NewsMapper只是一个接口
		// MyBatis会使用JDK的动态代理为Mapper接口生成实现类
		NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
		System.out.println(newsMapper.getClass());
		
		NewsWrapper nw = new NewsWrapper();
		nw.setId(1); // 该对象的id属性将作为传入参数,
		// newsList属性将作为传出参数,调用存储过程后,newsList属性就封装游标类型的传出参数的值
		newsMapper.findNewsByProc2(nw);  // 调用了带传出参数的存储过程
		
		// 取出传出参数对应的值(游标引用封装的结果集)
		List<News> list = nw.getNewsList();
		
		list.forEach(e -> {
			System.out.println(e.getContent());
		});
	
		// 4. 提交事务
		sqlSession.commit();
		// 5. 关闭资源
		sqlSession.close();	
	}	
}

接口类

package org.itcheng.app.dao;

import java.util.Map;

import org.itcheng.app.domain.NewsWrapper;

// Mapper组件相当于DAO组件
public interface NewsMapper
{
	void findNewsByProc(Map<String, Object> map);
	
	void findNewsByProc2(NewsWrapper nw);
}

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 根元素是mapper,该元素的namespace属性值相当于该mapper的唯一标识 -->	
<mapper namespace="org.itcheng.app.dao.NewsMapper">

	<select id="findNewsByProc" statementType="CALLABLE">
		<!--
		第二个参数是一个游标引用,因此该参数必须使用List类型的变量
		如果你用Map作为参数传入,第二个result会以key-value对被放入Map参数中,其中key是result,value就是游标引用对应的结果集
		  -->
		{call p_get_news_by_id(#{id}, #{result, mode=OUT, jdbcType=OTHER, javaType=ResultSet, resultMap=newsMap})}
	</select>
	
	<select id="findNewsByProc2" statementType="CALLABLE">
		<!--
		第二个参数是一个游标引用,因此该参数必须使用List类型的变量
		如果你用Map作为参数传入,第二个result会以key-value对被放入Map参数中,其中key是result,value就是游标引用对应的结果集
		  -->
		{call p_get_news_by_id(#{id}, #{newsList, mode=OUT, jdbcType=OTHER, javaType=ResultSet, resultMap=newsMap})}
	</select>	
	
	<resultMap type="news" id="newsMap">
		<id column="news_id" property="id"/>
		<result column="news_title" property="title"/>
		<result column="news_content" property="content"/>
	</resultMap>
</mapper>

对象类

package org.itcheng.app.domain;

public class News
{
	private Integer id;
	private String title;
	private String content;
	//有参无参构造器,set和get方法
}
package org.itcheng.app.domain;
import java.util.List;

public class NewsWrapper
{
	private Integer id;
	// 该属性用于封装游标引用类型的传出参数
	private List<News> newsList;
	//set和get方法
}

主配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
	PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置根元素 -->	
<configuration>

 	<typeAliases>
 		<!-- 为指定包下所有类指定别名 -->
 		<package name="org.itcheng.app.domain"/>
 	</typeAliases>
 	
	<!-- 用于配置多个数据库环境 -->
	<environments default="pgsql">
		<!-- environment配置一个数据库环境 -->
		<environment id="pgsql">
			<!-- 配置事务类型:JDBC或Managed,此时的JDBC等都是实现类的缩写 -->
			<transactionManager type="JDBC" />
			<!-- 配置数据库连接池,POOLED也是一个实现类的缩写  -->
			<dataSource type="POOLED">
				<property name="driver" value="org.postgresql.Driver" />
				<property name="url" value="jdbc:postgresql://localhost:5432/mybatis" />
				<property name="username" value="postgres" />
				<property name="password" value="32147" />
			</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<!-- mapper文件负责管理MyBatis的SQL语句 -->
		<mapper resource="org/itcheng/app/dao/NewsMapper.xml" />
	</mappers>


</configuration>

项目0512游标引用_注解

主配置文件

package lee;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.itcheng.app.dao.NewsMapper;
import org.itcheng.app.domain.News;
import org.itcheng.app.domain.NewsWrapper;

public class NewsManager
{
	// SqlSessionFactory应该是应用级别
	private static SqlSessionFactory sqlSessionFactory;
	public static void main(String[] args) throws IOException
	{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 1. 创建SqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		// 2. 打开SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		// 查询消息
		selectNews(sqlSession);	
		
		//  再次打开SqlSession
		sqlSession = sqlSessionFactory.openSession();
		
		// 查询消息
		selectNews2(sqlSession);				
	}
	
	public static void selectNews(SqlSession sqlSession)
	{
		// 此处的NewsMapper只是一个接口
		// MyBatis会使用JDK的动态代理为Mapper接口生成实现类
		NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
		System.out.println(newsMapper.getClass());
		
		Map<String, Object> map = new HashMap<>();
		map.put("id", 1);
		// 调用存储过程。游标类型的传出参数会以key-value对形式放入Map中
		newsMapper.findNewsByProc(map);  // 调用了带传出参数的存储过程
		
		// 取出传出参数对应的值(游标引用封装的结果集)
		List<News> list = (List<News>) map.get("result");
		
		list.forEach(e -> {
			System.out.println(e.getContent());
		});
	
		// 4. 提交事务
		sqlSession.commit();
		// 5. 关闭资源
		sqlSession.close();	
	}
	
	public static void selectNews2(SqlSession sqlSession)
	{
		// 此处的NewsMapper只是一个接口
		// MyBatis会使用JDK的动态代理为Mapper接口生成实现类
		NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
		System.out.println(newsMapper.getClass());
		
		NewsWrapper nw = new NewsWrapper();
		nw.setId(1); // 该对象的id属性将作为传入参数,
		// newsList属性将作为传出参数,调用存储过程后,newsList属性就封装游标类型的传出参数的值
		newsMapper.findNewsByProc2(nw);  // 调用了带传出参数的存储过程
		
		// 取出传出参数对应的值(游标引用封装的结果集)
		List<News> list = nw.getNewsList();
		
		list.forEach(e -> {
			System.out.println(e.getContent());
		});
	
		// 4. 提交事务
		sqlSession.commit();
		// 5. 关闭资源
		sqlSession.close();	
	}	
	
}

接口类

package org.itcheng.app.dao;

import java.util.Map;

import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.StatementType;
import org.itcheng.app.domain.NewsWrapper;

// Mapper组件相当于DAO组件
public interface NewsMapper
{
	@Select("{call p_get_news_by_id(#{id}, #{result, mode=OUT, jdbcType=OTHER, javaType=ResultSet, resultMap=newsMap})}")
	@Options(statementType = StatementType.CALLABLE)
	void findNewsByProc(Map<String, Object> map);
	
	@Select("{call p_get_news_by_id(#{id}, #{newsList, mode=OUT, jdbcType=OTHER, javaType=ResultSet, resultMap=newsMap})}")
	@Options(statementType = StatementType.CALLABLE)
	void findNewsByProc2(NewsWrapper nw);
}

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 根元素是mapper,该元素的namespace属性值相当于该mapper的唯一标识 -->	
<mapper namespace="org.itcheng.app.dao.NewsMapper">
	
	<resultMap type="news" id="newsMap">
		<id column="news_id" property="id"/>
		<result column="news_title" property="title"/>
		<result column="news_content" property="content"/>
	</resultMap>
</mapper>

主配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
	PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置根元素 -->	
<configuration>

 	<typeAliases>
 		<!-- 为指定包下所有类指定别名 -->
 		<package name="org.itcheng.app.domain"/>
 	</typeAliases>
 	
	<!-- 用于配置多个数据库环境 -->
	<environments default="pgsql">
		<!-- environment配置一个数据库环境 -->
		<environment id="pgsql">
			<!-- 配置事务类型:JDBC或Managed,此时的JDBC等都是实现类的缩写 -->
			<transactionManager type="JDBC" />
			<!-- 配置数据库连接池,POOLED也是一个实现类的缩写  -->
			<dataSource type="POOLED">
				<property name="driver" value="org.postgresql.Driver" />
				<property name="url" value="jdbc:postgresql://localhost:5432/mybatis" />
				<property name="username" value="postgres" />
				<property name="password" value="32147" />
			</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<!-- mapper文件负责管理MyBatis的SQL语句 -->
		<package name="org.itcheng.app.dao" />
	</mappers>


</configuration>
01-21 15:31