sorry for my broken english, not a native speaker :)
Here is my problem:
I try to connect via JDBC to a DB hosted on a MySQL server (Version: 5.6.37). I don't host the server and can't change any server configs.
When I try to connect using SQuirreL everything works as expected. I get access to the DB.
When I try to connect via self-written app via my IDE (eclipse) I get an Caused by: java.sql.SQLException: Access denied for user ... (using password: YES)
I'm using HikariCP to manage the connections. Tried also non connection pool aproach via DriverManager.getConnection. Both times the same.
The driver I'm using is mysql-connector-java-5.1.44-bin.jar
// DriverManager approach
private static final Properties dbProps = new Properties();
static {
dbProps.put("password", dbPass);
dbProps.put("user", dbUser);
dbProps.put("autoReconnect", "true");
dbProps.put("failOverReadOnly", "false");
dbProps.put("maxReconnects", "1");
}
...
public static Connection getConnection() {
Connection con = null;
try {
con = DriverManager.getConnection(connectionString, dbProps);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
...
// HakiriCP approach
private static HikariConfig config = new HikariConfig();
private static HikariDataSource ds;
private static final Properties dbProps = new Properties();
static {
PropertyLoader.loadPropertiesFromFile(dbProps); // read properties from external source
config.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s", dbProps.getProperty("db.server"),
dbProps.getProperty("db.port"), dbProps.getProperty("db.database")));
config.setUsername(dbProps.getProperty("db.user"));
config.setPassword(dbProps.getProperty("db.pass"));
config.addDataSourceProperty("cachePrepStmts", dbProps.getProperty("db.cachePrepStmts", "true"));
config.addDataSourceProperty("prepStmtCacheSize", dbProps.getProperty("db.prepStmtCacheSize", "250"));
config.addDataSourceProperty("prepStmtCacheSqlLimit", dbProps.getProperty("db.prepStmtCacheSqlLimit", "2048"));
ds = new HikariDataSource(config);
}
...
public static Connection getConnection() {
Connection con = null;
try {
con = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
...
EDIT - when I wireshark the connection tries, I see different encoded passwords (SQuirreL vs App). But when I print the password to the console it is exactly the one that work with SQuirreL.
EDIT - The connecttion handling is done in one single class. When I test it all alone without any of the other logic (it is a old swing app) everything works fine. But when I make the exact same call from the swing application it fails '(sends different password string).
What am I doing wrong?
I'm thankful for every help.
Cheers!
I found the solution. For all the project I have UTF-8 encoding. But eclipse decided to use UTF-16 when running or debugging code.
Option can be found here: Run Configurations -> Common -> Encoding
Ok, eclipse made some joke with me.
Thanks to wireshark givin me the hint that something is wrong with the encoding.
Thanks to you guys to trying to help (inluding the ones giving me -1, they don't know it better ;))
Cheers!
I am starting H2 db in embedded mode. By default h2 db file is getting created in users directory. I have requirement of creating in a custom location. The custom location should be read from environment variable ( Example %MY_HOME%= C:\TEST).
The database file should be created in c:\TEST. What changes should I make in web.xml to do the same?
Thanks in advance
You can add you custom location by setting db.url property of H2.
for example :
If your database name is DBNAME then you can set db.url in web.xml with your custom location in following manner :
jdbc:h2:file:C:\\Test\\DBNAME
If you are using Hibernate in your application then you can build session factory for H2 database in following manner :
private static SessionFactory buildSessionFactory()
{
String methodName = "buildSessionFactory -->";
_logger.debug(methodName + Constants.CALLED);
try
{
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
URL resourceURL = HibernateUtil.class.getClassLoader().getResource("hibernate.cfg.xml");
_logger.debug(resourceURL);
configuration = configuration.configure(resourceURL);
//Here you can set your custom url for H2 database.
String url = "jdbc:h2:file:C:\\Test\\DBNAME;MV_STORE=FALSE;MVCC=TRUE;DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO";
_logger.debug("Database URL " + url);
_logger.debug("Build Session Factory URL: " + url);
configuration = configuration.setProperty("hibernate.connection.url", url);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
_logger.debug("Session factory built");
_logger.debug(Constants.END);
return configuration.buildSessionFactory(serviceRegistry);
}
catch (Throwable ex)
{
_logger.debug("Failed to create session factory");
_logger.error("Initial SessionFactory creation failed.", ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
I got an answer for my query. We can set init parameters in two ways.
1) web.xml, Generally everyone uses.
2) contextInitialized will be method called as call back method while tomcat is getting started. In that method you can set the init parameters by using instance of servletContext clas.
I have created my JDBC connection like bellow:
java.sql.Connection conn = java.sql.DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:DBSID", "DB_USER",
"DB_PASS");
How can I get JDBC driver class name (e.g. "oracle.jdbc.driver.OracleDriver") during run-time something like that:
String driverClsName = getDriverClsName(conn);
//e.g. driverClsName = "oracle.jdbc.driver.OracleDriver"
I've already searched stackoverflow for that but no final solution found.
Already viewed How to get driver class name (not driver name) from jdbc connection
What should be code inside below method:
String getDriverClsName(Connection conn){
//code here
}
I've already tried conn.getMetaData().getDriverName(); which is returning Oracle JDBC driver.
My requirement is to show information(such as class name) about current driver being used in the application.
DriverManager.getDriver(String) should do this:
Connection conn = DriverManager.getConnection(...);
String originalURL = conn.getMetaData().getURL();
Driver drv = DriverManager.getDriver(originalURL);
String driverClass = drv.getClass().getName();
Try the following method:
conn.getMetaData().getDriverName();
Couple of other methods available:
conn.getMetaData().getDriverVersion();
conn.getMetaData().getDriverMajorVersion();
conn.getMetaData().getDriverMinorVersion();
I'm trying to create my first connection pool. I'm creating a Java web aplication with Tomcat 7 and a MySQL DB, and I'd like to create the simplest connection pool possible.
I've taken a look at several tutorials but it's not really clear for me, so I'd like you to confirm if I'm doing well.
I've written the following class as a connection pool manager:
package dao.mysql;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
public class MySQLConnectionPool {
private static DataSource datasource;
private static String driver = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/mydb";
private static String username = "user";
private static String password = "password";
public MySQLConnectionPool() {
datasource = new DataSource(configurePoolProperties(driver, url, username, password));
}
private PoolProperties configurePoolProperties(String driver, String url, String username, String password) {
PoolProperties properties = new PoolProperties();
properties.setDriverClassName(driver);
properties.setUrl(url);
properties.setUsername(username);
properties.setPassword(password);
return properties;
}
public static synchronized Connection getConnection() {
Connection connection = null;
try {
connection = datasource.getConnection();
} catch (SQLException ex) {
System.out.println("Error while getting a connection from the pool! \nSQL state:" + ex.getSQLState() + "\nMESSAGE" + ex.getMessage());
}
return connection;
}
}
I'm not sure about the static properties nor the synchronized.
And I'm not sure about the "client" classes of the pool. I understand they have only to get a connection using
Connection con = MySQLConnectionPool.getConnection();
and finally close this connection using
con.close();
And that's it?
And also, is there any simpler or better way to do this?
Thanks very much!
This is the wrong way to do it.
Tomcat already has a connection pool and you can configure and setup without any code through the context.xml in the conf directory.
Once it is defined there, all you need to do is to lookup the JNDI DataSource in your code. Hardcoding all that (and re-inventing the wheel) is a very bad idea.
To learn how to configure a JNDI DataSource check out the manual: http://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html
The Tomcat manual also has an example on how to obtain a connection from the pool:
InitialContext cxt = new InitialContext();
DataSource ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/dsname" );
where dsname is the name you provided in the context.xml
Check out the JNDI Datasource HOW-TO and the Tomcat JDBC Connection Pool Tomcat documentation. Letting Tomcat do it is preferable especially since it avoids class loader leaks.
We have a JPA application (using hibernate) and we need to pass a call to a legacy reporting tool that needs a JDBC database connection as a parameter. Is there a simple way to get access to the JDBC connection hibernate has setup?
As per the hibernate docs here,
Connection connection()
Deprecated. (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use
doWork(org.hibernate.jdbc.Work) ...
Use Hibernate Work API instead:
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
// do whatever you need to do with the connection
}
});
Where you want to get that connection is unclear. One possibility would be to get it from the underlying Hibernate Session used by the EntityManager. With JPA 1.0, you'll have to do something like this:
Session session = (Session)em.getDelegate();
Connection conn = session.connection();
Note that the getDelegate() is not portable, the result of this method is implementation specific: the above code works in JBoss, for GlassFish you'd have to adapt it - have a look at Be careful while using EntityManager.getDelegate().
In JPA 2.0, things are a bit better and you can do the following:
Connection conn = em.unwrap(Session.class).connection();
If you are running inside a container, you could also perform a lookup on the configured DataSource.
If you are using JAVA EE 5.0, the best way to do this is to use the #Resource annotation to inject the datasource in an attribute of a class (for instance an EJB) to hold the datasource resource (for instance an Oracle datasource) for the legacy reporting tool, this way:
#Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource;
Later you can obtain the connection, and pass it to the legacy reporting tool in this way:
Connection conn = dataSource.getConnection();
if you use EclipseLink:
You should be in a JPA transaction to access the Connection
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();
Hibernate 4 / 5:
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));
Since the code suggested by #Pascal is deprecated as mentioned by #Jacob, I found this another way that works for me.
import org.hibernate.classic.Session;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.engine.SessionFactoryImplementor;
Session session = (Session) em.getDelegate();
SessionFactoryImplementor sfi = (SessionFactoryImplementor) session.getSessionFactory();
ConnectionProvider cp = sfi.getConnectionProvider();
Connection connection = cp.getConnection();
The word pure doesn't match to the word hibernate.
EclipseLink
Getting a JDBC Connection from an EntityManager
It's somewhat straightforward as described in above link.
Note that the EntityManager must be joined to a Transaction or the unwrap method will return null. (Not a good move at all.)
I'm not sure the responsibility of closing the connection.
// --------------------------------------------------------- EclipseLink
try {
final Connection connection = manager.unwrap(Connection.class);
if (connection != null) { // manage is not in any transaction
return function.apply(connection);
}
} catch (final PersistenceException pe) {
logger.log(FINE, pe, () -> "failed to unwrap as a connection");
}
Hibernate
It should be, basically, done with following codes.
// using vendor specific APIs
final Session session = (Session) manager.unwrap(Session.class);
//return session.doReturningWork<R>(function::apply);
return session.doReturningWork(new ReturningWork<R>() {
#Override public R execute(final Connection connection) {
return function.apply(connection);
}
});
Well, we (at least I) might don't want any vendor-specific dependencies. Proxy comes in rescue.
try {
// See? You shouldn't fire me, ass hole!!!
final Class<?> sessionClass
= Class.forName("org.hibernate.Session");
final Object session = manager.unwrap(sessionClass);
final Class<?> returningWorkClass
= Class.forName("org.hibernate.jdbc.ReturningWork");
final Method executeMethod
= returningWorkClass.getMethod("execute", Connection.class);
final Object workProxy = Proxy.newProxyInstance(
lookup().lookupClass().getClassLoader(),
new Class[]{returningWorkClass},
(proxy, method, args) -> {
if (method.equals(executeMethod)) {
final Connection connection = (Connection) args[0];
return function.apply(connection);
}
return null;
});
final Method doReturningWorkMethod = sessionClass.getMethod(
"doReturningWork", returningWorkClass);
return (R) doReturningWorkMethod.invoke(session, workProxy);
} catch (final ReflectiveOperationException roe) {
logger.log(Level.FINE, roe, () -> "failed to work with hibernate");
}
OpenJPA
Runtime Access to DataSource
OPENJPA-1803 Unwrap EntityManager to Connection
I'm not sure OpenJPA already serves a way using unwrap(Connection.class) but can be done with the way described in one of above links.
It's not clear the responsibility of closing the connection. The document (one of above links) seems saying clearly but I'm not good at English.
try {
final Class<?> k = Class.forName(
"org.apache.openjpa.persistence.OpenJPAEntityManager");
if (k.isInstance(manager)) {
final Method m = k.getMethod("getConnection");
try {
try (Connection c = (Connection) m.invoke(manager)) {
return function.apply(c);
}
} catch (final SQLException sqle) {
logger.log(FINE, sqle, () -> "failed to work with openjpa");
}
}
} catch (final ReflectiveOperationException roe) {
logger.log(Level.FINE, roe, () -> "failed to work with openjpa");
}
Hibernate uses a ConnectionProvider internally to obtain connections. From the hibernate javadoc:
The ConnectionProvider interface is not intended to be exposed to the application. Instead it is used internally by Hibernate to obtain connections.
The more elegant way of solving this would be to create a database connection pool yourself and hand connections to hibernate and your legacy tool from there.
I ran into this problem today and this was the trick I did, which worked for me:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DAOMANAGER");
EntityManagerem = emf.createEntityManager();
org.hibernate.Session session = ((EntityManagerImpl) em).getSession();
java.sql.Connection connectionObj = session.connection();
Though not the best way but does the job.
Below is the code that worked for me. We use jpa 1.0, Apache openjpa implementation.
import java.sql.Connection;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
public final class MsSqlDaoFactory {
public static final Connection getConnection(final EntityManager entityManager) {
OpenJPAEntityManager openJPAEntityManager = OpenJPAPersistence.cast(entityManager);
Connection connection = (Connection) openJPAEntityManager.getConnection();
return connection;
}
}
I'm using a old version of Hibernate (3.3.0) with a newest version of OpenEJB (4.6.0). My solution was:
EntityManagerImpl entityManager = (EntityManagerImpl)em.getDelegate();
Session session = entityManager.getSession();
Connection connection = session.connection();
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(sql);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
I had an error after that:
Commit can not be set while enrolled in a transaction
Because this code above was inside a EJB Controller (you can't commit inside a transaction). I annotated the method with #TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED) and the problem was gone.
Here is a code snippet that works with Hibernate 4 based on Dominik's answer
Connection getConnection() {
Session session = entityManager.unwrap(Session.class);
MyWork myWork = new MyWork();
session.doWork(myWork);
return myWork.getConnection();
}
private static class MyWork implements Work {
Connection conn;
#Override
public void execute(Connection arg0) throws SQLException {
this.conn = arg0;
}
Connection getConnection() {
return conn;
}
}
I am a little bit new to Spring Boot, I have needing the Connection object to send it to Jasperreport also, after trying the different answers in this post, this was only useful for me and, I hope it helps someone who is stuck at this point.
#Repository
public class GenericRepository {
private final EntityManager entityManager;
#Autowired
public GenericRepository(EntityManager entityManager, DataSource dataSource) {
this.entityManager = entityManager;
}
public Connection getConnection() throws SQLException {
Map<String, Object> properties = entityManager.getEntityManagerFactory().getProperties();
HikariDataSource dataSource = (HikariDataSource) properties.get("javax.persistence.nonJtaDataSource");
return dataSource.getConnection();
}
}