ディレクトリ
ストアド・プロシージャ・コールを実行すると、結果セットを返します
序文
1、JdbcTemplate、POM依存性、DI噴射「を参照することができるの導入に共通のCRUDの春JdbcTemplateテンプレート解析 JdbcTemplateコールデータベースが紙プレゼント」ストアドプロシージャを MySQLはまた、ストアド・プロシージャを有するが、しかしできるだけカバー少し以上に、私たちはOracleのストアドプロシージャを呼び出すことを選択し、他のデータベースは、同じ理由です。
1)メソッドを実行します。一般的にDDL文の実装に使用される任意のSQL文を、実行することができ;およびビルドテーブルに、削除テーブルなどSQL。
2)更新、batchUpdateメソッド:追加、変更、削除のステートメントを実行するための更新方法を、batchUpdateメこの方法は、関連する文のバッチを実行するために使用される;
3)queryForObject、queryForList、クエリ方法:クエリ関連した文を実行するために、queryForObjectクエリ結果は、過剰以下であることが例外をスローします;
4)queryForListを照会結果と空で、リストのサイズは、NullPointerExceptionが0ではありません返します。
5)呼び出し方法:手順、機能関連した文を実行するために記憶されています。
2、この環境:Oracleの11グラム(ドライブバージョンojdbc8-19.3.0.0)+ JavaのJDK 1.8 +春ブーツ2.1.5 + + IDEA 2018。
図3は、JdbcTemplate JDBC自体が軽量なパッケージなので、ストアドプロシージャを呼び出すと、「似ているJDBCは、ストアドプロシージャ/関数を呼び出します。」
図4は、テストを容易にするために、事前にデータの準備:従業員のテーブルとテストデータの部門テーブルを準備します
Oracleドライバのダウンロード
1、オープンソースのMySQLとは異なり、オラクル料、通常は成功したオラクルからダウンロードすることはできませんが、上記のMaven中央リポジトリに依存している Oracleはダウンロードのみに公式サイトに直接行くことができます:
<!-- https://mvnrepository.com/artifact/com.oracle.jdbc/ojdbc8 -->
<!-- oracle 官网提供的驱动依赖,通常都会下载失败,需要手动在本地仓库进行 mvn install 安装-->
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency>
1.6 JDK、一致ojdbc6 ojdbc8 1.8一致JDKを、ojdbc10一致10等をJDK、およびojdbc14一致がJDK1.4です。
2、道を解決:、以下の(実効プロテスト)として、そこにダウンロードして、いくつかが利用できる共有するのが良い人や組織があり、ネットワークに依存して同等の達人の公式ウェブサイト:
<!-- https://mvnrepository.com/artifact/com.github.noraui/ojdbc8 -->
<!--这是网络上的雷锋提供的开源 ojdbc8 驱动,功能与官网的是一样的,专门用于替代 Oracle 官网 maven 下载失败-->
<dependency>
<groupId>com.github.noraui</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency>
3、道を解決:あなたは、Mavenの中央リポジトリojdbcドライブからダウンロードすることはできませんが、JARパッケージOracleの公式サイトから直接ダウンロードすることができますが。
3.1、で始まるダウンロードする公式サイトojdbc8.jar パッケージ:https://www.oracle.com/database/technologies/jdbc-ucp-122-downloads.html
Oracleの公式サイトから家にそれらをダウンロードすることはありませんので、アカウントが存在しない場合、あなたは、登録無料のドライバをダウンロードする必要があり、あなたは、ログインする必要があるものです。
3.3は、次のように使用したプロジェクトを展開するコマンドをインストールMVN、それが自動的にローカル倉庫に格納されます。
mvn install:install-file -DgroupId=com.oracle.jdbc -DartifactId=ojdbc8 -Dversion=12.2.0.1 -Dpackaging=jar -DgeneratePom=true -Dfile=C:\Users\Think\Downloads\ojdbc8.jar
-DgroupId:groupIdをカスタマイズすることができ、指定した値が、人々の公式ウェブサイトへの勧告と整合が
-DartifactId:値がたartifactIdを指定し、あなたが勧告をカスタマイズできるの公式サイトに他の人と一致している
-Dversion:指定された値のバージョン、彼がかもしれません定義され、それはまた、バージョン番号が見ることができるMANIFEST.MFファイルオープンojdbc8.jarからも入手できる同じ公式サイト、と人々に推奨され
、このようなJAR、WARパッケージとして、パッケージの種類を指定します。-Dpackaging
-DgeneratePom:かどうかを指定生成されたpom.xmlファイルは、それが生成する指定
のjarパッケージファイルのパスを展開する必要性を:-Dfile
Oracleデータ・ソースの構成
1、次のコードの準備を開始する前に、グローバルコンフィギュレーション・ファイルに配置されたデータ・ソースを指定します。
#数据源配置
spring:
profiles: oracleDb
datasource:
username: hnbs_3
password: 1
driverClassName: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL
その他の設定項目は、公式ウェブサイトを参照することができますhttps://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#common-application-properties
または:org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.java
戻り値ストアドプロシージャ呼び出しを実行しません
1、Mysqlの「ある存在する場合は、表のテーブル名をドロップテーブルが存在する削除操作」時にのみ、Oracleと裁判官が存在しない場合は、テーブルが存在しない場合、それは、直接削除され、「表のドロップテーブル」にし私は文句を言うでしょう、
2は、ここではこの問題を解決するために、ストアドプロシージャを使用して、次の関数を準備するためのOracleデータベースのストアドプロシージャをされて、テーブルが既に存在する場合は、パラメータテーブル名として渡され、それを削除、または動作しない復帰せずに、ストアドプロシージャを。
--表名作为参数,如果表已经存在,则删除它。
create or replace procedure pro_drop_table_by_name(tableName in user_tables.TABLE_NAME%type)
is
flag number := 0; --表是否存在的表示,大于0表示表已经存在
begin
--user_tables 是系统定义的视图,可以查看当前用户下的所有表信息,表中的表名区分大小写,而且是大写
select count(1) into flag from user_tables where table_name = upper(tableName) ;
if flag > 0 then
execute immediate 'drop table '|| tableName ;--如果表已经存在,则删除它
end if;
end;
-- 数据库中调用存储过程:call pro_drop_table_by_name('student');
注:ここでは、データの整合性を確保するために、データテーブルが削除された場合、それは別のテーブルで参照されている場合は削除するときに、あなたはエラーになりますされ削除し、カスケードしませんでした
/**
* 删除表
* http://localhost:8080/emp/dropTable?tableName=emp
* http://localhost:8080/emp/dropTable?tableName=dept
* emp 员工表引用了 dept 部门表,如果先删除 dept 表,其中有数据被 emp 表引用,则删除时报错:
* oracle.jdbc.OracleDatabaseException: ORA-02449: 表中的唯一/主键被外键引用
*
* @param tableName
* @return
*/
@GetMapping("emp/dropTable")
public String dropTableByName(@RequestParam String tableName) {
JsonObject jsonObject = new JsonObject();
try {
//sql 和在数据库中完全一样
String sql = "call pro_drop_table_by_name('" + tableName + "')";
jdbcTemplate.execute(sql);
jsonObject.addProperty("code", 200);
jsonObject.addProperty("message", sql);
} catch (DataAccessException e) {
logger.error(e.getMessage(), e);
jsonObject.addProperty("code", 500);
jsonObject.addProperty("message", e.getMessage());
}
return jsonObject.toString();
}
単一の戻り値ストアドプロシージャ呼び出しを実行
次のように製造プロセスに格納されている1、Oracleデータベースです。
--表名作为参数,同时指定返回参数,如果表名存在,则返回 1,不存在返回 0
create or replace procedure pro_check_table_by_name(tableName in user_tables.TABLE_NAME%type, ifExists out number) is
begin
--user_tables 是系统定义的视图,可以查看当前用户下的所有表信息,表中的表名区分大小写,而且是大写
select count(1) into ifExists from user_tables where table_name = upper(tableName) ;
end;
-- 数据库中调用存储过程:
declare
tableName varchar2(30) := 'demp'; //被检查的表名
ifExists number; //返回参数
begin
pro_check_table_by_name(tableName,ifExists);
dbms_output.put_line(ifExists);//打印返回值
end;
2、(CallableStatementCreator CSC、CallableStatementCallback実行 <T>アクション)をストアドプロシージャ「下位の呼び出しであるJDBCは、ストアドプロシージャ/関数を呼び出すので、正確に同じことを書くことjava.sql.CallableStatementのCallableStatementCreatorを作成するには、呼び出しを行うとCallableStatementCallbackでの戻り値を取得するには、」 。
/**
* 检查某个表在数据库中是否已经存在,存在时返回1,否则返回0
* http://localhost:8080/emp/checkTableByName?tableName=emp
*
* @param tableName
* @return
*/
@GetMapping("emp/checkTableByName")
public Integer checkTableByName(@RequestParam String tableName) {
Integer execute = (Integer) jdbcTemplate.execute(new CallableStatementCreator() {
//创建可回调语句,方法里面就是纯 jdbc 创建调用存储的写法
@Override
public CallableStatement createCallableStatement(Connection connection) throws SQLException {
//存储过程调用 sql,通过 java.sql.Connection.prepareCall 获取回调语句
String sql = "call pro_check_table_by_name(?,?)";
CallableStatement callableStatement = connection.prepareCall(sql);
//设置第一个占位符参数值,传入参数。参数索引从1开始
callableStatement.setString(1, tableName);
//注册第二个参数(返回值)的数据类型
callableStatement.registerOutParameter(2, OracleTypes.INTEGER);
return callableStatement;
}
}, new CallableStatementCallback<Object>() {
//正式调用存储过程以及处理返回的值.
@Override
public Object doInCallableStatement(CallableStatement callableStatement) throws SQLException {
//执行调用存储过程
callableStatement.execute();
//参数索引从1开始,获取村存储过程的返回值.
return callableStatement.getInt(2);
}
});
return execute;
}
ストアド・プロシージャ・コールを実行すると、結果セットを返します
次のように図1に示すように、格納されたデータを作成します。
--创建存储过程,用于分页查询
--传入参数:pageNo 查询的页码,pageSize 每页的条数;输出参数:vrows 使用一个引用游标用于接收多条结果集。普通游标无法做到,只能使用引用游标
create or replace procedure pro_query_emp_limit(pageNo in number,pageSize in number,vrows out sys_refcursor) is
begin
--存储过程中只进行打开游标,将 select 查询出的所有数据放置到 vrows 游标中,让调用着进行获取
open vrows for select t.empno,t.ename,t.job,t.mgr,t.hiredate,t.sal,t.comm,t.deptno from (select rownum r,t1.* from emp t1) t
where t.r between ((pageNo-1) * pageSize+1) and pageNo * pageSize;
end;
--数据库中使用引用游标读取上面的存储过程返回的值。下面只是加深理解,和 java 调用无关
declare
vrows sys_refcursor ;--声明引用游标
vrow emp%rowtype; --定义变量接收遍历到的每一行数据
begin
pro_query_emp_limit(5,3,vrows);--调用存储过程
loop
fetch vrows into vrow; -- fetch into 获取游标的值
exit when vrows%notfound; -- 如果没有获取到值,则退出循环
dbms_output.put_line('姓名:'|| vrow.ename || ' 薪水:'|| vrow.sal);
end loop;
end;
図2に示すように、上記呼び出し、返された結果は、基本的に同じで選び出し、差は、ResultSetに返される結果セットの結果です。
/**
* 存储过程实现分页查询,传入页码和条数即可进行分页返回
* http://localhost:8080/emp/pageQuery?pageNo=2&pageSize=5
*
* @param pageNo 页码
* @param pageSize 每页显示的条数
* @return
*/
@GetMapping("emp/pageQuery")
public List pageQuery(@RequestParam Integer pageNo, @RequestParam Integer pageSize) {
List execute = (List) jdbcTemplate.execute(new CallableStatementCreator() {
//创建可回调语句,方法里面就是纯 jdbc 创建调用存储的写法
@Override
public CallableStatement createCallableStatement(Connection connection) throws SQLException {
//存储过程调用 sql,通过 java.sql.Connection.prepareCall 获取回调语句,sql 外围可以花括号括起来
String sql = "{call pro_query_emp_limit(?,?,?)}";
CallableStatement callableStatement = connection.prepareCall(sql);
//设置第占位符参数值
callableStatement.setInt(1, pageNo);
callableStatement.setInt(2, pageSize);
//输出参数类型设置为引用游标
callableStatement.registerOutParameter(3, OracleTypes.CURSOR);
return callableStatement;
}
}, new CallableStatementCallback<Object>() {
//正式调用存储过程以及处理返回的值.
@Override
public Object doInCallableStatement(CallableStatement callableStatement) throws SQLException {
//存储返回结果
List<Map<String, Object>> resultMapList = new ArrayList<>(8);
//遍历时临时对象
Map<String, Object> temp;
//执行调用存储过程,将结果转为 java.sql.ResultSet 结果集
callableStatement.execute();
ResultSet resultSet = (ResultSet) callableStatement.getObject(3);
//遍历结果集
while (resultSet.next()) {
temp = new HashMap<>(8);
//根据字段名称取值
temp.put("empno", resultSet.getInt("empno"));
temp.put("ename", resultSet.getString("ename"));
temp.put("job", resultSet.getString("job"));
temp.put("mgr", resultSet.getInt("mgr"));
temp.put("hiredate", resultSet.getDate("hiredate"));
temp.put("sal", resultSet.getFloat("sal"));
resultMapList.add(temp);
}
return resultMapList;
}
});
return execute;
}
callメソッドは、ストアドプロシージャを呼び出します
1、それはあったが、開口前記コールストアドプロシージャ、関連する機能のステートメントを実行するための特別の方法。呼び出し方法は唯一のあなたは、変換の結果を気にしないことができたCallableStatementを作成する必要があり、さらにパッケージに基づいて実行するために結果を返します。
図2に示すように、各シーケンスSqlParameterプレースホルダパラメータにその対応の、コールバックCallableStatementCallbackリスト<SqlParameter>を使用するexexute。
SqlParameter 表示存储过程的传入参数,可以不指定参数名称,但是必须指定参数类型 SqlOutParameter 表示存储过程的输出参数,必须指定名称和类型,名称自定义即可,会被作为返回值存放在 map 中
3、代わりに上記の機能を達成するために以下のメソッドを呼び出して、データベースのテーブルが既に存在しているチェックするストアドプロシージャを使用して、それ以外の場合は、呼び出しメソッド呼び出しを使用して、0を返し、戻り1が存在します。
/**
* 存储过程检查某个表在数据库中是否已经存在,存在时返回1,否则返回0,使用 call 方法进行调用
* http://localhost:8080/emp/callCheckTableByName?tableName=emp
*
* @param tableName
* @return
*/
@GetMapping("emp/callCheckTableByName")
@SuppressWarnings("all")
public Map<String, Object> callCheckTableByName(@RequestParam String tableName) {
//SqlParameter 表示存储过程的传入参数,可以不指定参数名称,但是必须指定参数类型
//SqlOutParameter 表示存储过程的输出参数,必须指定名称和类型,名称自定义即可,会被作为返回值存放在 map 中
List<SqlParameter> sqlParameterList = new ArrayList<>(4);
sqlParameterList.add(new SqlParameter(OracleTypes.VARCHAR));
sqlParameterList.add(new SqlOutParameter(tableName, OracleTypes.NUMBER));
//call 方法在 execute 的基础上对返回结果进行进一步的封装,只需要创建 CallableStatement
//List<SqlParameter> 中的每一个 SqlParameter 按顺序对应占位符参数
//返回的 map 包含返回参数
Map<String, Object> call = jdbcTemplate.call(new CallableStatementCreator() {
@Override
public CallableStatement createCallableStatement(Connection connection) throws SQLException {
//存储过程调用 sql,通过 java.sql.Connection.prepareCall 获取回调语句,sql 外围可以花括号括起来
String sql = "{call pro_check_table_by_name(?,?)}";
CallableStatement callableStatement = connection.prepareCall(sql);
//设置第一个占位符参数值,传入参数。参数索引从1开始
callableStatement.setString(1, tableName);
//注册第二个参数(返回值)的数据类型,oracle.jdbc.OracleTypes 中定义了全部的数据类型常量
callableStatement.registerOutParameter(2, OracleTypes.INTEGER);
return callableStatement;
}
}, sqlParameterList);
return call;
}
4、カーソルを使用するための呼び出しは、はるかに便利値を所有することはもはや必要を返さない、そしてそれは、自動的に推奨される方法を変換されます後、ストアドプロシージャ呼び出しページングクエリメソッド呼び出しを使用して:
/**
* 使用 call 方法调用存储过程进行分页查询,推荐方式
* http://localhost:8080/emp/callPageQuery?pageNo=2&pageSize=5
*
* @param pageNo
* @param pageSize
* @return
*/
@GetMapping("emp/callPageQuery")
@SuppressWarnings("all")
public List<Map<String, Object>> callPageQuery(@RequestParam Integer pageNo, @RequestParam Integer pageSize) {
//设置存储过程参数
//SqlParameter 表示存储过程的传入参数,可以不知道参数名称,但是必须指定参数类型
//SqlOutParameter 表示存储过程的输出参数,必须指定名称和类型,名称自定义即可,会被作为返回值存放在 map 中
List<SqlParameter> sqlParameterList = new ArrayList<>(4);
sqlParameterList.add(new SqlParameter(OracleTypes.NUMBER));
sqlParameterList.add(new SqlParameter(OracleTypes.NUMBER));
sqlParameterList.add(new SqlOutParameter("resultSet", OracleTypes.CURSOR));
//使用了 call 之后对于返回的游标就方便多了,不再需要自己一个一个取值了,它会自动进行转换
//call 的 key 会是 resultSet,然后它的值会是一个 List<Map>,自动转换好了
Map<String, Object> call = jdbcTemplate.call(new CallableStatementCreator() {
//创建可回调语句,方法里面就是纯 jdbc 创建调用存储的写法
@Override
public CallableStatement createCallableStatement(Connection connection) throws SQLException {
//存储过程调用 sql,通过 java.sql.Connection.prepareCall 获取回调语句,sql 外围可以花括号括起来
String sql = "{call pro_query_emp_limit(?,?,?)}";
CallableStatement callableStatement = connection.prepareCall(sql);
//设置第占位符参数值
callableStatement.setInt(1, pageNo);
callableStatement.setInt(2, pageSize);
//输出参数类型设置为引用游标
callableStatement.registerOutParameter(3, OracleTypes.CURSOR);
return callableStatement;
}
}, sqlParameterList);
//没有值时就是空 list,不会控制在异常
List<Map<String, Object>> dataList = (List<Map<String, Object>>) call.get("resultSet");
return dataList;
}