I want to fetch parameter name and parameter type of given prepared statement. I am using MySQL Database. But when I run my program it is throwing an error:
Exception in thread "main" java.sql.SQLException: Parameter metadata not available for the given statement
at this line
String paramTypeName = paramMetaData.getParameterTypeName(param);
I don't know why this is happening. Please anybody help me if possible.
Here's my code:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class Main {
public static void main(String[] args) throws Exception {
Connection conn = getMySqlConnection();
Statement st = conn.createStatement();
String query = "select * from survey where id > ? and name = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
ParameterMetaData paramMetaData = pstmt.getParameterMetaData();
if (paramMetaData == null) {
System.out.println("db vendor does NOT support ParameterMetaData");
} else {
System.out.println("db vendor supports ParameterMetaData");
// find out the number of dynamic parameters
int paramCount = paramMetaData.getParameterCount();
System.out.println("paramCount=" + paramCount);
System.out.println("-------------------");
for (int param = 1; param <= paramCount; param++) {
System.out.println("param number=" + param);
String paramTypeName = paramMetaData.getParameterTypeName(param);
System.out.println("param SQL type name=" + paramTypeName);
}
}
pstmt.close();
conn.close();
}
public static Connection getMySqlConnection() throws Exception {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "";
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
}
According to this
Should the driver generate simplified parameter metadata for PreparedStatements when no
metadata is available either because the server couldn't support preparing the statement, or
server-side prepared statements are disabled?
You have to set generateSimpleParameterMetadata to true
use a connection string similar to this
jdbc:mysql://localhost:3306/mydb?generateSimpleParameterMetadata=true
MySQL JDBC driver currently does not support it. I am solving the similar issue and came up with the following workaround:
include H2 database in your project (it can also run in embedded mode or in-memory)
translate your MySQL create database script to H2 syntax (or write it in ANSI so it is compatible with both)
compile prepared statements on H2 database first and get metadata from them - H2 database supports this function and SQL query syntax is similar in most cases - then save the obtained meta information for later use
there might be differences in data types, etc, but in general this should give you about 80% match with MySQL without too much hassle
I know it has much caveats, but it might work in some use cases.
Also consider upgrading MySQL database to 5.7, there are some enhancements related to prepared statements which may help, but I am not very deeply knowledgable about those:
http://dev.mysql.com/doc/refman/5.7/en/prepared-statements-instances-table.html
http://dev.mysql.com/doc/refman/5.7/en/prepare.html
You have not set the parameter to the prepared statements, without which you cannot get parameter metadata. so first set the parameter
pstmt.setInt(val)
pstmt.setString(val)
After adding the parameters you can get the meta data about the parameter.
Hope this helps.
Related
I am trying to access a database from a different server , but no success so far. The event is, when I choose the object "ALL" in my combobox, the table will load all data from different servers.
The current code, which I only connected to the localhost, works fine. However, when I try to connect another server to load both of their data, I get a syntax error when trying to put 192.168.1.51.sales.items in the String sqlall. Also, I tried modifying the prepareStatement by writing cn.prepareStatement(sqlall) + cn1.prepareSatement("union Select * from 192.168.1.52.sales.items); I have no more idea on how to connect on both servers.
I would like to apologize beforehand if you find my coding a bit messy. Thank you. My code is as follows:
private void combobox_branchItemStateChanged(java.awt.event.ItemEvent evt) {
Object branch = combobox_branch.getSelectedItem();
try
{
// All is selected
if("All".equals(branch))
{
Connection cn = db.itemconnector.getConnection();
String sqlall = " Select * from sales2.items union Select * from sales1.items union Select * from sales.items " ; //I tried accessing multiple databases in my own localhost and worked.
PreparedStatement ps = cn.prepareStatement(sqlall);
ResultSet rs = ps.executeQuery();
DefaultTableModel tm = (DefaultTableModel)itemTable.getModel();
tm.setRowCount(0);
while(rs.next())
{
Object o[] = {rs.getInt("id"), rs.getString("location"), rs.getString("product_name"),rs.getString("product_category"),rs.getString("product_description"),rs.getInt("product_stock"), rs.getFloat("product_price"), rs.getString("product_status")};
tm.addRow(o);
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, e, "Connection Error", JOptionPane.ERROR_MESSAGE);
}
}
And I have a class in a different package and this is its code:
package db;
import java.sql.*;
public class itemconnector {
public static Connection getConnection() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection cn = (Connection)
DriverManager.getConnection("jdbc:mysql://192.168.1.50:3306/sales","root","");
return cn;
}
It is not possible to query different databases on different servers in a single SQL query.
It is also not possible to get around this by "concatenating" prepared statements. (For a start, that is nonsensical Java!)
You need to open a separate Connection to each separate database server and query the relevant tables on that server. Then combine the information from the separate ResultSet objects in Java code.
The "combining" will be something like iterating the results in each result set and adding them to a Java data structure ...
This question already has answers here:
CREATE DATABASE query using java jdbc and prepared statement returns syntax error [duplicate]
(2 answers)
Closed 4 years ago.
I'm trying to create a database with java jdbc with a method so i'm passing the name type string of database as argument to database but i'm facing an issue which is You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Algebra'' at line 1
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DbTest {
private Connection connection;
public void createDb(String name) throws SQLException {
connection = DriverManager.getConnection
("jdbc:mysql://localhost/?user=root&password=root");
String createDbSql = "CREATE DATABASE IF NOT EXISTS ?";
PreparedStatement createDbStat = connection.prepareStatement(createDbSql);
createDbStat.setString(1,name);
createDbStat.executeUpdate();
}
DbTest() {
try {
createDb("Algebra");
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new DbTest();
}
}
When you use createDbStat.setString(1, name); it will create a query like this :
CREATE DATABASE IF NOT EXISTS 'databasename'
//----------------------------^____________^
And this is a wrong syntax, the correct should be :
CREATE DATABASE IF NOT EXISTS databasename
to solve your problem you can just use :
String createDbSql = String.format("CREATE DATABASE IF NOT EXISTS `%s`", name);
// ^^^^
PreparedStatement createDbStat = connection.prepareStatement(createDbSql);
//createDbStat.setString(1,name); no need for this
createDbStat.executeUpdate();
For security reason
Just for security reason, and to avoid SQL Injection make sure that your database name match this:
if(name.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")){
//Correct name
}
for more details read this Check for valid SQL column name
You can't bind your parameter (1) to the database name-
you'll have to use string concatenation in this case.
Your question is also similar to
How to use a tablename variable for a java prepared statement insert
and
CREATE DATABASE query using java jdbc and prepared statement returns syntax error
I am trying to solve this problem with the help of properties file, but in a Properties file, we can handle only Database Driver problem. If I want to switch my MySQL to Oracle database I need to change my all query. The problem is how to make query independent in JDBC?
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class DBIndependencyExample {
public static void main(String[] args) {
try {
Properties pros = new Properties();
InputStream fis = new FileInputStream(
"D:\\Programs\\Eclipse\\DBIndependecyByPropertiesFile\\src\\connectdb.properties");
pros.load(fis);
String Drivername = pros.getProperty("k1");
//System.out.println(Drivername);
String url = pros.getProperty("k2");
String un = pros.getProperty("k3");
String pw = pros.getProperty("k4");
Class.forName(Drivername);
Connection con = DriverManager.getConnection(url, un, pw);
System.out.println("Driver Is Loaded With" + Drivername);
System.out.println("Connection is Opened");
Statement smt = con.createStatement();
String sql = pros.getProperty("k5");
//System.out.println(sql);
ResultSet rs = smt.executeQuery(sql);
while (rs.next()) {
System.out.println("username is:" + rs.getString(1) + " password is:" + rs.getString(2));
}
con.close();
System.out.println("Connection is closed");
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Properties File:
//Mysql Connectivity
//Start Properties File Code
k1=com.mysql.jdbc.Driver
k2=jdbc:mysql://localhost:3306/practice
k3=root
k4=root
k5=select * from student
//Oracle Connectivity
k1=oracle.jdbc.driver.OracleDriver
k2=jdbc:oracle:thin:#localhost:1521/orcla
k3=scott
k4=manish
k5=select * from dept
If i want to switch my mysql to oracle database i need to change my
all query.
If your SQL queries rely only on the ANSI SQL and never on proprietary specificites (function, keywords, and...) you should be able to switch from an DBMS to another one without any change in the queries.
Note that Hibernate will not translate for a DBMS specifities to another one as for example translate a query on the DUAL table written in Oracle to a MySQL way.
Hibernate ensures that your SQL queries be portable while you don't create native queries, a possibility still provided by Hibernate.
Here is the original SQL ANSI draft and here a download link for the last version of Information technology -- Database languages -- SQL -- Part 1: Framework (SQL/Framework)
I don't think so if you switch to hibernate or any orm frameworks. In case of hibernate you can use hql to write the queries in that way you are database independent no matter what database you switch hibernate will take care. You can even look at Spring CrudRepository. I highly doubtful you can achieve database independent queries just with the JDBC. It is good to begin with JDBC for a long run you should consider orm frameworks.
You can write a generic method that can handle any sql query (regardless of the database used). The trick here is to use database metadata to automatically
populate a hash map (a hash map is convenient because we can use the column names as keys) containing the query results. For parameterized queries, you'll need a more complex method, which can be found at the link provided below (DBSelect.getRecordsForCustomQuery). If all your queries targeting different databases are the same, then you don't even have to use metadata, just hardcode the column names.
public Map<String, Object> getQueryResults(String query, Connection conn){
ResultSet rs=null;
PreparedStatement stmt=null;
Map<String, Object> objMap = new HashMap<>();
stmt = conn.prepareStatement(sqlQuery);
rs = stmt.executeQuery();
while(rs.next()){
for (int i=1;i<=rs.getMetaData().getColumnCount();i++) {
objMap.put( rs.getMetaData().getColumnName(i), rs.getObject(i));
}
}
return mapObj;
}
You can, of course, modify this method to suit your needs.
A slightly more elaborate solution which uses reflection and generics can be found here ( https://github.com/IvanGH2/EasyORM ) but you don't
even have to use all of that.
can anyone please help me on this? I am trying to execute a SQL query (to Microsoft SQL) using JAVA. But, nothing happens on my table. Also, no exception either. But i am pretty sure that this code directly connecting to my DB. Here's my code.
package Testing;
//import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class TestingClass {
public static void main(String[] srg)
{
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; // Start JDBC
String dbURL = "jdbc:sqlserver://localhost:1433;DatabaseName=OPERATIONS"; // Connect the server and the database
String userName="AppControlTeam";
String userPwd="*****";
//
Connection connection = null;
try{
Class.forName(driverName);
connection = DriverManager.getConnection(dbURL,userName,userPwd);
String sql = "DELETE FROM GFR_GROWTH_RATE";
PreparedStatement statement = connection.prepareStatement(sql);
statement.executeUpdate();
connection.close();
}
catch (Exception e){
e.printStackTrace();
}
}
}
I have been already added the JDBC driver on the package. Also, i'm pretty sure that this is not a classpath issue since the connection to DB thru this code is already success.
Thanks in advance to someone who can help! :D
-Jiro
Your DELETE may be rolled back if you didn't set your JDBC driver's autocommit property to true. Maybe try calling
connection.commit();
// right before...
connection.close();
Or alternatively:
connection.setAutoCommit(true);
// before...
PreparedStatement statement = connection.prepareStatement(sql);
Probably the row is locked by a different session, may be an uncommitted session that has modified (deleted/updated) the records from the table. Another possibility is by a tool which open the row/record with locked state - so the delete statement hangs.
Working with database in java requires a set of lines of code to be written. If the database connection is established again-n-again the same set of lines need to be repeated again-n-again which creates an overhead to programmer.
Hence, I am making a utility class which works as a database agent. The method of this class will be responsible for all the database related stuff from establishing a connection to executing a query and returning the result.
My class goes like this -
package connect;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Connector
{
private ResultSet rs;
public String password;
public void connect(String dbUrl, String dbClass, String dbUserName, String dbPassword, String query)
{
try
{
Class.forName(this.dbClass).newInstance();
Connection conn = DriverManager.getConnection (dbUrl, dbUserName, dbPassword);
Statement stmt = conn.createStatement();
rs = stmt.executeQuery(query);
while(rs.next())
{
this.password = (String) rs.getObject(1);
}
conn.close();
} //end try
catch(Exception e)
{
e.printStackTrace();
}
}
}
When a programmer needs a query to be executed, below lines can be written for that purpose -
Connector con = new Connector();
con.connect("your database URL",
"your database driver",
"your database username",
"your database password",
"your query");
My question here is that right now I am retreiving the data from ResultSet in the connect method itself. The retreived data can vary from query-to-query hence I want a data structure in which I can store the data from rs in connect() method and return it.
It will look like -
<data structure> result = con.connect("your database URL",
"your database driver",
"your database username",
"your database password",
"your query");
Can someone please suggest me a data structure for this purpose?
Not sure why you're re-inventing this particular wheel, and it seems like if you're repeatedly connecting for every query you're basically writing yourself out of any performance, but why not just use RowSetDynaClass if you're not going to map to objects?
Just be aware that there are a ton of pre-existing solutions that have been tested and proven. And use connection pools; creating connections is expensive.
There is a lot of Open Source, implementation like the one you want to do above.
Spring JDBCTemplate for example.
If you can't use any libraries already available to solve your problem, you could use
Vector<Map<String, Object>>
Where String contains column name and Object is the value of the column. Each element in the Vector corresponds to a row of the ResultSet. This may not be the most efficient data structure but should get the job done.