Convert all the mysql table data into JSON in spring boot - mysql

I want to just specify the table name and it will automatically convert all of its data to JSON Format
I have tried a code that is storing the data from table into JSON using JDBC .
public class DataBaseToJson {
public static ResultSet RetrieveData() throws Exception {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
String mysqlUrl = "jdbc:mysql://localhost/studentsDB?autoReconnect=true&useSSL=false";
Connection con = DriverManager.getConnection(mysqlUrl, "root", "root");
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery("Select * from students");
return resultSet;
}
public static void main(String args[]) throws Exception {
JSONObject jsonObject = new JSONObject();
JSONArray array = new JSONArray();
ResultSet resultSet = RetrieveData();
while (resultSet.next()) {
JSONObject record = new JSONObject();
record.put("students ID", resultSet.getInt("students_id"));
record.put("students Name", resultSet.getString("students_name"));
array.add(record);
}
jsonObject.put("students Information", array);
try {
FileWriter file = new FileWriter("output.json");
file.write(jsonObject.toJSONString());
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I don't want to specify the fileds in a file. I want to make it generic so that we could only put the table name and it will automatically convert all the data from that table and save into a JSON file.

public static void main(String args[]) throws Exception {
String tableName = "books";
Connection connection = createConnection();
JSONArray array = new JSONArray();
JSONObject jsonObject = new JSONObject();
List<String> columns = loadColumns(connection, tableName);
ResultSet dataSet = loadData(connection, tableName);
while (dataSet.next()) {
JSONObject record = new JSONObject();
for (String column : columns) {
record.put(column, dataSet.getObject(column));
}
array.add(record);
}
jsonObject.put(tableName, array);
try {
FileWriter file = new FileWriter("output.json");
file.write(jsonObject.toJSONString());
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static Connection createConnection() throws SQLException {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
String mysqlUrl = "jdbc:mysql://localhost/library?autoReconnect=true&useSSL=false";
Connection connection = DriverManager.getConnection(mysqlUrl, "root", "root");
return connection;
}
public static List<String> loadColumns(Connection connection, String tableName) throws SQLException {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT COLUMN_NAME FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE TABLE_NAME LIKE '"+tableName+"'");
List<String> columnsName = new ArrayList<String>();
while(resultSet.next()) {
columnsName.add(resultSet.getString("COLUMN_NAME"));
}
return columnsName;
}
public static ResultSet loadData(Connection connection, String tableName) throws SQLException {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("Select * from "+tableName+"");
return resultSet;
}

You can select list of columns for given table using INFORMATION_SCHEMA:
SELECT COLUMN_NAME FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE TABLE_NAME LIKE 'table_name'
Now, convert ResultSet from above query to List<String> of column names. After that we can use it to convert final ResultSet to JSON Object.
Pseudocode:
Connection connection = createConnection();
List<String> columns = loadColumns(connection, tableName);
ResultSet dataSet = loadData(connection, tableName);
while (dataSet.next()) {
JSONObject record = new JSONObject();
for (String column : columns) {
record.put(column, dataSet.getObject(column));
}
array.add(record);
}
// save array to file
When ResultSet is huge we should consider to use Streaming API from Jackson or Gson libraries to avoid "out of memory" problem.
See also:
How to get database structure in MySQL via query
Jackson Streaming API
Jackson - Processing model: Streaming API
Gson Streaming
Update
It looks like we do not event need to select column names using extra SQL query because ResultSet has getMetaData method:
Retrieves the number, types and properties of this ResultSet object's
columns.
See also:
ResultSetMetaData class

Related

inserting two tables from multiple databases in jdbc

How to insert the two tables from two databases in jdbc is it possible?
I have the code but its not working
public class MergeData {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
#SuppressWarnings("unchecked")
public static void main(String[] args) throws SQLException {
//"jdbc:mysql://localhost:3306/fhv1", "root", "root"
DBDataFetcher database1 = new DBDataFetcher("jdbc:mysql://localhost:3306/fhv1", "root", "root");
List<Object> restDetailsList = (List<Object>) database1.fetchTableRows("restdetails");
database1.closeConnection();
long restid = 0;
for(Object obj : restDetailsList) {
if (obj instanceof RestDetails) {
restid = ((RestDetails) obj).getRest_id();
System.out.print(restid + " ");
}
}
DBDataFetcher database2 = new DBDataFetcher("jdbc:mysql://localhost:3306/test", "root", "root");
List<Object> restLocationList = (List<Object>) database2.fetchTableRows("restlocation");
database2.closeConnection();
for(Object obj : restLocationList) {
if (obj instanceof RestLocation) {
((RestLocation) obj).setRest_id(++restid);
System.out.print(((RestLocation) obj).getRest_id() + " ");
restDetailsList.add(obj);
}
}
DBDataMerger merger = new DBDataMerger("jdbc:mysql://localhost:3306/db", "root", "root");
merger.mergeTable(restDetailsList, "restdetails");
merger.closeConnection();
}
}
In plain JDBC, you should create two connections (one for each database)
public Connection getDbConnection(String dbUrl, String driver, String user, String psw){
Connection conn=null;
try{
Class.forName(driver);
conn = DriverManager.getConnection(dbUrl,user,psw);
}catch(SQLException e){
//log exception
}
return conn;
}
And to insert records you can do something like
public void insertRecord(){
//add try and catch/finally
//inserting into 1st DB
Connection conn1 = getDBConnection(dbURl1, driver1, user1, psw1);
Statement stmt = conn1.CreateStatement();
String insert1 = "insert into tbl1 (a,b,c) values(1,2,2);
stmt.executeUpdate(insert1);
//inserting into 2nd DB
Connection conn2 = getDBConnection(dbURl2, driver2, user2, psw2);
stmt = conn2.CreateStatement();//reassing statement or use a new one
String insert2 = "insert into tbl2 (a,b,c) values(1,2,2);
stmt.executeUpdate(insert2);
}
Normally, you'll want to use a PreaparedStatement instead of Statement (because it's usually faster and more secure than a Statement)

Query MySQL DB using preparedStatement.setDate

public java.util.List<Tag> getAlltagsByDate(String date ){
DataSource dataSource = new DataSource();
Connection conn = dataSource.createConnection();
ResultSet resultSet = null;
PreparedStatement stmt = null;
Tag tags_Data = new Tag();
String query = "select * from tag_data where tag_data_date = ?";
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date nn =df.parse(date);
stmt = conn.prepareStatement(query);
stmt.setDate(1, java.sql.Date.valueOf(date));
resultSet = stmt.executeQuery(query);
I am getting an error
Can anyone help me with this,
I need to query mySQL db where date = input in html
No, skip the Date part; simply use the string. Let's see the value of (String date ).
MySQL is happy if you can end up with ... tag_data_date = '2015-12-11'.
If String date looks like '2015-12-11', then the conversion to Date is unnecessary.
I have presented a solution. As you have not mentioned much about your DB structure, so ,
Consider test as database name, and consisting of table tag_data having two columns id and tag_data_date as shown below.
CREATE TABLE `tag_data` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`tag_data_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Also consider data in table as
INSERT INTO `tag_data` (`id`, `tag_data_date`) VALUES
(1, '2015-12-20 00:00:00');
And your java class as below
public class JDBCPreparedStatementExample {
private static final String DB_DRIVER = "com.mysql.jdbc.Driver"; //mysql driver class
private static final String DB_CONNECTION = "jdbc:mysql://localhost:3306/test"; //connectionstring
private static final String DB_USER = "root"; //mysql username
private static final String DB_PASSWORD = "root"; //mysql password
public static void main(String[] argv) throws ParseException {
try {
getDateForDate("2015-12-20"); //time passed as arguement
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
//Method to interact with DB and print data,this can be changed to return value of List<Key> as per your requirement
private static void getDateForDate(String date) throws SQLException, ParseException {
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date dateCal =df.parse(date); // parse date in String to Date Object
String updateTableSQL = "select * from tag_data where tag_data_date = ?";
try {
//get DB connection
dbConnection = getDBConnection();
// Create preapared statement
preparedStatement = dbConnection.prepareStatement(updateTableSQL);
preparedStatement.setDate(1, new Date(dateCal.getTime()));//convert java.util.Date to java.sql.Date
// execute update SQL stetement
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
// It is possible to get the columns via name
// also possible to get the columns via the column number
// which starts at 1
// e.g. resultSet.getString(2);
int id = resultSet.getInt("id");
Date tag_data_date = resultSet.getDate("tag_data_date");
System.out.println("Date: " + tag_data_date);
System.out.println("Comment: " + id);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
private static Connection getDBConnection() {
Connection dbConnection = null;
try {
Class.forName(DB_DRIVER);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(
DB_CONNECTION, DB_USER,DB_PASSWORD);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
}

JDBC SQL aliasing not working

I am trying to run the following query in my java web application:
SELECT platform AS "Platform" FROM edb.cases
The web-app is working fine and is able to execute all queries however whenever I use an alias (through 'AS'), the resultant data-set gives me a null value for the alias. In fact, despite using an alias for the column 'platform' in the above query, the resultant data-set has a null value for the key 'Platform' but gives me the correct value for the key 'platform' (which is the original name of the column).
Now the actual sql statement which I need to execute is a bit more complex with select statements and left joins on the same table twice using aliases, like so:
SELECT numOne.platform , numTwo.platform AS 'PlatformTwo' FROM edb.cases LEFT JOIN
edb.platform as numOne ON (numOne.rank = cases.platform) LEFT JOIN edb.platform as numTwo ON
(numTwo.rank = cases.highestPlatform) WHERE cases.index = 1000
The problem is that the resultant data-set contains the correct value for the key 'platform' (for numOne table) but the keys 'PlatformOne' and 'PlatformTwo' DO NOT EXIST. The aliases are not working!
I have tried both the statements in MySql workbench and they work fine.
Please do not hesitate to ask for more information.
EDIT:
The code that prepares the query and sends it to the database:
public static List<Map<String, Object>> executeQuery(final String query,
Map<Integer, Object> data) {
List<Map<String, Object>> result = null;
try {
Connection conn = createConnection();
PreparedStatement pstmt = null;
pstmt = conn.prepareStatement(query);
if(data != null) {
pstmt = createPreparedStatement(pstmt, data);
}
System.out.println(pstmt.toString());
//The GET_CASE_FOR_INDEX query uses the executequery function in the else block:
if((pstmt.toString().indexOf("INSERT") >= 0) || (pstmt.toString().indexOf("UPDATE") >= 0)) {
pstmt.executeUpdate();
} else {
ResultSet rs = pstmt.executeQuery();
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
result = new ArrayList<Map<String, Object>>();
/*
* Get the next row of the ResultSet 'rs' and insert a Map of the Column/Value pair
* into the ArrayList of Maps 'result'
*/
while(rs.next()) {
Map<String, Object> row = new HashMap<String, Object>(columns);
for(int i=1; i <= columns; i++) {
try {
row.put(md.getColumnName(i), rs.getObject(i));
} catch(Exception e) {
System.out.println(md.getColumnName(i));
System.out.println(row);
e.printStackTrace();
}
}
result.add(row);
}
}
destroyConnection(conn);
pstmt.close();
} catch(SQLException e) {
//TODO
e.printStackTrace();
}
return result;
}
The function creating the prepared statement:
//creates a prepared statement by checking the type of the value that needs to be set.
private static PreparedStatement createPreparedStatement(
PreparedStatement pstmt, Map<Integer, Object> data) {
try {
for(Integer key : data.keySet()) {
Object value = data.get(key);
System.out.println(key);
if(data.get(key).equals(Types.NULL)) {
pstmt.setNull(key, Types.INTEGER);
} else if(value.getClass().equals(Integer.class)) {
pstmt.setInt(key, (Integer) value);
} else if(value.getClass().equals(String.class)) {
pstmt.setString(key, (String) value);
} else if(value.getClass().equals(Date.class)) {
pstmt.setDate(key, (Date) value);
} else if(value.getClass().equals(Timestamp.class)) {
pstmt.setTimestamp(key, (Timestamp) value);
}
}
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pstmt;
}
And the code snippet which uses the executeQuery function to execute the query and sends it to the web template:
Map<Integer, Object> data_details = new HashMap<Integer, Object>();
data_details.put(1, parameter_ID);
List<Map<String, Object>> details = DBUtility.executeQuery(DBQuery.GET_CASE_FOR_INDEX, data_details);
webContext.setVariable("details", details);//This is where the template variable is being set
System.out.println(details);
The GET_CASE_FOR_INDEX query is :
SELECT numOne.platform , numTwo.platform AS 'PlatformTwo' FROM edb.cases LEFT JOIN
edb.platform as numOne ON (numOne.rank = cases.platform) LEFT JOIN edb.platform as numTwo ON
(numTwo.rank = cases.highestPlatform) WHERE cases.index = ?
When I print the details hash map (which is the result data-set) the key PlatformTwo is entirely absent!
You are using the .getColumnName method of ResultSetMetaData, which returns the name of the underlying column (if available). .getColumnLabel will return the column alias as defined by SELECT ... AS ....
To illustrate, the following Java code
PreparedStatement ps = conn.prepareStatement(
"SELECT platform AS Platypus FROM cases");
ResultSet rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
System.out.println(String.format(
".getColumnName returns \"%s\"",
rsmd.getColumnName(1)));
System.out.println(String.format(
".getColumnLabel returns \"%s\"",
rsmd.getColumnLabel(1)));
returns
.getColumnName returns "platform"
.getColumnLabel returns "Platypus"

How to get data from MYSQL database

I have a database named as "test" in which I have a table named as "first" which contains raw data, I want to get this table data. What should be the prepare statement I have to use in order to get data from table "first" ? Below is the code I am trying. Any help or guidance would be appreciable.
#Path("/database") // Specific URL
#GE
#Produces(MediaType.TEXT_PLAIN)
public String returnDB_Status() throws Exception {
PreparedStatement query = null;
String result = null;
Connection conn = null;
try {
conn = mysql_prac.dbConn().getConnection(); // this works fine ...
query = conn.prepareStatement("SELECT * from first" ); // Table named as "first" is placed inside the connected database.
ResultSet rs = query.executeQuery();
result = "Data received : " + rs;
query.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}
return result;
}
and the source code used get a connection
public class mysql_prac {
private static DataSource mysql_prac = null;
private static Context context = null;
public static DataSource dbConn() throws Exception {
if (mysql_prac != null) {
return mysql_prac;
}
try {
if (context == null) {
context = new InitialContext();
}
mysql_prac = (DataSource) context.lookup("JDBC_ref"); //JNDI ID (JDBC_REF)
} catch (Exception e) {
e.printStackTrace();
}
return mysql_prac;
}
}
You must loop through the ResultSet to get the fields of each row. So I made the following edit together with some comments.Please notice the comments.
try {
conn = mysql_prac.dbConn().getConnection(); // this works fine ...
query = conn.prepareStatement("SELECT * from first" ); // Table named as "first" is placed inside the connected database.
ResultSet rs = query.executeQuery();//You must loop through the results set to get the fields of each row
while(rs.next()){
String dbUserID = rs.getString("column1");//this is just an example to retrieve all data in the column called 'column1'
result = "Data received : " + dbUserID;
System.out.println(result);
}
query.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}

Store the results of ResultSet in a list

My goal is to centralize all the interactions with my MySql database in a single class (e.g. SqlUtils). I basically want to maintain access to ResultSet or a similar class even after the connection is closed. The following way doesn't work as after my business method receives the ResultSet, an exception is thrown because the underlying connection is already closed. I want to emphasize that opening and closing a connection to the database has to take place inside getResultSet().
public ResultSet getResultSet(String sql) {
try (Connection conn = getConnection();){
return conn.createStatement().executeQuery(sql);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
What I'm now thinking to do is something like this:
public List<ResultHolder> getResultSet(String sql) {
List<ResultHolder> list = new LinkedList<>();
try (Connection conn = getConnection();
ResultSet res = conn.createStatement().executeQuery(sql);) {
while(res.next()) {
list.add(res.convertToResultHolder());
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
Is there any class that does what I need, which I expressed as ResultHolder.
If you want to have access to all the resultset data even after connection is closed then I would suggest following:
public List<Map<String, Object>> getResultSet(String sql) {
// this list will hold all the data returned from resultset
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
try (Connection conn = getConnection();
ResultSet rs = conn.createStatement().executeQuery(sql);) {
while(rs.next()) {
// this map corresponds to each row of the resultset
// key: column-name, value: column-value
Map<String, Object> row = new LinkedHashMap<String, Object>();
// populate each row using resultset's Meta data
ResultSetMetaData meta = rs.getMetaData();
for (int i=1; i<=meta.getColumnCount(); i++)
row.put(meta.getColumnName(i), rs.getObject(i));
rows.add(row);
}
} catch (Exception e) {
e.printStackTrace();
}
return rows;
}