jdbcTemplate pass in null value - mysql

I'm working with mysql and spring 4.1.6, but am having trouble sending in a null variable to the data base. I know to send a null value the syntax IS NULL is used but the field being sent into the data base is optional(the only optional value in the entire object), so it may be null or may have a value.
My request to database that simple checks if the address exists called by CRUD methods:
Note: the variable in question is street2
public boolean doesExist(Address address){
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 ? AND city=? AND state=? AND zip=? AND country=?);";
String s = isNullDBQuery(address.getStreet2());
jdbcTemplate = new JdbcTemplate(dataSource);
int exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), isNullDBQuery(address.getStreet2()), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
if(exist == 1){
return true;
} else {
return false;
}
}
My isNullDBQuery:
private String isNullDBQuery(String s){
if(s == null){
return "IS NULL";
} else {
return "=" + s;
}
}
The error that's being returned is a syntax error with 'IS NULL'. The query sent to the database is street2 'IS NULL' rather then street2 IS NULL. Is it possible to get rid of the single quotation marks in my request? or is there a better way to do this?
any help is appreciated

No. Only values may be passed as parameters of a prepared statement. Not arbitrary portions of the query.
You need to use two different SQL queries (or generate it dynamically based on the nullness of the street2).

I managed to figure out how to achieve what I wanted:
public boolean doesExist(Address address){
String street2 = stringIsNull(address.getStreet2());
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 " + street2 + " AND city=? AND state=? AND zip=? AND country=?);";
jdbcTemplate = new JdbcTemplate(dataSource);
int exist;
if(street2.equals("IS NULL")){
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
} else {
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getStreet2(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
}
if(exist == 1){
return true;
} else {
return false;
}
}
private String stringIsNull(String string){
if(string == null) {
return "IS NULL";
} else {
return "=?";
}
}

Related

Why org.apache.commons.lang.StringUtils.isBlank() returns false for empty and null values

I saw the implementation of StringUtils.isBlank() and was surprised that in my case, it is not working as expected.
I was writing a Junit and I faced this issue.
AmazonSNSRegistrationService.java:
public String doAWSSNSNDeviceRegistration(Map<String, Object> jsonBody){
String deviceId = (String) jsonBody.get(PushNotificationsConstants.DEVICE_ID);
String pushToken = (String) jsonBody.get(PushNotificationsConstants.PUSH_TOKEN);
String appId = (String) jsonBody.get(PushNotificationsConstants.APP_ID);
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(pushToken) || StringUtils.isBlank(appId)) {
System.out.println("$$$$$ Empty");
throw new Exception("Required parameters are empty.");
}
return registerWithSNS(pushToken, deviceId, appId);
}
AmazonSNSRegistrationServiceTest.java:
#Test
public void doAWSSNSNDeviceRegistrationBlankTest() {
Map<String, Object> jsonBody = new HashMap<String, Object>();
jsonBody.put(PushNotificationsConstants.APP_ID, "");
jsonBody.put(PushNotificationsConstants.DEVICEID, " ");
try{
amazonSNSRegistrationService.doAWSSNSNDeviceRegistration(jsonBody);
}
catch(Exception e){
}
}
I'm not passing Push Token , so it will be null. Other values are either "" or " ".
But in if condition, none of the statements give true. All return false and the Exception is not thrown. I want this code to throw exception when any of the statement in if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(pushToken) || StringUtils.isBlank(appId)) returns true.

Rename value within query

I have a problem with renaming a specific value in a column in mySQL Database. At first i thought i could just use 'AS' to rename, but i'm actually trying to rename a value in a column. My column is named FoundLost. In this column I Store values '0' and '1'. '0' is Found and '1' is Lost.
The reason I need to rename this values is because I use the data from this database to create a pieChart. with the function .getName it gives the names '0' and '1'.
I was hoping someone could help me out!
The class with the query is the code below:
public static ObservableList getPChartFoundLost() {
String query = "SELECT FoundLost, concat(round(count(FoundLost) *100 / (SELECT count(FoundLost) FROM Luggage))) AS percent FROM Luggage GROUP BY FoundLost";
ObservableList FoundLost = FXCollections.observableArrayList();
Connection connection = DatabaseUtils.connect();
if (connection != null) {
try {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
while (resultSet.next()) {
FoundLost.add(new PieChart.Data(resultSet.getString("FoundLost"), resultSet.getInt("percent")));
}
resultSet.close();
statement.close();
} catch (SQLException sqle) {
System.out.println(sqle.getMessage());
}
DatabaseUtils.disconnect(connection);
}
return FoundLost;
}
Controller:
public void clickPChartFoundLost(ActionEvent event) {
//PieChart
ObservableList FoundLost = StatisticsUtils.getPChartFoundLost();
pieChart.setVisible(true);
pieChart.setData(FoundLost);
pieChart.setTitle("Found and Lost luggage");
for (final PieChart.Data data : pieChart.getData()) {
data.getNode().addEventHandler(MouseEvent.ANY,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
//Label vullen met data van Observable list uit Database
pieChartValueLable.setText(String.valueOf(data.getName()) + ": "
+ String.valueOf(data.getPieValue()) + "%");
}
});
}
}
Thanks!!
In your query, try this as your first column instead of just FoundLost. It translates your 0 and 1 values to meaningful strings for your chart. The rest of your query can stay the same.
IF(FoundLost = 0,'Found','Lost') AS FoundLost

