Is there some trick to update an Oracle CLOB with Mybatis 3? - oracle

I am updating a CLOB column in my Oracle database. The parameterized SQL looks like it is executing correctly without error, but when I run a select to see the change, it has not been updated. Note: MyBatis 3 is built using JDBC Parameterized Queries, so those rules also apply.
MyBatis Mapping:
<update id="updateRSA103RequestData" parameterType="com.company.domain.RSA103XMLData" flushCache="true">
update
RSA_SUBMIT_DATA
set TXLIFE_REQUEST = #{request}
where RSA_SUBMIT_QUEUE_ID = #{id}
</update>
Runtime Logs:
2012-07-13 12:35:26,728 DEBUG Connection:Thread main: - ooo
Connection Opened 2012-07-13 12:35:26,837 DEBUG
PreparedStatement:Thread main: - ==> Executing: update
RSA_SUBMIT_DATA set TXLIFE_REQUEST = ? where RSA_SUBMIT_QUEUE_ID = ?
2012-07-13 12:35:26,837 DEBUG PreparedStatement:Thread main: - ==>
Parameters: testasdfasdf(String), 51(Integer) 2012-07-13 12:35:27,024
DEBUG Connection:Thread main: - xxx Connection Closed
Select query after change:
select *
from RSA_SUBMIT_DATA
where RSA_SUBMIT_QUEUE_ID = 51
RSA_SUBMIT_QUEUE_ID | TXLIFE_REQUEST | TXLIFE_RESPONSE
51 | originalString | resultString
Mapper invocation:
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
log.debug("autoCommit: " + sqlSessionFactory.getConfiguration().getEnvironment().getDataSource().getConnection().getAutoCommit());
PolicyTransactionMapper policyTransactionDAO = sqlSession
.getMapper(PolicyTransactionMapper.class);
RSA103XMLData xmlData = new RSA103XMLData();
xmlData.setId(rsaSubmitQueueID);
xmlData.setRequest(request);
policyTransactionDAO.updateRSA103RequestData(xmlData);
Any help is appreciated.

I don't think your SqlSession is opened with auto commit.
Per MyBatis User Guide, to use auto commit, try.
SqlSession sqlSession = sqlSessionFactory.openSession(true);
Also, your log statement is actually opening a new connection. See DataSourceUtils.getConnection vs DataSource.getConnection
This will probably return a different connection than what your mapper is using anyways.

Related

io.vertx.oracleclient.OracleException: Error : 1000, Position : 0, Sql = SET TRANSACTION ISOLATION LEVEL READ COMMITTED

I have one question regarding oracle cursors . Actually I upgraded my project to latest vert.x version and now I started to see some errors. I have one SQL Verticle which actively used and it throw exception after a while. You can see on below :
"io.vertx.oracleclient.OracleException: Error : 1000, Position : 0, Sql = SET TRANSACTION ISOLATION LEVEL READ COMMITTED, OriginalSql = SET TRANSACTION ISOLATION LEVEL READ COMMITTED, Error Msg = ORA-01000: maximum open cursors exceeded"
I am using withTransaction method belong to vertx-sql-client:4.2.7 and I am not sure whether I manage it myself or vertx manage. I expected that cursors already managed by vertx. Is there anybody who see such an error ? or Any comment ? Thanks in advance .
Also Any idea why vertx open cursor for sql "SET TRANSACTION ISOLATION LEVEL READ COMMITTED, OriginalSql = SET TRANSACTION ISOLATION LEVEL READ COMMITTED" and not close ?
Example code :
override suspend fun processItem(callback: Callback) {
pool.withTransaction { conn ->
conn.query("select * from TABLE where ROWNUM='1'") .execute()
}}

Is there any way to view the physical SQLs executed by Calcite JDBC?

