问题
I am testing an spring boot application that reads/writes data to an Oracle DB. This Oracle DB has Oracle packages and in those packages procedures. At some point, the spring boot application calls this procedure via a Entity Repository as follows
@Repository
public interface StudentRepository extends JpaRepository<Student, String> {
@Modifying
@Query(value = "begin sch1.STUDENT_PACKAGE.Set_Grades_To_A('A'); end;", nativeQuery = true)
public void setStudentGradeToA();
}
So, it uses a native query to make the call to to a procedure Set_GradesToA in the STUDENT_PACKAGE package of the sch1 schema.
I am currently testing the functionality of the Spring Boot application and NOT the integration between it and the Oracle database. Therefore, I have decided to use an in-memory database (H2) (with the Oracle compatibility option) to replace the Oracle DB for now. BUT how can I fake out these java package procedures?
I have tried creating an alias in my schema.sql (or data.sql) as follows:
CREATE SCHEMA if not exists sch1;
CREATE ALIAS sch1.STUDENT_PACKAGE AS $$ void Set_Grades_To_A(String s) { new String(s); } $$;
I really don't care what is inside the Set_Grades_To_A procedure what I care about is how to define it.
When I create the alias as above, I'm still getting a Syntax Error.
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "BEGIN SCH1[*].STUDENT_PACKAGE.Set_Grades_To_A('A'); END; "; SQL statement:
begin sch1.STUDENT_PACKAGE.Set_Grades_To_A('A'); end; [42000-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.message.DbException.getSyntaxError(DbException.java:203)
I guess I have two questions:
How can I fake out a stored procedure inside an Oracle package in the schema sch1?
Why am I getting the Syntax Error above?
回答1:
Here is what I did.
Question #2: To answer this question I had to change the native query as follows
@Repository
public interface StudentRepository extends JpaRepository<Student, String> {
@Modifying
@Query(value = "call sch1.STUDENT_PACKAGE.Set_Grades_To_A('A')", nativeQuery = true)
public void setStudentGradeToA();
}
Question #1: Three things are involved to answer this. Now that I had changed the native query as above I got a different error:
Caused by: org.h2.jdbc.JdbcSQLException: Database "sch1" not found; SQL statement:
call sch1.STUDENT_PACKAGE.Set_Grades_To_A('A') [90013-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
It was looking for a database called sch1. It seems like the pattern used to call a stored procedure in H2 is database.schema.procedure_name. Since I don't care what that procedure actually does I was able to fake this out by creating a database called sch1 a schema called STUDENT_PACKAGE and the procedure name Set_Grades_To_A
To create the in memory database, you have to set the following property spring.datasource.url in the application.properties file.
Create the
sch1database as followsspring.datasource.url=jdbc:h2:mem:sch1;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=Oracle;INIT=CREATE SCHEMA IF NOT EXISTS first_schema. Notice the database name issch1Create the
STUDENT_PACKAGEschema by adding this\\;CREATE SCHEMA IF NOT EXISTS STUDENT_PACKAGEto the end of thespring.datasource.url. This adds a second schema calledSTUDENT_PACKAGE. The property should look like thisspring.datasource.url=jdbc:h2:mem:sch1;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=Oracle;INIT=CREATE SCHEMA IF NOT EXISTS first_schema\\;CREATE SCHEMA IF NOT EXISTS STUDENT_PACKAGECreate a the
Set_Grades_To_Astored procedure by adding this to your schema.sqlCREATE ALIAS STUDENT_PACKAGE.Set_Grades_To_A AS $$ void setGradesToA(String s) { new StringBuilder(s).reverse().toString(); } $$;
来源:https://stackoverflow.com/questions/57062428/how-to-define-oracle-package-procedure-in-h2-for-testing