how to get parameter when mybatis exception

I'm sorry. I can't write English well.
this is my mybatis error message(e.getMessage())
### Error updating database. Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
### The error may involve default.user-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO USER (name) VALUES (?)
### Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name'
at row 1; SQL []; Data truncation: Data too long for column 'name' at row 1; nested exception is
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
I want know parameter when Exception occur.
SQL: INSERT INTO USER (name) VALUES (?) >> I want get this question value.
i try this code
try {
sqlSessionTemplate.insert("namespace.id", parameter);
} catch (Exception e) {
if (e instanceof BadSqlGrammarException) {
logger.error("{}", e.getMessage());
} else if (e instanceof DataIntegrityViolationException) {
logger.error("{}", e.getMessage());
} else if (e instanceof MysqlDataTruncation) {
logger.error("{}", e.getMessage());
}
}
DataIntegrityViolationException, MysqlDataTruncation does not support get error paramters.
this is a sample, I want know get parameters(object) in Exception.
Can you give me some advice to solve this problem?Thanks.
Set up logging in MyBatis and set it to TRACE level. That way you will have your whole INSERT statement (with actually used parameters) written in the log file.
you can write a mybatis's plugin,as follow:
#Intercepts({ #Signature(type = ParameterHandler.class, method = "setParameters", args = { PreparedStatement.class }) })
public class SQLErrorContextInterceptor implements Interceptor {
private final ILogger logger = new LoggerImpl(this.getClass());
#Override
public Object intercept(Invocation invocation) throws Throwable {
invocation.proceed();
Object target=invocation.getTarget();
if( ! (target instanceof DefaultParameterHandler) ){
return null;
}
DefaultParameterHandler hander=(DefaultParameterHandler)target;
//obtains 5 fields from DefaultParameterHandler object
Class<?> clz =hander.getClass();
Field f = clz.getDeclaredField("mappedStatement");
f.setAccessible(true);
MappedStatement mappedStatement=(MappedStatement)f.get(hander);
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry=mappedStatement.getConfiguration().getTypeHandlerRegistry();
f=clz.getDeclaredField("boundSql");
f.setAccessible(true);
BoundSql boundSql=(BoundSql)f.get(hander);
Object parameterObject=hander.getParameterObject();
//used to stored parameters values order by sql parameters
List<Object> columnValues = new ArrayList<Object>();
// get parameters'value by for-each
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
value = metaObject == null ? null : metaObject.getValue(propertyName);
}
columnValues.add(value);
}
}
}
// overwrite sql's context in ErrorContext, and append parameters's value-str
ErrorContext.instance().sql(boundSql.getSql() + " parameters:" + this.getParameterValueString(columnValues));
return null;
}
private String getParameterValueString(List<Object> columnValues) {
List<Object> typeList = new ArrayList<Object>(columnValues.size());
for (Object value : columnValues) {
if (value == null) {
typeList.add("null");
} else {
typeList.add(value + "(" + value.getClass().getSimpleName() + ")");
}
}
final String parameters = typeList.toString();
return parameters.substring(1, parameters.length() - 1);
}
#Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
#Override
public void setProperties(Properties properties) {
}
}

ibatis can not rereurn primary key for batch insert

