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