Set jdbc interceptor using DriverManager class - java

I am using DriverManager.getConnection(url, prop) to get the connection. I am trying to inject the jdbc interceptors using properties like below but it is not working.
Properties prop = new Properties();
...
prop.setProperty("jdbcInterceptors", "com.amazonaws.xray.sql.mysql.TracingInterceptor;");
However, when we try to do via datasource it is working.
import org.apache.tomcat.jdbc.pool.DataSource;
DataSource source = new DataSource();
source.setUrl("url");
source.setUsername("user");
source.setPassword("password");
source.setDriverClassName("com.mysql.jdbc.Driver");
source.setJdbcInterceptors("com.amazonaws.xray.sql.mysql.TracingInterceptor;");
Not sure what is wrong with DriverManager properties.

These interceptors are a feature of the Tomcat org.apache.tomcat.jdbc.pool.DataSourceProxy and its subclass org.apache.tomcat.jdbc.pool.DataSource. This is not a feature of JDBC itself, nor a feature of the JDBC driver you're using, so the only way to access it is through a Tomcat data source.
In short, it doesn't work with DriverManager because this feature doesn't exist in DriverManager.

Related

Mapping of JDBC connection string parameters to MyBatis properties

I am using mybatis-guice (MyBatisModule) to connect the Java application with the PostgreSQL database.
The connection parameters are sent to MyBatis as named properties (see an example here: https://mybatis.org/guice/jdbc-helper.html)
The MyBatis properties corresponding to the JDBC connection string postgresql://localhost/mydb?user=me&password=secret are:
final Properties properties = new Properties();
properties.setProperty("JDBC.host", "localhost");
properties.setProperty("JDBC.schema", "mydb");
properties.setProperty("JDBC.username", "me");
properties.setProperty("JDBC.password", "secret");
Names.bindProperties(binder, properties);
How to send other parameters of JDBC connection string to MyBatis?
For example, I need to use the following connection string: postgresql://localhost/mydb?user=me&password=secret&prepareThreshold=0, how could I send the attribute prepareThreshold=0 to MyBatis?
Following an example in the MyBatis docs, I tried to use
properties.setProperty("JDBC.prepareThreshold", "0");
but apparently it doesn't work.
Is it possible to use miscellaneous JDBC connection string parameters like prepareThreshold in the MyBatis Guice module?

How to set the jdbc ClientInfo in a MySQL DataSource

In Java with MySQL we want to add the jdbc ClientInfo to identify the source of each query. Currently we can do something like:
try(Connection connection = dataSource.getConnection()){
connection.setClientInfo("ApplicationName", "MyApp");
}
But I need to add it to every connection created and means checking all the source code for places where a new connection is created. I will like to set it to the DataSource level.
So far what works for me is to extends the DataSource with a custom overriden getConnection method that calls setClientInfo. This is not only a dirty workarround but datasource specific.
I have seen that mysql driver has ClientInfoProviders like the default com.mysql.cj.jdbc.CommentClientInfoProvider. A custom ClientInfoProvider can be configured like:
Properties properties = new Properties();
properties.setProperty(PropertyKey.clientInfoProvider.getKeyName(), "foo.bar.CustomClientInfoProvider");
properties.setProperty(APPLICATION_NAME, "MyApp");
HikariConfig dataSourceConfig = new HikariConfig();
dataSourceConfig.setDataSourceProperties(properties);
...
But it is only called if someone calls the getClientInfo in the connection anyway.
So I will like to know:
Is there support in the MySql driver to set the clientInfo in the DataSource just by setting properties?
If there is a way. How can it be done?
I think you can use AspectJ as a possible solution for it. You can create an aspect which will intercept calls of the DataSource.getConnection method and then call the setClientInfo method with configured parameters when the connection is established.

Create SqlSession from existing Connection directly

I'm working with existing Java code wherein there is an existing JDBC connection pooling mechanism on deployed systems and an already existing setup to get JDBC connections. I'd like to leverage this to create a MyBatis SqlSession object without creating a Configuration, DataSource, and other things
I have code that already creates a java.sql.Connection object is given the desired resource. I'd like to leverage this and get that SqlSession object and use MyBatis from that point onwards.
I don't want MyBatis to manage connection pooling, determining which data source to use, etc. Is this possible?
I'm afraid you can't avoid creation of the Configuration object. It is used by the internal mybatis machinery like executors. But even if you could it will not help you much. In this case you will need to implement most of Configuration functionality yourself so it does not make sense to do that.
You main goal is to be able to use SqlSessionFactory.openSession(Connection connection) method. To do this you need to have SqlSessionFactory. The easiest way for you is to create Configuration like it is descried in mybatis documentation:
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
// set properties to configuration here
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);
Now if your connection pool does implement DataSource you use it directly to create environment. If it does not you need to create an adapter around your pool which implements javax.sql.DataSource.
My solution is similar to Roman's above, but I needed to create an Oracle datasource. For various reasons, the connection needs to be created using the Class.forName type sequence
Class.forName("oracle.jdbc.driver.OracleDriver");
String connectionString = "jdbc:oracle:thin:#//yadayada";
String username = "myusername";
String password = "mypassword";
OracleDataSource oracleDataSource = new OracleDataSource();
oracleDataSource.setURL(connectionString);
oracleDataSource.setPassword(password);
oracleDataSource.setUser(username);
environment = new Environment("dev",transactionFactory,oracleDataSource);
configuration = new Configuration(environment);
configuration.addMappers("MyMybatisMapper");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
return sqlSessionFactory.openSession();
What I was missing was the OracleDataSource object.

