I'm creating a simple app which uses JDBC to get data from MySQL. I use a dao to get data from the database. All but one are working fine (code is the same for all DAOs). Also I'm committing INSERT and UPDATE methods manually.
Workbench returns valid result even if I set isolation level read committed manually.
JDBCSessionDao create method:
public void create(Session session) throws SQLException{
try(PreparedStatement ps = conn.prepareStatement(INSERT_SESSION)){
conn.setAutoCommit(false);
LocalTime start = session.getStartTime();
LocalTime end = session.getEndTime();
System.out.println(start + ", " + end);
System.out.println(Time.valueOf(start) + ", " + Time.valueOf(end));
ps.setTime(1, Time.valueOf(start));
ps.setTime(2, Time.valueOf(end));
ps.setDate(3, Date.valueOf(session.getDate()));
ps.setLong(4, session.getMovieId());
ps.executeUpdate();
conn.commit();
conn.setAutoCommit(true);
}
catch (SQLException e){
logger.error(e.getMessage());
conn.rollback();
}
}
JDBCSessionDao findByDate method
public List<Session> findByDate(LocalDate date) {
List<Session> sessions = new ArrayList<>();
SessionMapper mapper = new SessionMapper();
try(PreparedStatement ps = conn.prepareStatement(SELECT_BY_DATE_ORDER_BY_TIME_ASC)){
ps.setDate(1, Date.valueOf(date));
ResultSet rs = ps.executeQuery();
System.out.println(rs.getFetchSize());
while(rs.next()){
Session s = mapper.extractFromResultSet(rs);
sessions.add(s);
}
}
catch (SQLException e){
logger.error(e.getMessage());
}
return sessions;
}
Query:
String SELECT_BY_DATE_ORDER_BY_TIME_ASC = "SELECT * FROM sessions WHERE session_date=? ORDER by start_time ASC";
JDBCDaoFactory getConnection() method:
private Connection getConnection(){
String url = "jdbc:mysql://localhost:3306/cinemajee?useLegacyDatetimeCode=false&serverTimezone=Europe/Kiev";
String user = "root";
String password = "root";
try{
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(url, user, password);
}
catch (SQLException | ClassNotFoundException e){
e.printStackTrace();
throw new RuntimeException();
}
}
Query result in workbench:
query result
Try modifying the query in your code. Perhaps the session_date parameter isn't working. So change from this:
"SELECT * FROM sessions WHERE session_date=? ORDER by start_time ASC"'
to this:
"SELECT * FROM sessions ORDER by start_time ASC LIMIT 5"'
I've forgot to change column names in SessionMapper, they were written in camel case (e.g. sessionId) but my db columns is in snake case (e.g. session_id).
Related
The result set that I'm trying to retrieve from another class returns null, even though the query works.I'm trying to initialize my object based on the records kept in databases,which means if there is initially a record in sqlite,I retrieve the one with latest date.Else,I try to retrieve the earliest one from mysql database. The code that is supposed to retrieve result set from mysql database is like this:
public ResultSet lowestDate() throws SQLException {
ResultSet rs1 = null;
String resultQuery = "SELECT * FROM alarm ORDER BY `timestamp` ASC LIMIT 1";
rs1 = stmt.executeQuery(resultQuery);
return rs1;
}
Statement is initialized globally.And I call this in another class like this:
public void setLastAlarm() throws SQLException, ParseException {
String liteQuery = "SELECT * FROM alarm_entries ORDER BY date(`timestamp`) DESC LIMIT 1";
conn.connectLite();
Connection getCon = conn.getLiteConnection();
try {
stmt = getCon.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
try {
rs = stmt.executeQuery(liteQuery);
if (rs.next()) {
//while (rs.next()) {
nuDate = rs.getString("timestamp");
newDate = format.parse(nuDate);
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
lastAlarm.setTimestamp(newDate);
//}
}
else{
rsq=mysqlConnection.lowestDate();
lastAlarm.setTimestamp(format.parse(rsq.getString("timestamp")));
lastAlarm.setBacklogId(rsq.getBytes("backlog_id"));
}
}catch (Exception e){
e.printStackTrace();
}
}
public void run() {
try {
setLastAlarm();
You never call ResultSet#next() on the result set being returned from the lowestDate() helper method. Hence, the cursor is never being advanced to the first (and only) record in the result set. But I think it is a bad idea to factor your JDBC code in this way. Instead, just inline your two queries like this:
try {
rs = stmt.executeQuery(liteQuery);
if (rs.next()) {
nuDate = rs.getString("timestamp");
newDate = format.parse(nuDate);
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
lastAlarm.setTimestamp(newDate);
}
else {
String resultQuery = "SELECT * FROM alarm ORDER BY timestamp LIMIT 1";
rs = stmt.executeQuery(resultQuery);
if (rs.next()) {
String ts = rs.getString("timestamp");
lastAlarm.setTimestamp(format.parse(ts));
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
}
}
} catch (Exception e){
e.printStackTrace();
}
public static void main(String[] argv) {
try {
createTable();
insertRecordIntoTable("leo","123");
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
private static void createTable() throws SQLException {
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
String sequence = "CREATE SEQUENCE ID_SEQ INCREMENT BY 1 MAXVALUE 99999999999999999999 MINVALUE 1 CACHE 20";
String createTableSQL = "CREATE TABLE DBUSER1("
+ "USER_ID NUMBER(5) NOT NULL, "
+ "USERNAME VARCHAR(20) NOT NULL, "
+ "PASSWORD VARCHAR(20) NOT NULL, "
+ "PRIMARY KEY (USER_ID) "
+ ")";
try {
dbConnection = getDBConnection();
preparedStatement = dbConnection.prepareStatement(createTableSQL);
System.out.println(createTableSQL);
// execute create SQL stetement
preparedStatement.executeUpdate(createTableSQL);
preparedStatement.executeUpdate(sequence);
System.out.println("Table \"dbuser\" is created!");
} 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;
}
private static void insertRecordIntoTable(String username, String password) throws SQLException {
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
String insertTableSQL = "INSERT INTO DBUSER1"
+ "(USER_ID, USERNAME, PASSWORD) VALUES"
+ "(ID_SEQ.NEXTVAL,?,?)";
try {
dbConnection = getDBConnection();
preparedStatement = dbConnection.prepareStatement(insertTableSQL);
// execute insert SQL stetement
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
preparedStatement.executeUpdate();
System.out.println("Record is inserted into DBUSER table!");
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
I cannot find the error when I try to create a sequence for my table.
When I try to insert some data in my table with the sequence it says it doesn't exist, but I did create it. Also I am not sure if i need a preparedStatement.setInt(1, seq_id.nextval); it gives an error but im not quite sure how I would do this
The solution might be adding the schema name (owner) before the name of sequence:
CREATE SEQUENCE some_nameOf_schema.ID_SEQ INCREMENT BY 1 MAXVALUE 99999999999999999999 MINVALUE 1 CACHE 20
You're preparing a statement with one SQL text, and executing the statement with two different SQL texts;
preparedStatement = dbConnection.prepareStatement(createTableSQL);
preparedStatement.executeUpdate(createTableSQL);
preparedStatement.executeUpdate(sequence);
...which is actually invalid according to the docs;
int executeUpdate(String sql)
throws SQLException
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
Note:This method cannot be called on a PreparedStatement or CallableStatement.
What you need to do is to prepare and execute two different statements;
preparedStatement = dbConnection.prepareStatement(createTableSQL);
preparedStatement.executeUpdate();
preparedStatement = dbConnection.prepareStatement(sequence);
preparedStatement.executeUpdate();
In general, it doesn't make much sense to CREATE database objects every time your application starts up, because this is something that's usually done only once, when you install/upgrade the database/schema the application uses.
However, if you really have to do it this way, the current solution could be improved so that the following points are considered:
Only execute the CREATE statements when the objects do not yet exist in the DB. This can be done by first inspecting the USER_OBJECTS data dictionary view.
Use a plain Statement instead of PreparedStatement for executing the DDL (prepared statements are only useful for DML operations that use input variables)
Handle JDBC resources (Connection / Statement / ResultSet) concisely and safely through the try-with-resources construct
Here's how the code could look like:
// query constants
private static final String CHECK_DB_OBJECT =
"SELECT 1 FROM user_objects WHERE object_name = ?";
private static final String CREATE_SEQUENCE =
"CREATE SEQUENCE ID_SEQ INCREMENT BY 1 MAXVALUE 99999999999999999999" +
" MINVALUE 1 CACHE 20";
private static final String CREATE_TABLE = "CREATE TABLE DBUSER1("
+ "USER_ID NUMBER(5) NOT NULL, "
+ "USERNAME VARCHAR(20) NOT NULL, "
+ "PASSWORD VARCHAR(20) NOT NULL, "
+ "PRIMARY KEY (USER_ID) "
+ ")";
/* clip the main method etc. */
/**
* Creates the table and sequence only if they do not already exist.
*/
private static void createTableAndSequenceIfAbsent() {
try (Connection dbConnection = DriverManager.getConnection(
DB_CONNECTION, DB_USER, DB_PASSWORD);
PreparedStatement ps = dbConnection
.prepareStatement(CHECK_DB_OBJECT)) {
if (!dbObjectExists(ps, "ID_SEQ")) {
executeDDL(dbConnection, CREATE_SEQUENCE);
}
if (!dbObjectExists(ps, "DBUSER1")) {
executeDDL(dbConnection, CREATE_TABLE);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private static boolean dbObjectExists(PreparedStatement ps,
String objectName) throws SQLException {
ps.setString(1, objectName);
ResultSet rs = ps.executeQuery();
// if the #CHECK_DB_OBJECT query returned a row, the object exists
return rs.next();
}
private static void executeDDL(Connection c, String sql)
throws SQLException {
try (Statement st = c.createStatement()) {
st.execute(sql);
}
}
I'm getting this error even though I am not trying to edit the table/column:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: The operation failed because the operation is not supported with the type of the specified table. Specified table: "DASH103985.wajihs". Table type: "ORGANIZE BY COLUMN". Operation: "WITH RS".. SQLCODE=-1667, SQLSTATE=42858
#MultipartConfig
public class DemoServlet extends HttpServlet {
private static Logger logger = Logger.getLogger(DemoServlet.class.getName());
private static final long serialVersionUID = 1L;
#Resource(lookup="jdbc/db2")DataSource dataSource;
private String getDefaultText() {
TweetsCombined = new String(" ");
try {
// Connect to the Database
Connection con = null;
try {
System.out.println("Connecting to the database");
} catch (SQLException e) {
TweetsCombined = "first" +e;
}
// Try out some dynamic SQL Statements
Statement stmt = null;
try {
stmt = con.createStatement();
String tableName = "wajihs";// change table name here to one
// chosen in the first website
String columnName = "msgBody";// msgBody is where the tweets
// are stored
String query = "SELECT * FROM \"" + tableName + "\"";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
content = rs.getString(columnName) + ". ";
if (content.toLowerCase().contains("RT".toLowerCase())
|| content.toLowerCase().contains("Repost: ".toLowerCase())) {
// do nothing
}
else {
TweetsCombined.concat(content);
}
}
// Close everything off
// Close the Statement
stmt.close();
// close
con.commit();
// Close the connection
con.close();
} catch (Exception e) {
TweetsCombined = "second" +e;
System.out.println(e.getMessage());
}
} catch (Exception e) {
TweetsCombined = "third" + e;
System.out.println(e);
}
return TweetsCombined;
}
As I explained here, dashDB, with its BLU Acceleration features, has certain limitations compared to DB2 without BLU Acceleration. In your case it is that you can only run queries with the CS isolation level against column-organized tables.
Either change your connection configuration to use CS isolation level or create your table(s) while explicitly specifying ORGANIZE BY ROW.
I need help with the code below and getting it to return a true or false value. Any and all help would be appreciated.
public synchronized static boolean checkCompanyName(String companyName,
Statement statement) {
try {
ResultSet res = statement
.executeQuery("SELECT `companyName` FROM `companys` WHERE companyName = '"
+ companyName + "';");
boolean containsCompany = res.next();
res.close();
return containsCompany;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Try to make your query like this:
ResultSet res = statement.executeQuery("SELECT companyName FROM companys WHERE companyName = " + companyName);
Or you can either you PreparedStatement which is better then you did before
You should be using a PreparedStatement (for that end pass the Connection in to the method). Also, you should retrieve the value from the ResultSet and validate it matches your companyName. Something like
static final String query = "SELECT `companyName` FROM "
+ "`companys` WHERE companyName = ?";
public synchronized static boolean checkCompanyName(String companyName,
Connection conn) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(query);
ps.setString(1, companyName);
rs = ps.executeQuery();
if (rs.next()) {
String v = rs.getString(1);
return v.equals(companyName);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
}
}
}
return false;
}
Two comments:
You only need to check if there's at least one row matching your criteria, so you can use .first()
Your code is vulnerable to SQL Injection attacks. Please read this to learn more about it.
The easiest way to avoid SQL injection attacs is to use prepared statements. So let me strike two birds with a single stone and give you a solution using them:
/*
Check if the company exists.
Parameters:
conn - The connection to your database
company - The name of the company
Returns:
true if the company exists, false otherwise
*/
public static boolean checkCompanyName(Connection conn, String company) {
boolean ans = false;
try(PreparedStatement ps = conn.prepareStatement(
"select companyName from companies where companyName = ?"
) // The question mark is a place holder
) {
ps.setString(1, company); // You set the value for each place holder
// using setXXX() methods
try(ResultSet rs = ps.executeQuery()) {
ans = rs.first();
} catch(SQLException e) {
// Handle the exception here
}
} catch(SQLException e) {
// Handle the exception here
}
return ans;
}
Suggested reads:
Bobby Tables: A guide to preventing SQL injection
The Java Tutorials - JDBC: Using prepared statements
I have a problem trying to execute more than one query into my Java Application code.
I have a procedure that is called in main and is in the class "Fant":
public void XXX(){
Connectivity con=new Connectivity(); // this class set up the data for the connection to db; if ( !con.connect() ) {
System.out.println("Error during connection.");
System.out.println( con.getError() );
System.exit(0);
}
ArrayList<User> blabla=new ArrayList<User>();
blabla=this.getAllUsers(con);
for (User u:blabla)
{
try {
Connectivity coni=new Connectivity();//start a new connection each time that i perform a query
Statement t;
t = coni.getDb().createStatement();
String query = "Select count(*) as rowcount from berebe.baraba";
ResultSet rs = t.executeQuery(query);
int numPrenotazioni=rs.getInt("rowcount");
rs.close(); //close resultset
t.close(); //close statement
coni.getDb().close(); //close connection
}
}
catch (SQLException e)
{
System.err.println("SQLState: " +
((SQLException)e).getSQLState());
System.err.println("Error Code: " +
((SQLException)e).getErrorCode());
}
}
}
The called function is defined as:
ArrayList<User> getAllUsers(Connectivity con) {
try{
ArrayList<User> userArrayList=new ArrayList<User>();
String query = "Select idUser,bubu,lala,sisi,gogo,gg from berebe.sasasa";
Statement t;
t = con.getDb().createStatement();
ResultSet rs = t.executeQuery(query);
while (rs.next())
{
User utente=new User(....); //user fields got from query
userArrayList.add(utente);
}
rs.close();
t.close();
con.disconnect(); //disconnect the connection
return userArrayList;
} catch (SQLException e) {
}
return null;
}
The main is:
public static void main(String[] argv) {
ArrayList<User> users=new ArrayList<User>();
System.out.println("-------- MySQL JDBC Connection Testing ------------");
Fant style = new Fant();
style.XXX();
}
The query performed into "getAllusers" is executed and into the arraylist "blabla" there are several users; the problem is that the second query that needs the count is never executed.
The MYSQlState given when running is= "S1000" and the SQLERROR is "0".
Probably i'm mistaking on connections issues but i'm not familiar with statements,connections,resultsets.
Thank you.
You might forget to call rs.next() before getting the result form it in XXX()methods as shown below:
ResultSet rs = t.executeQuery(query);
// call rs.next() first here
int numPrenotazioni=rs.getInt("rowcount");