如果输入值不为null,则更新列,否则忽略并保留数据库中列的现有值

我使用JAVA和MySQL来更新表,输入参数作为JSON输入。 问题是我不知道所有参数在输入中是否存在和不存在,因此可以为某些参数获取空值。 因此,当我运行更新查询时,我的数据库中的所有列都存储了这些空值。 我浏览了网页并查看了堆栈上的各种解决方案。 我发现这是一个经过测试的解决方案,但它对我不起作用。 我是新手,所以我愿意以任何其他方式实现这一目标:

String updateQuery = "UPDATE " + USER_TABLE + " SET " + USER_TABLE_FIRST_NAME + "=IFNULL("+ user.getFirstName() + "," + USER_TABLE_FIRST_NAME + ")," + USER_TABLE_LAST_NAME + "='" + user.getLastName() + "'," + USER_TABLE_ABOUT_ME + "='" + user.getAboutMe() + "'," + USER_TABLE_CITY + "='" + user.getCity() + "'," + USER_TABLE_DOB + "='" + user.getDateOfBirth() + "' WHERE " + USER_TABLE_ID + "='" + user.getUserId() + "'"; 

虽然IFNULL避免设置空值并保留数据库的现有值,但是当它没有空值而是实际值时,它不会反过来工作。 我只测试了一列,即USER_TABLE_FIRST_NAME。 而“user”是我发送输入的JSON对象

  { "firstName":"Rakesh", "city":"Jaipur" } 

它给了我以下错误:

  com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Rakesh' in 'field list' at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:422) at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) at com.mysql.jdbc.Util.getInstance(Util.java:381) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1030) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2536) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1564) at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1485) at com.sports.jogar.services.UserService.updateUser(UserService.java:174) at com.sports.jogar.resources.UserResource.updateUser(UserResource.java:72) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151) at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171) at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195) at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104) at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:387) at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:331) at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:103) at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:269) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) at org.glassfish.jersey.internal.Errors.process(Errors.java:315) at org.glassfish.jersey.internal.Errors.process(Errors.java:297) at org.glassfish.jersey.internal.Errors.process(Errors.java:267) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297) at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:252) at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1025) at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:372) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:345) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:220) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) 

您将用户名直接插入SQL而不转义甚至引用。 我想你只是错过了撇号。

为了防止SQL注入问题,不要从动态数据中插入SQL字符串常量,总是使用PreparedStatement并插入标记。

或者,转义值,但使用标记更安全,并通过允许数据库缓存已编译的SQL语句来提高SQL性能。

 String updateQuery = "UPDATE " + USER_TABLE + " SET " + USER_TABLE_FIRST_NAME + "=IFNULL(? ," + USER_TABLE_FIRST_NAME + ")," + USER_TABLE_LAST_NAME + "=?," + USER_TABLE_ABOUT_ME + "=?," + USER_TABLE_CITY + "=?," + USER_TABLE_DOB + "=?" + " WHERE " + USER_TABLE_ID + "=?"; PreparedStatement stmt = conn.prepareStatement(updateQuery); stmt.setString(1, user.getFirstName()); stmt.setString(2, user.getLastName()); stmt.setString(3, user.getAboutMe()); stmt.setString(4, user.getCity()); stmt.setString(5, user.getDateOfBirth()); stmt.setString(6, user.getUserId()); 

注意:扩展答案以涵盖空检查问题。

当你使用简单的字符串注入时, "A='" + name + "'"对于非空值变为A='Joe' ,但A='null'空值变为A='null' ,这绝对不是你想要的。

通过使用参数标记,值? 可以为null ,这意味着IFNULL(?, Name)将给出所需的确切行为,即使用?的值? 什么时候它不是null,而NAME的值何时? 一片空白。

IFNULL不会对您提供的变量进行空值检查。 请注意,您是字符串连接查询而不是在字符串变量/对象上调用IFNULL

当您向IFNULL提供一个字符串时,它表示提供的STRING是SELECT的列名。 因此,它正在寻找一个名为你提供的字符串的列 – 在这种情况下是’Rakesh’。 因此,例外。

IFNULL文件在这里 。

您不能期望在业务逻辑层(您将SQL查询连接并准备为字符串)中调用IFNULL函数评估。 执行查询时, IFNULL函数在数据库中执行。

在您的情况下,请考虑将IF-NULL逻辑移动到业务逻辑中并移出查询。 评估各个组件属性并相应地组合SQL字符串。

 String updateQuery = "UPDATE " + USER_TABLE + " SET " ; if(null != user.getFirstName()){ updateQuery += " USER_TABLE_FIRST_NAME = '"+ user.getFirstName() + "'," ; } if(null != user.getLastName() ){ updateQuery += " USER_TABLE_LAST_NAME = '" + user.getLastName() + "'," ; } if(null != user.getAboutMe()){ updateQuery += " USER_TABLE_ABOUT_ME = '" + user.getAboutMe() + "'," ; } if(null != user.getCity()){ updateQuery += " USER_TABLE_CITY = '" + user.getCity() + "'," ; } if(null != user.getDateOfBirth() ){ updateQuery += " USER_TABLE_DOB ='" + user.getDateOfBirth() + "'"; } updateQuery += " WHERE " + USER_TABLE_ID + "='" + user.getUserId() + "'";