in my project , we use springmvc , spring and ibatis framework, the problem is :
in my dao code is :
#Override
public Integer insertAdzoneEnvInfoBatch(List<AdzoneEnvInfoDO> adzoneEnvInfoList) {
return executeInsertBatch("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfoList);
}
public Integer executeInsertBatch(final String sqlID, final List stList) {
Integer result = new Integer(-1);
if ((sqlID != null) && (stList != null) && !stList.isEmpty()) {
result = (Integer) getSqlMapClientTemplate().execute(
new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor)
throws SQLException {
Integer result = new Integer(-1);
executor.startBatch();
for (int i = 0; i < stList.size(); i++) {
executor.insert(sqlID, stList.get(i));
}
result = new Integer(executor.executeBatch());
return result;
}
});
}
return result;
}
in my sqlmap file ,the sql is
<insert id="AdzoneEnvInfoDAO.insertAdzoneEnvInfo" parameterClass="adzoneEnvInfo">
insert into c_adzone_env_info(
url,adzoneid,pid,total_screen,screen_no,snapshot,adzone_num,ali_adzone_num,same_screen_num,same_screen_ali_num,
covered,ad_link,ad_snapshot,adzone_owner,
adzone_style,adzone_size,date_time,create_time,update_time
)
values(
#url#,#adzoneid#,#pid#,#totalScreen#,#screenNo#,#snapshot#,#adzoneNum#,#aliAdzoneNum#,
#sameScreenNum#,#sameScreenAliNum#,#covered#,#adLink#,#adSnapshot#,#adzoneOwner#,
#adzoneStyle#,#adzoneSize#,#dateTime# , now() , now()
)
<selectKey resultClass="long" keyProperty="id" type="post">
SELECT last_insert_id() as ID from c_adzone_env_info limit 1
</selectKey>
</insert>
and the dataobject has a property id respond to mysql autoincrement primary key
in my unittest ,code is
#Test
public void test(){
AdzoneEnvInfoDO adzoneEnvInfoDO = new AdzoneEnvInfoDO();
adzoneEnvInfoDO.setAdLink("adlink");
adzoneEnvInfoDO.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO.setAdzoneid(99999999L);
adzoneEnvInfoDO.setAdzoneNum(434);
adzoneEnvInfoDO.setAdzoneOwner(11);
adzoneEnvInfoDO.setAdzoneSize("232下232");
adzoneEnvInfoDO.setAdzoneStyle(2);
adzoneEnvInfoDO.setAliAdzoneNum(334);
adzoneEnvInfoDO.setCovered(33);
adzoneEnvInfoDO.setUrl("sds");
adzoneEnvInfoDO.setUrlId(232323L);
adzoneEnvInfoDO.setTotalScreen(32423);
AdzoneEnvInfoDO adzoneEnvInfoDO1 = new AdzoneEnvInfoDO();
adzoneEnvInfoDO1.setAdLink("adlink");
adzoneEnvInfoDO1.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO1.setAdzoneid(99999999L);
adzoneEnvInfoDO1.setAdzoneNum(434);
adzoneEnvInfoDO1.setAdzoneOwner(12);
adzoneEnvInfoDO1.setAdzoneSize("232下232");
adzoneEnvInfoDO1.setAdzoneStyle(22);
adzoneEnvInfoDO1.setAliAdzoneNum(334);
adzoneEnvInfoDO1.setCovered(33);
adzoneEnvInfoDO1.setUrl("sds");
adzoneEnvInfoDO1.setUrlId(232323L);
adzoneEnvInfoDO1.setTotalScreen(32423);
adzoneEnvInfoDAO.insertAdzoneEnvInfoBatch(Arrays.asList(adzoneEnvInfoDO, adzoneEnvInfoDO1));
System.out.println(adzoneEnvInfoDO.getId());
System.out.println(adzoneEnvInfoDO1.getId());
}
and in normal, the two object id should be parimary key in mysql ,but i found it is always null 0
and if i call a not batch method , it will be normal , the single data method is
public Long insertAdzoneEnvInfo(AdzoneEnvInfoDO adzoneEnvInfo) {
return (Long)executeInsert("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfo);
}
I got the same problem as you recently. I just read around the mybatis codes. This one is helpful to insert entities into MySQL. However it is a bit complicated because an ObjectWrapperFactory and a TypeHandler are registered in mybatis configuration file. See
https://github.com/jactive/java/tree/master/test/mybatis-demo
and the entry point
https://github.com/jactive/java/blob/master/test/mybatis-demo/java/com/jactive/mybatis/DaoTest.java

How to use TIME datatype in SQL Server 2008 and C#?

I am developing a web application with C# & SQL Server 2008.
I have a data reader which reads the column PlayTime, defined as TIME datatype.
I want to write a function that returns PlayTime's value.
private static Timespan GetTime(IDataReader rdr, string columnName)`
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return ; // Here I want to return null or zero
}
return (TimeSpan)rdr[index];
}
Am I right using Timespan for time data type?
How to return null if datareader value is nothing?
Best Regards,
RedsDevils
Something like this:
private static TimeSpan? GetTime(IDataReader rdr, string columnName)
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return null;
}
return (TimeSpan)rdr[index];
}
You need to use nullable Timespan
private static Nullable<TimeSpan> GetTime(IDataReader rdr, string columnName)
{
int index = rdr.GetOrdinal(columnName);
if (rdr.IsDBNull(index))
{
return null;
}
return (Nullable<TimeSpan>)rdr[index];
}