Skip to content

Commit 4b2d820

Browse files
Merge branch 'main' into ws-ocictl
2 parents fe3da37 + 70c5f97 commit 4b2d820

File tree

6 files changed

+314
-0
lines changed

6 files changed

+314
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>swierzy.oraclejdbc23newfeatures</groupId>
8+
<artifactId>OracleJDBC23cNewFeatures</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<maven.compiler.source>18</maven.compiler.source>
13+
<maven.compiler.target>18</maven.compiler.target>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
drop table if exists test;
2+
create table test ( id number(10) primary key,
3+
timestamp# date,
4+
val varchar2(2000));
5+
6+
drop sequence if exists test_seq;
7+
create sequence test_seq;
8+
9+
10+
create or replace trigger test_tr
11+
before insert on test for each row
12+
begin
13+
select test_seq.nextval
14+
into :new.id;
15+
16+
:new.timestamp# := sysdate;
17+
end;
18+
/
19+
20+
insert into test(val) values (DBMS_RANDOM.STRING('a',2000));
21+
22+
commit;
23+
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package swierzy.oraclejdbc23newfeatures;
2+
import java.util.concurrent.*;
3+
import java.util.*;
4+
5+
// Subscriber class used in Main.reactiveCallsDemo to demonstrate reactive call to INSERT statement
6+
7+
public class DMLSubscriber<Long> implements Flow.Subscriber<Long> {
8+
private Flow.Subscription subscription;
9+
CountDownLatch latch;
10+
11+
public DMLSubscriber(CountDownLatch latch) {
12+
super();
13+
this.latch = latch;
14+
}
15+
16+
// onSubscribe is begin called in the background when the subscriber is being subsribed to a publisher
17+
@Override
18+
public void onSubscribe(Flow.Subscription subscription) {
19+
this.subscription = subscription;
20+
subscription.request(1L);
21+
}
22+
23+
// onNext is begin called in the background when publisher propagates a new value
24+
@Override
25+
public void onNext(Long item) {
26+
System.out.println("DMLSubscriber.onNext: Number of rows processed : " + item);
27+
}
28+
29+
@Override
30+
public void onError(Throwable t) {
31+
t.printStackTrace();
32+
latch.countDown();
33+
}
34+
35+
@Override
36+
public void onComplete() {
37+
System.out.println("DMLSubscriber.onComplete: DML statement completed succesfully.");
38+
latch.countDown();
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package swierzy.oraclejdbc23newfeatures;
2+
import java.sql.*;
3+
import oracle.jdbc.*;
4+
5+
import java.util.UUID;
6+
import java.util.concurrent.*;
7+
import oracle.rsi.*;
8+
import java.time.*;
9+
10+
/*
11+
main application class
12+
it uses two additional subscriber classes
13+
1. DMLSubscriber as a subscriber for the INSERT statement being called asynchronously
14+
2. QuerySubscriber as a subscriber for the SELECT statement being called asynchronously
15+
it provides two methods demonstrating JDBC 23c new features
16+
1. reactiveCallsDemo() which demonstrates Oracle JDBC 23c driver support for reactive programming
17+
2. streamsIngestionDemo() which demonstrates Oracje JDBC 23c driver support for streams ingestion
18+
*/
19+
public class Main {
20+
private static CountDownLatch latch = new CountDownLatch(2);
21+
/*
22+
reactiveCallsDemo: method, which demonstrates reactive programming support
23+
provided by Oracle23c JDBC driver
24+
*/
25+
public static void reactiveCallsDemo() throws Exception {
26+
// database connection used by psDML and psQuery PreparedStatement objects
27+
Connection con;
28+
// prepared statements used to call INSERT and SELECT SQL statements in NOWAIT mode
29+
PreparedStatement psDML, psQuery;
30+
31+
// database connection creation
32+
System.out.println("Main.reactiveCallsDemo: connecting to the database.");
33+
con = DriverManager.getConnection(
34+
"<db_url>",
35+
"<db_username>",
36+
"<db_password>");
37+
System.out.println("Main.reactiveeCallsDemo: Connected to the database");
38+
39+
// prepared statements for INSERT and SELECT calls creation
40+
psDML = con.prepareStatement("INSERT INTO TEST (VAL)"+
41+
"SELECT DBMS_RANDOM.STRING('a',2000) "+
42+
"FROM TEST");
43+
44+
psQuery = con.prepareStatement("SELECT COUNT(*) FROM TEST");
45+
46+
/*
47+
INSERT and SELECT statements reactive calls
48+
notes:
49+
1. reactive methods are implemented ONLY as Oracle extensions to the standard JDBC interfaces
50+
- it is not possible to call them without using OraclePrepareStatement class directly
51+
2. traditional JAVA casting due to Oracle official documentation is not recommended
52+
- it is needed to use class.unwrap method to get the OraclePreparedStatement object
53+
*/
54+
Flow.Publisher<OracleResultSet> fpQuery = psQuery.unwrap(OraclePreparedStatement.class).executeQueryAsyncOracle();
55+
fpQuery.subscribe(new QuerySubscriber(latch));
56+
System.out.println("Main.reactiveCallsDemo: SELECT started in NOWAIT mode");
57+
58+
Flow.Publisher<Long> fpDML = psDML.unwrap(OraclePreparedStatement.class).executeUpdateAsyncOracle();
59+
fpDML.subscribe(new DMLSubscriber(latch));
60+
System.out.println("Main.reactiveCallsDemo: INSERT started in NOWAIT mode");
61+
/*
62+
As this demo uses reactive methods, the execution does not wait for the end of SQL statements
63+
reactiveCallsDemo() execution is completed BEFORE completion of INSERT and SELECT statements reactive execution
64+
*/
65+
System.out.println("Main.reactiveCallsDemo: end of method and return to Main.main.");
66+
67+
}
68+
69+
/*
70+
stramsIngestionDemo(): method, which demonstrates support for Streams Ingestion
71+
provided by Oracle 23c JDBC driver
72+
*/
73+
public static void streamsIngestionDemo() throws Exception {
74+
String value;
75+
76+
// auxiliary, traditional database connection used to check number of rows in TEST table
77+
Connection conAux = DriverManager.getConnection(
78+
"<db_url>",
79+
"<db_username>",
80+
"<db_password>");
81+
82+
// auxiliary PreparedStatement object used to check number of rows in TEST table
83+
PreparedStatement psAux = conAux.prepareStatement("SELECT COUNT(*) FROM TEST");
84+
// auxiliary ResultSet object used to check number of rows in TEST table
85+
ResultSet rsAux;
86+
int countInt;
87+
88+
/*
89+
Streams Ingestion additionally to traditional JDBC parameters, like
90+
connection string, username and password, requires providing the following data
91+
1. ExecutorService: pool of threads responsible for execution
92+
2. buffer size
93+
3. interval (in seconds) between pushing the data into the database
94+
4. names of target schema, table and columns
95+
*/
96+
97+
System.out.println("Main.streamsIngestDemo: connecting to the database.");
98+
ExecutorService es = Executors.newFixedThreadPool(5);
99+
ReactiveStreamsIngestion rs = ReactiveStreamsIngestion
100+
.builder()
101+
.url("<db_url>")
102+
.username("<db_username>")
103+
.password("<db_password>")
104+
.executor(es)
105+
.bufferRows(60)
106+
.bufferInterval(Duration.ofSeconds(2))
107+
.schema("<db_username>")
108+
.table("TEST")
109+
.columns(new String[] {"VAL"})
110+
.build();
111+
System.out.println("Main.streamsIngestiondemo: connected to the database");
112+
113+
// Streams Ingestion uses reactive calls and provides its own publisher and subscriber
114+
PushPublisher<Object[]> pushPublisher = ReactiveStreamsIngestion.pushPublisher();
115+
pushPublisher.subscribe(rs.subscriber());
116+
System.out.println("Main.streamsIngestionDemo: ReactiveStreamsIngestion configured.");
117+
118+
for (int i = 1; i <= 60; i++) {
119+
// generation of a random value
120+
value = UUID.randomUUID().toString();
121+
// pushing the data into the database
122+
pushPublisher.accept(new Object[] {value});
123+
System.out.println("Main.streamsIngestionDemo: A random string #"+i+" has been generated and pushed into the database stream.");
124+
125+
/*
126+
Auxiliary PreparedStatement object got from the auxiliary, separate database connection,
127+
checks the number of rows in the TEST table
128+
*/
129+
rsAux = psAux.executeQuery();
130+
rsAux.next();
131+
countInt = rsAux.getInt(1);
132+
System.out.println("Main.streamsIngestionDemo: Number of rows in TEST table: "+countInt);
133+
Thread.sleep(200);
134+
}
135+
136+
// closing the stream and the executor service
137+
pushPublisher.close();
138+
rs.close();
139+
es.shutdown();
140+
System.out.println("Main.streamsIngestionDemo: end of method and return to Main.main.");
141+
}
142+
public static void main(String[] args) {
143+
try {
144+
System.out.println("Main.main: begin of the demonstration");
145+
Class.forName("oracle.jdbc.driver.OracleDriver");
146+
reactiveCallsDemo();
147+
streamsIngestionDemo();
148+
System.out.println("Main.main: waiting for DML and Query subscribers");
149+
latch.await();
150+
System.out.println("Main.main: end of the demonstration");
151+
}
152+
catch (Exception e) {
153+
e.printStackTrace();
154+
}
155+
}
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package swierzy.oraclejdbc23newfeatures;
2+
import oracle.jdbc.*;
3+
import java.sql.*;
4+
import java.util.LinkedList;
5+
import java.util.List;
6+
import java.util.concurrent.*;
7+
8+
// Subscriber class used in Main.reactiveCallsDemoo to demonstrate reactive call to SELECT statement
9+
public class QuerySubscriber<OracleResultSet> implements Flow.Subscriber<OracleResultSet> {
10+
private Flow.Subscription subscription;
11+
private CountDownLatch latch;
12+
public QuerySubscriber(CountDownLatch latch) {
13+
super();
14+
this.latch = latch;
15+
}
16+
17+
// onSubscribe is begin called in the background when the subscriber is being subsribed to a publisher
18+
public void onSubscribe(Flow.Subscription subscription) {
19+
this.subscription = subscription;
20+
subscription.request(Long.MAX_VALUE);
21+
}
22+
23+
// onNext is begin called in the background when publisher propagates a new value
24+
@Override
25+
public void onNext(OracleResultSet item) {
26+
try {
27+
((ResultSet) item).next();
28+
System.out.println("QuerySubscriber.onNext: Number of rows in TEST table : "+((ResultSet) item).getNString(1));
29+
}
30+
catch (Exception e) {
31+
e.printStackTrace();
32+
}
33+
}
34+
35+
@Override
36+
public void onError(Throwable t) {
37+
t.printStackTrace();
38+
latch.countDown();
39+
}
40+
41+
@Override
42+
public void onComplete() {
43+
System.out.println("QuerySubscriber.onComplete: SELECT statement completed succesfully.");
44+
latch.countDown();
45+
}
46+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# OracleJDBC23cNewFeatures
2+
This repo contains working code of examples demonstrating Reactive API support provided in Oracle JDBC Driver 23c
3+
Before running the code there is need to provide in the code
4+
1. database connection string - it should point into a 21c or 23c database
5+
2. username
6+
3. password
7+
8+
Also it is needed to create database structures (a table, a sequence and a trigger) used by this demo.
9+
It can be done by executing jdb23cnfdemotable.sql script from, for example, SQL Developer, SQLcl or SQL*Plus
10+
To build and run this project there's need to use Maven (POM file contains all the dependencies, including JDBC driver)
11+
12+
13+
Review Date: 28.01.2024
14+
15+
16+
### Documentation
17+
18+
- [Oracle JDBC23c Driver Developer's Guide](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/index.html#Oracle%C2%AE-Database)
19+
20+
### Blogs
21+
22+
- [Oracle 23c JDBC driver: support for reactive programming](https://blogs.oracle.com/coretec/post/oracle-23c-jdbc-driver-support-for-reactive-programming)
23+
24+
25+
# License
26+
27+
Copyright (c) 2023 Oracle and/or its affiliates.
28+
29+
Licensed under the Universal Permissive License (UPL), Version 1.0.
30+
31+
See [LICENSE](https://github.com/oracle-devrel/technology-engineering/blob/main/LICENSE) for more details.

0 commit comments

Comments
 (0)