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?
Related
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.
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.
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 want to use JOOQ to access my database from the Ninja Framework. How can I get a JDBC connection from a controller?
Here's resources I found that didn't quite work.
How to retrieve the datasource used by a persistence unit programmatically - Tedious set of steps to get the connection from an EntityManager.
http://blog.jooq.org/2015/05/26/type-safe-queries-for-jpas-native-query-api/ - works by building a query in JOOQ and passing to EntityManager.createNativeQuery. It's functional, but it's not as nice as just having the connection.
Could I inject the connection into a controller like so:
public Result myController(#DBConnection Connection connection) {
List<String> articles = DSL.using(connection).selectFrom(ARTICLE).fetch(ARTICLE.TITLE);
return Results.html().render("template", articles);
}
DropWizards has a plugin that looks like a winner: https://github.com/benjamin-bader/droptools/tree/master/dropwizard-jooq
public BlogPost getPost(#QueryParam("id") int postId, #Context DSLContext database) {
BlogPostRecord post = database
.selectFrom(POST)
.where(POST.ID.equal(postId))
.fetchOne();
// do stuff
}
Following up on #LukasEder's answer this is the approach:
HibernateEntityManagerFactory hibernateEntityManagerFactory = ((EntityManagerImpl) entityManager).getFactory();
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory();
C3P0ConnectionProvider c3P0ConnectionProvider = (C3P0ConnectionProvider) sessionFactoryImpl.getConnectionProvider();
Connection connection = c3P0ConnectionProvider.getConnection();
This is obviously very very strange and bad code.
A clean solution is to provide access to Connection / DataSource by Ninja directly (separating the connection pool from Hibernate or any implementation). That is not too hard and is partly done in the ebeans plugin. Let's discuss that on our mailing list if you are interested in contributing code :)
Short of any option to retrieve a JDBC Connection or DataSource from ninja framework directly, the standard approach should be to "unwrap" it from the EntityManager:
Connection connection = em.unwrap(Connection.class);
See also: How to get DataSource or Connection from JPA2 EntityManager in Java EE 6
A Hibernate-specific approach is documented here: How to retrieve the datasource used by a persistence unit programmatically
I have to configure two database on same project by configuring two CFG file,
I tried but it is always use the first configuration file,
May i know how can i use two database on same project
In your code, what you need to do is to open two different session factory for different databases.
For example:
Configuration configA=new Configuration();//use the default hibernate.cgf.xml file
Congiruration configB=new Configuration.configure('/hibernate_db2.cfg.xml') // use hibernate_db2.cfg.xml under root folder.
SessionFactory sfa=configA.buildSessionFactory();
SessionFactory sfb=configB.buildSessionFactory();
Now, you open different session using different db.
You need to have two configuration files.
hibernate-mysql.cfg.xml
hibernate-oracle.cfg.xml
And code should be like this.
mysql configuration
private static SessionFactory sessionAnnotationFactory;
sessionAnnotationFactory = new Configuration().configure("hibernate-mysql.cfg.xml").buildSessionFactory();
Session session = sessionAnnotationFactory.openSession();
oracle sql configuration
sessionAnnotationFactory = new Configuration().configure("hibernate-oracle.cfg.xml").buildSessionFactory();
Session session = sessionAnnotationFactory.openSession()