HikariCP + Hibernate + MySql: warnings even when defining correct 'driverClassName' property

I'm having this problem with HikariCP and MySql in my maven project: a warning shows up saying:
Loading class 'com.mysql.jdbc.Driver'. This is deprecated. The new driver class is 'com.mysql.cj.jdbc.Driver'. The driver has automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
I want to get rid of this warning.
For that, I need to know why even having the maven MySql connector in its latest version and HikariCP configuration set to set the class com.mysql.cj.jdbc.Driver (which is the non-deprecated one) this warning still shows up.
Here it is the maven dependency in pom.xml:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
Then, I have this properties file called hikaricp-hibernate.properties
jdbcUrl=jdbc:mysql://localhost:3306/local_database
driverClassName=com.mysql.cj.jdbc.Driver
#user and password and other data omitted
Now, for the HibernateConfiguration I have:
package mypackage;
// ... imports
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
private static final String HIBERNATE_PROPERTIES = "/hikaricp-hibernate.properties";
#Bean(name = "hikariDataSource")
public DataSource dataSource() {
HikariConfig config = new HikariConfig(HIBERNATE_PROPERTIES);
HikariDataSource dataSource = new HikariDataSource(config);
return dataSource;
}
}
In the same class, I register as beans the LocalSessionFactoryBean and the TransactionManager, but the code does not matter here.
I also already checked the configuration in debug mode to see if the driverClassName is the one I have put and the answer is yes.
Therefore, the logs are shown even if registered correctly.
Also, HikariCP docs tells me to use the jdbcUrl configuration:
The MySQL DataSource is known to be broken with respect to network timeout support. Use jdbcUrl configuration instead.
Why?
Does jdbcUrl configuration triggers automatically the old Class (if yes, how can I override and avoid this?)? And then it seems that it is deprecated and searches for another one? Does it ignore my driverClassName config?
There's no issue with the code that's here - the key points being:
You're listing a dependency on the 8.* branch of the mysql connector, which contains the new JDBC driver
You're listing the new driver under driverClassName in your properties file
You're instantiating the HikariConfig correctly, with the properties that you're defining.
If the old driver is being loaded, it therefore isn't in this code - it's either with a separate application, or somewhere else in this application.

Does Cassandra JDBC provide a DataSource?

I have a large amount of legacy code that relies on being able to pass around a DataSource instead of a Connection object. I can see sample code for making a connection, ie:
Class.forName("org.apache.cassandra.cql.jdbc.CassandraDriver");
con = DriverManager.getConnection("jdbc:cassandra:root/root#localhost:9160/MyKeyspace");
However I can't see from the documentation any way to create a DataSource. Am I going to have to write my own DataSource to wrap the above code?
You can use BasicDataSource class of Apache Commons DBCP http://commons.apache.org/proper/commons-dbcp/ which is a DataSource implementation that can work with any JDBC driver. See usage example here http://www.kodejava.org/how-do-i-create-a-basicdatasource-object/
You can use the CassandraDataSource class.
https://code.google.com/a/apache-extras.org/p/cassandra-jdbc/source/browse/src/main/java/org/apache/cassandra/cql/jdbc/CassandraDataSource.java

Categories