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.
Related
I need to set SimpleDriverDataSource object in order to create datasource with MongoDB, however I am not able to figure out what I should pass as "Driver".
I searched and found out that this is the JDBC driver for MongoDB "mongodb.jdbc.MongoDriver", but how do I set it up while initializing SimpleDriverDataSource object?
I have tried doing the below, but it shows error mentioned below
#Bean
protected DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
Driver driver = new Driver("mongodb.jdbc.MongoDriver");
ds.setDriverClass(driver);
ds.setUrl("jdbc:mongodb://localhost:27017:spring-security-sampledb");
ds.setUsername("root");
ds.setPassword("secret");
return ds;
}
error
Cannot instantiate the type Driver
I am new to Spring Boot. Can you please help me in implementing this?
java.sql.Driver is an interface, which means you cannot instantiate it like that. You may want to review the basics of Java before starting with Spring Boot.
In any case, you need to use new mongodb.jdbc.MongoDriver() instead of new Driver(), or use setDriverClass and pass it the class reference (mongodb.jdbc.MongoDriver.class) instead of a Driver instance.
Also, please be aware that SimpleDriverDataSource is probably the wrong choice, as - for example - it doesn't provide connection pooling.
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.
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.
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
I'm using a Connection via severals pools :
DataSource ds = initialContext.lookup("poolname1");
Connection cn = ds.getConnection();
submethod1(cn);
submethod2(cn);
void submethod1(Connection cn)
{
// using connection
// ..
}
My question is: how to log "poolname" in submethods ? or similar informations about DataSource.
Perhaps this will help
getClientInfo()
or
getMetaData()
as mentionned in the Official Java Doc
The poolname in your example is actually a JNDI Name. This is generally a configuration which is configured in resource definition (e.q under in tomcat config).
For your problem as #sourlcheck mentioned, its not possible as connection are not aware of their datasource.
Once way to solve your problem is to give label to the datasource. Most of the Pooled datasource implementations (e.q. C3P0) offer a setter for setting up a name to the datasource. In C3P0 the datasournce class is ComboPooledDataSource and the method is getDataSourceName(). Once you get this name, it remains the same throughout its life cycle. But off course you need to introduce third party library
You can't log "poolname" in methods that receive Connection. Connections don't know if they are pooled or served directly from non-pooling DataSource.
Also you can create and access your pool in many different ways, not all of them guaranteeing existence of "poolname".