Recently I am studying Apache Calcite, by now I can use explain plan for via JDBC to view the logical plan, and I am wondering how can I view the physical sql in the plan execution? Since there may be bugs in the physical sql generation so I need to make sure the correctness.
val connection = DriverManager.getConnection("jdbc:calcite:")
val calciteConnection = connection.asInstanceOf[CalciteConnection]
val rootSchema = calciteConnection.getRootSchema()
val dsInsightUser = JdbcSchema.dataSource("jdbc:mysql://localhost:13306/insight?useSSL=false&serverTimezone=UTC", "com.mysql.jdbc.Driver", "insight_admin","xxxxxx")
val dsPerm = JdbcSchema.dataSource("jdbc:mysql://localhost:13307/permission?useSSL=false&serverTimezone=UTC", "com.mysql.jdbc.Driver", "perm_admin", "xxxxxx")
rootSchema.add("insight_user", JdbcSchema.create(rootSchema, "insight_user", dsInsightUser, null, null))
rootSchema.add("perm", JdbcSchema.create(rootSchema, "perm", dsPerm, null, null))
val stmt = connection.createStatement()
val rs = stmt.executeQuery("""explain plan for select "perm"."user_table".* from "perm"."user_table" join "insight_user"."user_tab" on "perm"."user_table"."id"="insight_user"."user_tab"."id" """)
val metaData = rs.getMetaData()
while(rs.next()) {
for(i <- 1 to metaData.getColumnCount) printf("%s ", rs.getObject(i))
println()
}
result is
EnumerableCalc(expr#0..3=[{inputs}], proj#0..2=[{exprs}])
EnumerableHashJoin(condition=[=($0, $3)], joinType=[inner])
JdbcToEnumerableConverter
JdbcTableScan(table=[[perm, user_table]])
JdbcToEnumerableConverter
JdbcProject(id=[$0])
JdbcTableScan(table=[[insight_user, user_tab]])
There is a Calcite Hook, Hook.QUERY_PLAN that is triggered with the JDBC query strings. From the source:
/** Called with a query that has been generated to send to a back-end system.
* The query might be a SQL string (for the JDBC adapter), a list of Mongo
* pipeline expressions (for the MongoDB adapter), et cetera. */
QUERY_PLAN;
You can register a listener to log any query strings, like this in Java:
Hook.QUERY_PLAN.add((Consumer<String>) s -> LOG.info("Query sent over JDBC:\n" + s));
It is possible to see the generated SQL query by setting calcite.debug=true system property. The exact place where this is happening is in JdbcToEnumerableConverter. As this is happening during the execution of the query you will have to remove the "explain plan for"
from stmt.executeQuery.
Note that by setting debug mode to true you will get a lot of other messages as well as other information regarding generated code.

TKProf (Oracle event 10046) on Spring Boot/JDBC

I'm trying to start oracle tracing through invoking direct JDBC calls. I'm obtaining my connection from Spring (boot/jdbc). Then I run the TKProf commands through statements... execute the query and print to the log.
The 3 statements below are returning false. If I use this same statements through Intellij's console I will get the intended results and my *.trc file is properly generated.
try (final Connection connection = DataSourceUtils.getConnection(dataSource)) {
log.debug(query);
final Long maxCount = findMaxCount();
boolean traceIdSet = connection.createStatement().execute("ALTER SESSION SET TRACEFILE_IDENTIFIER = '" + traceId + "'");
boolean traceEnabled = connection.createStatement().execute("ALTER SESSION SET EVENTS '10046 trace name context forever, level 8'");
final PreparedStatement stmt = connection.prepareStatement(query);
map(consumer, stmt.executeQuery(query));
boolean traceIdOff = connection.createStatement().execute("ALTER SESSION SET EVENTS '10046 trace name context off'");
log.debug("|" + traceIdSet + "|" + traceEnabled + "|" + traceIdOff + "| ____________________ DONE __________________________");
} catch (SQLException e) {
log.error("Error Performing the Query", e);
}
It has to be something in my configuration... I mean, java thin driver can do it because I can do it over the IDE... so I have to be missing some other stuff, maybe a Spring Boot convention that I should change.
Could you please help, any input is valuable.
Thanks!
My bad, the real issue was that I wasn't getting proper response from...
SELECT value FROM v$diag_info
Where I couldn't found the trace file, but only some others...
Nevertheless the trc files are in place, so there is no problem with Spring Boot/JDBC for enabling TKProf.

Why does h2 ignore slf4j messages on the first connection when LOG is set?

See sample code & output below (with Slf4j/logback on stdout). I can't find any bug reports on this. I'm using h2 version 1.3.176 (last stable), in-memory mode. It doesn't seem to matter what value is set for the LOG (0, 1 or 2) but just has to be set.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class H2TraceTest {
public static void main(String[] args) throws SQLException {
System.out.println("Query connection 1");
Connection myConn = DriverManager.getConnection("jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4;LOG=2");
myConn.createStatement().execute("SELECT 1");
System.out.println("Query connection 2");
DriverManager.getConnection("jdbc:h2:mem:tracetest").createStatement().execute("SELECT 1");
System.out.println("Query connection 1 again");
myConn.createStatement().execute("SELECT 1");
System.out.println("End");
}
}
Output:
Query connection 1
Query connection 2
16:17:02.955 INFO h2database - jdbc[3]
/**/Connection conn2 = DriverManager.getConnection("jdbc:h2:mem:tracetest", "", "");
16:17:02.958 DEBUG h2database - jdbc[3]
/**/Statement stat2 = conn2.createStatement();
16:17:02.959 DEBUG h2database - jdbc[3]
/**/stat2.execute("SELECT 1");
16:17:02.959 INFO h2database - jdbc[3]
/*SQL #:1*/SELECT 1;
Query connection 1 again
End
I know that the H2 documentation says about TRACE_LEVEL_FILE: it affects all connections. But thats not (fully) correct:
Every connection keeps a lazy reference to the logging system. And if you change that with the special marker TRACE_LEVEL_FILE=4, then that reference isn't changed for all existing connections - but only for those who do their first logging after that change.
So if you use the connection string "jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4" everything is as expected, because your session will write no logging message before changing the logging system. Unfortunately the LOG=2 in jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4;LOG=2 is evaluated first, because both parameter are written into and read from an unordered Map. And because LOG=2 is generating a log statement, the reference to the log adapter (=4) is never applied to the current session. Only to the next one.
What can you do:
Use only "jdbc:h2:mem:tracetest;TRACE_LEVEL_FILE=4" - LOG=2 is the default anyway. If you need any other log mode you can use connection.createStatement().executeUpdate("SET LOG 1")
Add some default parameters to the connection string until the TRACE_LEVEL_FILE parameter is the first parameter in the map (not really reliable, as the order may depend on the VM)
Discard the first connection at once
Fill in a bug report and wait for the fix (or fix it yourself), as I think this is somehow a bug
I know this is an old question but here is a reliable way to do it (i.e. you can ensure that TRACE_LEVEL_FILE is set to 4 first:
String url = "jdbc:h2:mem:tracetest;INIT=SET TRACE_LEVEL_FILE=4\\;SET DB_CLOSE_DELAY=-1/* for example, i.e. do other stuff */";

SELECT FOR UPDATE not working with JDBC and Oracle

I've written a simple Java program, which opens a transaction, selects some records, does some logic and then updates them. I want the records to be locked so I used SELECT...FOR UPDATE.
The program works perfectly fine with MS SQL Server 2005, but in Oracle 10g the records are not locked!
Any idea why?
I create the connection as follow:
Connection connection = DriverManager.getConnection(URL, User, Password);
connection.setAutoCommit(false);
If I execute the SELECT..FOR UPDATE from Oracle SQL Developer client I can see that the records are locked, so I'm thinking it might be an issue with the JDBC driver rather than a database problem, but I couldn't find anything useful online.
These are the details of the JDBC driver I'm using:
Manifest-Version: 1.0
Implementation-Vendor: Oracle Corporation
Implementation-Title: ojdbc14.jar
Implementation-Version: Oracle JDBC Driver version - "10.2.0.2.0"
Implementation-Time: Tue Jan 24 08:55:21 2006
Specification-Vendor: Oracle Corporation
Sealed: true
Created-By: 1.4.2_08 (Sun Microsystems Inc.)
Specification-Title: Oracle JDBC driver classes for use with JDK14
Specification-Version: Oracle JDBC Driver version - "10.2.0.2.0"
Sorry, I cannot reproduce this behaviour. Exactly how are you running your SELECT ... FOR UPDATE queries in JDBC?
I have a table, locktest with the following data in it:
SQL> select * from locktest;
A B
---------- ----------
1 0
2 0
3 0
4 0
5 0
I also have this Java class:
import oracle.jdbc.OracleDriver;
import java.sql.*;
public class LockTest {
public static void main(String[] args) throws Exception {
DriverManager.registerDriver(new OracleDriver());
Connection c = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:XE", "user", "password");
c.setAutoCommit(false);
Statement stmt = c.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rSet = stmt.executeQuery(
"SELECT a, b FROM locktest FOR UPDATE");
while (rSet.next()) {
if (rSet.getInt(1) <= 3) {
rSet.updateInt(2, 1);
}
}
System.out.println("Sleeping...");
Thread.sleep(Long.MAX_VALUE);
}
}
When I run this Java class, it makes some updates to the table and then starts sleeping. It sleeps so that it keeps the transaction open and hence retains the locks.
C:\Users\Luke\stuff>java LockTest
Sleeping...
While this is sleeping, I try to concurrently update the table in SQL*Plus:
SQL> update locktest set b = 1 where a <= 3;
At this point, SQL*Plus hangs until I kill the Java program.

Resources