java禁⽌执⾏删除sql_关于mybatis动态sql的⼀些陷阱:防⽌
批量update,。。。
我们的解决⽅案是针对3.0.6版本写了⼀个防⽌批量更新的插件。另外参照该插件,还可以写⼀些防⽌delete,select⽆limit 条数限制的插
件。通过这些插件可以避免批量更新、delete操作以及⽆limit限制的select操作(防⽌查询整个表的所有记录,尤其是⼤表)。
⽤法:
(1)在l中定义插件
interceptor=" com.interceptor .BatchUpdateForbiddenPlugin">
(2)在mapper⽂件中修改update的动态sql
在update语句的最后⾯添加了[presentColumn="orderNo"],表⽰解析后的where条件中必须带有orderNo。因为orderNo在业务中可以
标识⼀条记录,因此where条件带有orderNo的话,就可以保证是单条更新,
⽽不是批量更新。
实例:不⼀样的地⽅是添加了[presentColumn="orderNo"]
update
set
status = #{currentStatus}
]]>
and orderNo = #{orderNo, jdbcType=VARCHAR}
and status = #{preStatus, jdbcType=INTEGER}
[presentColumn="orderNo"]
异常:
当解析后的update语句如果是批量更新的sql时,会直接抛异常:
org.ptions.PersistenceException:
### Cause: java.lang.IllegalArgumentException:
该update语句:ders set status = ? WHERE status = ?
是批量更新sql,不允许执⾏。因为它的的where条件中未包含能表⽰主键的字段orderNo,所以会导致批量更新。
at org.ptions.ExceptionFactory.wrapException(ExceptionFactory.java:8)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:124)
at
org.apache.ibatis.submitted.dynsql.stDynamicSelectWithTypeHandler(DynSqlOrderTest.java:66)
flect.NativeMethodAccessorImpl.invoke0(Native Method)
flect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
flect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at flect.Method.invoke(Method.java:597)
at org.del.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.del.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.del.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
lipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
lipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
lipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
lipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
lipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
lipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.IllegalArgumentException:
该update语句:ders set status = ? WHERE status = ?
是批量更新sql,不允许执⾏。因为它的的where条件中未包含能表⽰主键的字段orderNo,所以会导致批量更新。
at
org.apache.ibatis.submitted.dynsql.nullparameter.BatchUpdateForbiddenPlugin.doCheckAndResetSQL(BatchUpdateForbiddenPlugin
at
org.apache.ibatis.submitted.dynsql.nullparameter.BatchUpdateForbiddenPlugin.checkAndResetSQL(BatchUpdateForbiddenPlugin.ja
at
org.apache.ibatis.submitted.dynsql.nullparameter.BatchUpdateForbiddenPlugin.intercept(BatchUpdateForbiddenPlugin.java:65)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:42)
at $Proxy7.update(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:122)
... 25 more
源码:
package com.interceptor ;
import java.util.Properties;
import org.apachemons.lang.StringUtils;
import org.utor.Executor;
import org.apache.ibatis.mapping.BoundSql;
批量更新sql语句import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
/
**
*
* 禁⽌批量更新的插件,只允许更新单条记录
*
*
*
* mapper⽰例:必须在update语句的最后⾯定义[presentColumn="orderNo"],其中orderNo是能标识orders表的主键(逻辑主键或者业务主键)
*
*
* update
* orders
* set
* status = #{currentStatus}
* ]]>
*
*
* and orderNo = #{orderNo, jdbcType=VARCHAR}
*
* and status = #{preStatus, jdbcType=INTEGER}
*
*
* [presentColumn="orderNo"]
*
*
*
* @author yi.chen@qunar
* @version 0.0.1
* @createTime 2012-04-03 18:25
*/
@Intercepts({ @Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class }) })
public class BatchUpdateForbiddenPlugin implements Interceptor {
private final static String presentColumnTag = "presentColumn";// 定义where条件中必须出现的字段/**
*
* 只对update语句进⾏拦截
*
*
* @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin
* .Invocation)
*/
public Object intercept(Invocation invocation) throws Throwable {
// 只拦截update
if (isUpdateMethod(invocation)) {
}
return invocation.proceed();
}
/**
*
* 判断该操作是否是update操作
*
* @param invocation
* @return 是否是update操作
*/
private boolean isUpdateMethod(Invocation invocation) {
if (Args()[0] instanceof MappedStatement) {
MappedStatement mappedStatement = (MappedStatement) invocation
.getArgs()[0];
return SqlCommandType.UPDATE.equals(mappedStatement
.getSqlCommandType());
}
return false;
}
/**
*
* 检查update语句中是否定义了presentColumn,并且删除presentColumn后重新设置update语句*
*
* @param invocation
* invocation实例
* @return MappedStatement 返回删除presentColumn之后的MappedStatement实例
*/
private Object checkAndResetSQL(Invocation invocation) {
MappedStatement mappedStatement = (MappedStatement) invocation
.getArgs()[0];
Object parameter = Args()[1];
BoundSql boundSql = BoundSql(parameter);
String resetSql = Sql());
return getMappedStatement(mappedStatement, boundSql, resetSql);
}
/**
*

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。