Batch processing JDBC - java

I am practicing JDBC batch processing and having errors:
error 1: Unsupported feature
error 2: Execute cannot be empty or null
Property files include:
itemsdao.updateBookName = Update Books set bookname = ? where books.id = ?
itemsdao.updateAuthorName = Update books set authorname = ? where books.id = ?
I know I can execute about DML statements in one update, but I am practicing batch processing in JDBC.
Below is my method
public void update(Item item) {
String query = null;
try {
connection = DbConnector.getConnection();
property = SqlPropertiesLoader.getProperties("dml.properties");
connection.setAutoCommit(false);
if ( property == null )
{
Logging.log.debug("dml.properties does not exist. Check property loader or file name is spelled right");
return;
}
query = property.getProperty("itemsdao.updateBookName");
statement = connection.prepareStatement(query);
statement.setString(1, item.getBookName());
statement.setInt(2, item.getId());
statement.addBatch(query);
query = property.getProperty("itemsdao.updateAuthorName");
statement = connection.prepareStatement(query);
statement.setString(1, item.getAuthorName());
statement.setInt(2, item.getId());
statement.addBatch(query);
statement.executeBatch();
connection.commit();
}catch (ClassNotFoundException e) {
Logging.log.error("Connection class does not exist", e);
}
catch (SQLException e) {
Logging.log.error("Violating PK constraint",e);
}
//helper class th
finally {
DbUtil.close(connection);
DbUtil.closePreparedStatement(statement);
}

You are mixing together methods of Statement and PreparedStatement classes:
(addBatch(String sql) belongs to Statement and cannot be called on a PreparedStatement or CallableStatement
addBatch() is to be used with PreparedStatement (as your tutorial shows).
Oracle implements both it's own and standard (JDBC 2.0) batch processing. From the Standard Update Batching docs:
In Oracle JDBC applications, update batching is intended for use with
prepared statements that are being processed repeatedly with different
sets of bind values.

Related

Why can't I get results from my Inner Join JDBC Query?

This JDBC query does not return anything despite it working on my SQLite Database Browser, no matter what I tried. The snippet is pretty self-explanatory of the results I'm looking for.
public void getCountryIdLocationIdDepartmentIdParEmploye(Employe employe) {
String query = "SELECT countries.country_id AS idc, locations.location_id AS idl, departments.department_id AS idd
FROM countries
INNER JOIN locations ON countries.country_id = locations.country_id
INNER JOIN departments ON locations.location_id = departments.location_id
INNER JOIN employees ON departments.department_id = employees.department_id
AND employees.employee_id = ?";
try {
PreparedStatement ps = maConnexion.prepareStatement(query);
ResultSet rs = ps.executeQuery();
ps.setInt(1, employe.getId());
setCountry_id(rs.getString("idc"));
setLocation_id(rs.getInt("idl"));
setDepartment_id(rs.getInt("idd"));
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
I've tried to replace setCountry_id(rs.getString("idc")); with setCountry_id(rs.getString(1)); etc. already but no good, my attributes stay unchanged.
Regards,
PS: country_id is indeed a string
In a compliant JDBC driver this should throw a SQLException because you set the parameter after executing the query (which means it should not be possible to execute the statement). It sounds like the SQLite JDBC driver has a bug in that regard.
You need to set the parameter before executing:
try (PreparedStatement ps = maConnexion.prepareStatement(query)) {
ps.setInt(1, employe.getId());
try (ResultSet rs = ps.executeQuery()) {
setCountry_id(rs.getString("idc"));
setLocation_id(rs.getInt("idl"));
setDepartment_id(rs.getInt("idd"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
Also observe the use of try-with-resources, which ensures you don't leak the prepared statement and result set.

Rollback doesn't work in java

I have a method which does a simple mysql insert, when I tried to rollback the insert action as follow, on an error but it is not rollingback on errors, please assist me,
public void addFamer(FamerDTO famer) throws Exception {
Connection con = JDBCConnectionPool.getInstance().checkOut();
con.setAutoCommit(false);
try {
String generalFamerDataSQL = "INSERT INTO famers(famer_code, name_wt_initials, full_name, gender, "
+ "nic_or_passport_no, sc_possition, phone_home, phone_mobile, phone_office) VALUES(?,?,?,?,?,?,?,?,?)";
PreparedStatement insertFamerPS = con.prepareStatement(generalFamerDataSQL, PreparedStatement.RETURN_GENERATED_KEYS);
insertFamerPS.setString(1, famer.getFamerCode());
insertFamerPS.setString(2, famer.getNameWithInitials());
insertFamerPS.setString(3, famer.getNameInFull());
insertFamerPS.setString(4, famer.getGender());
insertFamerPS.setString(5, famer.getNICorPassportNo());
insertFamerPS.setString(6, famer.getSocietyPosission());
insertFamerPS.setString(7, famer.getHomePhone());
insertFamerPS.setString(8, famer.getMobilePhone());
insertFamerPS.setString(9, famer.getOfficePhone());
insertFamerPS.execute();
String famerRelations = "INSERT INTO org_reg_blk_soc_fmr(org_id, region_id, famer_id, block_id, soc_id) "
+ "VALUES (?,?,?,?,?)";
PreparedStatement famerRelationsPS = con.prepareStatement(famerRelations);
famerRelationsPS.setInt(1, famer.getOrganization().getOrg_id());
famerRelationsPS.setInt(2, famer.getRegion().getRegion_id());
famerRelationsPS.setInt(3, famerID);
famerRelationsPS.setInt(4, famer.getBlock().getBlockId());
famerRelationsPS.setInt(6, famer.getSociety().getSoc_id()); //intentionally made an error here to test, put index as 6 for 5
famerRelationsPS.execute();
con.commit();
} catch (Exception e) {
if (con != null) {
logger.info("Rolling back!");
con.rollback();
}
logger.error(e.getLocalizedMessage());
} finally {
con.setAutoCommit(true);
JDBCConnectionPool.getInstance().checkIn(con);
}
}
once this method is called with the required parameters as there is a error in the second insert statement I expected to rollback the first insert action. but thought the error is shown, a record is added to the data base by the first insert statement.
Just to check - what is the table type you're using? Last time I used MySQL, MyISAM tables didn't support transactions, meaning you have to used another table type e.g. InnoDB.

How to pass userdefined table type to MSSQL request from Java

Given a simple stored procedure which has a table with a single column of integers as argument:
CREATE PROCEDURE [dbo].[table_sel]
#tbl INT32Table READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT value FROM #tbl
END
How do I execute this stored procedure from Java? From C# this does what I want:
SqlConnection sqlconn;
System.Data.DataTable tbl = new System.Data.DataTable("INT32Table", "dbo");
tbl.Columns.Add("value", typeof(int));
tbl.Rows.Add(2);
tbl.Rows.Add(3);
tbl.Rows.Add(5);
tbl.Rows.Add(7);
tbl.Rows.Add(11);
using (SqlCommand command = new SqlCommand("table_sel"))
{
command.Connection = sqlconn;
command.Parameters.AddWithValue("#tbl", tbl);
command.CommandType = System.Data.CommandType.StoredProcedure;
SqlDataReader reader = command.ExecuteReader();
//do stuff
}
Oh sorry,
as far as I know there's no such table object in Java, you can use cs.setObject() but then again you should obtain that object from somewhere (query on mssql server ?).
If you're looking for performance on inserts with JDBC then you should consider preparedStatements and batch execution.
java.sql.connection connection = //driver, url, database, credentials ...
try
{
PreparedStatement ps =
connection.prepareStatement("insert into tbl values (?)");
ps.setInt(1, your 1st int);
ps.addBatch();
ps.setInt(1, your 2nd int);
ps.addBatch();
ps.setInt(1, your 3rd int);
ps.addBatch();
ps.executeBatch();
}
catch (SQLException e)
{
// err handling goes here
}
finally
{
// close your resources
}
Regards
S
You Cannt pass TVP's using JDBC. The Microsoft JDBC team is still working on this as they mentioned 2 years ago. Refer the Link :
visit : http://blogs.msdn.com/b/jdbcteam/archive/2012/04/03/how-would-you-use-table-valued-parameters-tvp.aspx
Try some alternate solution instead of using TVP's by passing XML parameter and with OPENXML() in procedure body.
In Java you should use CallableStatement.
eg.
java.sql.connection connection = //driver, url, database, credentials ...
try
{
CallableStatement cs =
connection.prepareCall("{ call table_sel(?) }");
cs.setInt(1, your int);
cs.execute();
}
catch (SQLException e)
{
// err handling goes here
}
finally
{
// close your ressources
}
Regards
S

SQLException: No value specified for parameter 1

I encountered the following error when I was executing my application:
java.sql.SQLException: No value specified for parameter 1
What does it mean?
My UserGroup list in my dao:
public List<UsuariousGrupos> select(Integer var) {
List<UsuariousGrupos> ug= null;
try {
conn.Connection();
stmt = conn.getPreparedStatement("select id_usuario, id_grupo from usuarios_grupos where id_grupo ='" + var + "'");
ResultSet rs = stmt.executeQuery();
ug = new ArrayList<UsuariousGrupos>();
while (rs.next()) {
ug.add(getUserGrupos(rs));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn.Disconnected();
}
return ug;
}
public UsuariousGrupos getUserGrupos(ResultSet rs) {
try {
UsuariousGrupos ug = new UsuariousGrupos(rs.getInt("id_usuario"), rs.getInt("id_grupo"));
return ug;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
My get list of User groups in my managed bean:
public List<UsuariousGrupos> getListOfUserGroups() {
List<UsuariousGrupos> usuariosGruposList = userGrpDAO.select(var2);
listOfUserGroups = usuariosGruposList;
return listOfUserGroups;
}
My JSF page:
<p:dataTable var="usergroups" value="#{usuariousGruposBean.listOfUserGroups}">
<p:column headerText="" style="height: 0" rendered="false">
<h:outputText value="#{usergroups.id_grupo}"/>
</p:column>
My data table is able to display the list of groups from the database. However, when I select an individual row within my data table, it takes some time for the application to establish connection with my database to display the selected result.
Also, it is weird that the application is able to display certain selected results quicker than others. Does it have anything to do with the Exception I pointed out at the beginning?
Error:
Disconnected
Connected!!
java.sql.SQLException: No value specified for parameter 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:929)
at com.mysql.jdbc.PreparedStatement.checkAllParametersSet(PreparedStatement.java:2560)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2536)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2462)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2216)
at br.dao.UsuariousGruposDAO.select(UsuariousGruposDAO.java:126)
at br.view.UsuariousGruposBean.getListOfUserGroups(UsuariousGruposBean.java:54)
SEVERE: Error Rendering View[/index.xhtml]
javax.el.ELException: /index.xhtml #61,99 value="#{usuariousGruposBean.listOfUserGroups}": Error reading 'listOfUserGroups' on type br.view.UsuariousGruposBean
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
There is no such method as Connection() and getPreparedStatement() on java.sql.Connection.
conn.Connection();
stmt = conn.getPreparedStatement("select id_usuario, id_grupo from usuarios_grupos where id_grupo ='" + var + "'");
The conn is clearly a homegrown wrapper around JDBC code. Your particular problem is likely caused by the code behind the getPreparedStatement() method. It's apparently appending a ? to the SQL string before delegating through to the real connection.prepareStatement() method.
You probably don't want to hear this, but your JDBC approach is totally broken. This design indicates that the JDBC Connection is hold as a static or instance variable which is threadunsafe.
You need to totally rewrite it so that it boils down to the following proper usage and variable scoping:
public List<UsuariousGrupos> select(Integer idGrupo) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<UsuariousGrupos> usuariousGrupos = new ArrayList<UsariousGrupos>();
try {
connection = database.getConnection();
statement = connection.prepareStatement("select id_usuario, id_grupo from usuarios_grupos where id_grupo = ?");
statement.setInt(1, idGrupo);
resultSet = statement.executeQuery();
while (resultSet.next()) {
usuariousGrupos.add(mapUsuariousGrupos(resultSet));
}
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return usuariousGrupos;
}
See also:
How to declare a global static class in Java?
Unrelated to the concrete question, you've another problem. The following exception
javax.el.ELException: /index.xhtml #61,99 value="#{usuariousGruposBean.listOfUserGroups}": Error reading 'listOfUserGroups' on type br.view.UsuariousGruposBean
indicates that you're doing the JDBC stuff inside a getter method instead of (post)constructor or (action)listener method. This is also a very bad idea because a getter can be called more than once during render response. Fix it accordingly.
See also:
Why JSF calls getters multiple times
Usually you get this kind of error when using prepared statements and forgot to set the parameter with index 1.
In this case, you are using prepared statements but there is nothing to prepare, you make the query string by hand.
Also, you may run into additional problems because you're concatenating an Integer between aposthrophes. Numeric values go without them.
So, it should be like this:
stmt = conn.getPreparedStatement("select id_usuario, id_grupo from usuarios_grupos where id_grupo = " + var + ";");
But actually you should use something like getStatement() or use the getPreparedStatement() correctly (place a ? at the position of var and setInteger() to place it in.
So the final solution would be:
stmt = conn.getPreparedStatement("select id_usuario, id_grupo from usuarios_grupos where id_grupo = ?;");
stmt.setInt(1, var);
If you use
stmt = conn.getPreparedStatement("select id_usuario, id_grupo
from usuarios_grupos
where id_grupo = ?);
You have to
stmt.setInt(1, var);
before
ResultSet rs = stmt.executeQuery();
To assign a value to the first parameter (i.e. Parameter 1). If not your exception will occur.
Recently I have also met this problem, in my case I used jdbcTemplate batchUpdate method to batch insert records
void batchInsert(final List<EntryDataDO> doList) {
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
final EntryDataDO dataDO = doList.get(i);
if (dataDO == null){
return;
}
ps.setString(1, dataDO.getId());
ps.setString(2, dataDO.getDataCode());
...
}
#Override
public int getBatchSize() {
return doList.size();
}
});
}
Reason is that if the first element of doList is null and it will directly return and it will cause Caused by: java.sql.SQLException: No value specified for parameter 1 but if not first element is null, the batchUpdate is ok but the records will duplicate e.g. the second element is null, the second will duplicate the first record
insert into t (id,...) values (1,...),(1,...),(3,...)
So the solution is:
1. first exclude null element from doList
2. then call batchInsert(doListWithoutNull) that is to say: cannot exclude element inner org.springframework.jdbc.core.BatchPreparedStatementSetter#setValues
ResultSet rs = stmt.executeQuery();
Don't use this line before operation performed.

How can I avoid ResultSet is closed exception in Java?

As soon as my code gets to my while(rs.next()) loop it produces the ResultSet is closed exception. What causes this exception and how can I correct for it?
EDIT: I notice in my code that I am nesting while(rs.next()) loop with another (rs2.next()), both result sets coming from the same DB, is this an issue?
Sounds like you executed another statement in the same connection before traversing the result set from the first statement. If you're nesting the processing of two result sets from the same database, you're doing something wrong. The combination of those sets should be done on the database side.
This could be caused by a number of reasons, including the driver you are using.
a) Some drivers do not allow nested statements. Depending if your driver supports JDBC 3.0 you should check the third parameter when creating the Statement object. For instance, I had the same problem with the JayBird driver to Firebird, but the code worked fine with the postgres driver. Then I added the third parameter to the createStatement method call and set it to ResultSet.HOLD_CURSORS_OVER_COMMIT, and the code started working fine for Firebird too.
static void testNestedRS() throws SQLException {
Connection con =null;
try {
// GET A CONNECTION
con = ConexionDesdeArchivo.obtenerConexion("examen-dest");
String sql1 = "select * from reportes_clasificacion";
Statement st1 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs1 = null;
try {
// EXECUTE THE FIRST QRY
rs1 = st1.executeQuery(sql1);
while (rs1.next()) {
// THIS LINE WILL BE PRINTED JUST ONCE ON
// SOME DRIVERS UNLESS YOU CREATE THE STATEMENT
// WITH 3 PARAMETERS USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
System.out.println("ST1 Row #: " + rs1.getRow());
String sql2 = "select * from reportes";
Statement st2 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// EXECUTE THE SECOND QRY. THIS CLOSES THE FIRST
// ResultSet ON SOME DRIVERS WITHOUT USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
st2.executeQuery(sql2);
st2.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs1.close();
st1.close();
}
} catch (SQLException e) {
} finally {
con.close();
}
}
b) There could be a bug in your code. Remember that you cannot reuse the Statement object, once you re-execute a query on the same statement object, all the opened resultsets associated with the statement are closed. Make sure you are not closing the statement.
Also, you can only have one result set open from each statement. So if you are iterating through two result sets at the same time, make sure they are executed on different statements. Opening a second result set on one statement will implicitly close the first.
http://java.sun.com/javase/6/docs/api/java/sql/Statement.html
The exception states that your result is closed. You should examine your code and look for all location where you issue a ResultSet.close() call. Also look for Statement.close() and Connection.close(). For sure, one of them gets called before rs.next() is called.
You may have closed either the Connection or Statement that made the ResultSet, which would lead to the ResultSet being closed as well.
Proper jdbc call should look something like:
try {
Connection conn;
Statement stmt;
ResultSet rs;
try {
conn = DriverManager.getConnection(myUrl,"","");
stmt = conn.createStatement();
rs = stmt.executeQuery(myQuery);
while ( rs.next() ) {
// process results
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
} finally {
// you should release your resources here
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
you can close connection (or statement) only after you get result from result set. Safest way is to do it in finally block. However close() could also throe SqlException, hence the other try-catch block.
I got same error everything was correct only i was using same statement interface object to execute and update the database.
After separating i.e. using different objects of statement interface for updating and executing query i resolved this error. i.e. do get rid from this do not use same statement object for both updating and executing the query.
Check whether you have declared the method where this code is executing as static. If it is static there may be some other thread resetting the ResultSet.
make sure you have closed all your statments and resultsets before running rs.next. Finaly guarantees this
public boolean flowExists( Integer idStatusPrevious, Integer idStatus, Connection connection ) {
LogUtil.logRequestMethod();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connection.prepareStatement( Constants.SCRIPT_SELECT_FIND_FLOW_STATUS_BY_STATUS );
ps.setInt( 1, idStatusPrevious );
ps.setInt( 2, idStatus );
rs = ps.executeQuery();
Long count = 0L;
if ( rs != null ) {
while ( rs.next() ) {
count = rs.getLong( 1 );
break;
}
}
LogUtil.logSuccessMethod();
return count > 0L;
} catch ( Exception e ) {
String errorMsg = String
.format( Constants.ERROR_FINALIZED_METHOD, ( e.getMessage() != null ? e.getMessage() : "" ) );
LogUtil.logError( errorMsg, e );
throw new FatalException( errorMsg );
} finally {
rs.close();
ps.close();
}
A ResultSetClosedException could be thrown for two reasons.
1.) You have opened another connection to the database without closing all other connections.
2.) Your ResultSet may be returning no values. So when you try to access data from the ResultSet java will throw a ResultSetClosedException.
It happens also when using a ResultSet without being in a #Transactional method.
ScrollableResults results = getScrollableResults("select e from MyEntity e");
while (results.next()) {
...
}
results.close();
if MyEntity has eager relationships with other entities. the second time results.next() is invoked the ResultSet is closed exception is raised.
so if you use ScrollableResults on entities with eager relationships make sure your method is run transactionally.
"result set is closed" happened to me when using tag <collection> in MyBatis nested (one-to-many) xml <select> statement
A Spring solution could be to have a (Java) Spring #Service layer, where class/methods calling MyBatis select-collection statements are annotated with
#Transactional(propagation = Propagation.REQUIRED)
annotations being:
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
this solution does not require to set the following datasource properties (i.e., in JBoss EAP standalone*.xml):
<xa-datasource-property name="downgradeHoldCursorsUnderXa">**true**\</xa-datasource-property>
<xa-datasource-property name="resultSetHoldability">**1**</xa-datasource-property>

Categories