【原创】JSR303与ApacheValidate性能测试

原创
2016/08/15 10:57
阅读数 3.6K

软件开发中涉及到这样一个问题,那就是关于后台系统的数据验证,任何系统的绕不过去的。

下面针对于各种方式的数据验证进行一个测试。

 

if else

结论:这种效率是无疑是最高效的验证代码,优势是效率高,缺点是可能返回状态忘记设置,可能if else判断太多,看代码很烦。

code:


		long currentTimeMillis = System.currentTimeMillis();
		try
		{
			Map<String, Object> resultMap = new HashMap<String, Object>();
			resultMap.put("status", "y");
			resultMap.put("msg", "操作成功!");

			for (int i = 0; i < 300; i++)
			{
				PlatformDevelopers dev = new PlatformDevelopers();
				if (null == dev.getAddress() || dev.getAddress().length() == 0)
				{
					resultMap.put("status", "n");
					resultMap.put("msg", "Address 不能为空!");
					//这里按照正常流程走的话,应该是 return ;
					continue;
				}
			}
		} catch (Exception e)
		{
			e.printStackTrace();
		} finally
		{
			long l = System.currentTimeMillis();
			System.out.println(l - currentTimeMillis);
		}
	

程序执行300次,测试得到的平均时间为:32ms左右。

if else 太多的情况,如:


		StringBuilder builder = new StringBuilder(160);
		if (getDicMap().containsKey("id")) //如果包含id,则进行处理
		{
			builder.append(Str.tl(" and id in (:0) ", getMoreParameter("id")));
		} else if (this.getId() != null && !"".equals(this.getId()))
		{
			builder.append(" and id = " + this.getId());
		}
		if (getDicMap().containsKey("text")) //如果包含text,则进行处理
		{
			builder.append(Str.tl(" and text in (:0) ", getMoreParameter("text", true)));
		} else if (this.getText() != null && !"".equals(this.getText()))
		{
			builder.append(" and text like '%" + Str.filterSql(this.getText()) + "%'");
		}
		if (getDicMap().containsKey("realValue")) //如果包含realValue,则进行处理
		{
			builder.append(Str.tl(" and real_value in (:0) ", getMoreParameter("realValue", true)));
		} else if (this.getRealValue() != null && !"".equals(this.getRealValue()))
		{
			builder.append(" and real_value like '%" + Str.filterSql(this.getRealValue()) + "%'");
		}
		if (getDicMap().containsKey("fieldName")) //如果包含fieldName,则进行处理
		{
			builder.append(Str.tl(" and field_name in (:0) ", getMoreParameter("fieldName", true)));
		} else if (this.getFieldName() != null && !"".equals(this.getFieldName()))
		{
			builder.append(" and field_name like '%" + Str.filterSql(this.getFieldName()) + "%'");
		}
		if (getDicMap().containsKey("remark")) //如果包含remark,则进行处理
		{
			builder.append(Str.tl(" and remark in (:0) ", getMoreParameter("remark", true)));
		} else if (this.getRemark() != null && !"".equals(this.getRemark()))
		{
			builder.append(" and remark like '%" + Str.filterSql(this.getRemark()) + "%'");
		}
		if (getDicMap().containsKey("pid")) //如果包含pid,则进行处理
		{
			builder.append(Str.tl(" and pid in (:0) ", getMoreParameter("pid")));
		} else if (this.getPid() != null && !"".equals(this.getPid()))
		{
			builder.append(" and pid = " + this.getPid());
		}
		if (getDicMap().containsKey("pname")) //如果包含pname,则进行处理
		{
			builder.append(Str.tl(" and pname in (:0) ", getMoreParameter("pname", true)));
		} else if (this.getPname() != null && !"".equals(this.getPname()))
		{
			builder.append(" and pname like '%" + Str.filterSql(this.getPname()) + "%'");
		}
		if (getDicMap().containsKey("sort")) //如果包含sort,则进行处理
		{
			builder.append(Str.tl(" and sort in (:0) ", getMoreParameter("sort")));
		} else if (this.getSort() != null && !"".equals(this.getSort()))
		{
			builder.append(" and sort = " + this.getSort());
		}
	

 

Apache Validate

结论:这种判断效率比if else略低,优势是可以阻断程序继续往下执行,缺点是会抛出异常栈。

code:


		long currentTimeMillis = System.currentTimeMillis();
		try
		{
			for (int i = 0; i < 300; i++)
			{
				PlatformDevelopers dev = new PlatformDevelopers();
				Validate.notBlank(dev.getAddress(), "错误的参数!");
			}
		} catch (Exception e)
		{
			//e.printStackTrace();
		} finally
		{
			long l = System.currentTimeMillis();
			System.out.println(l - currentTimeMillis);
		}
	

程序执行300次,测试得到的平均时间为:47ms左右。

如:

java.lang.NullPointerException: Address 不能为空!
    at org.apache.commons.lang3.Validate.notBlank(Validate.java:448)
    at test.spring.boot.rest.TValidVsJSR.m2(TValidVsJSR.java:59)
    at test.spring.boot.rest.TValidVsJSR.main(TValidVsJSR.java:29)
 

JSR303(Hibernate Validator 5.2.4.Final 提供支持)

结论:这种判断最简单,一个注解搞定,只需处理错误即可。优点是方便,功能强大,可读性,可配置强大,有社区支持,缺点是效率最低,比上面的验证结果慢了10倍有余。

long currentTimeMillis = System.currentTimeMillis();
		for (int i = 0; i < 300; i++)
		{
			PlatformDevelopers dev = new PlatformDevelopers();
			//jsr
			Map<String, String> validate = ValidateUtil.validate(dev);
			if (!validate.isEmpty())
			{
				//				System.out.println(validate);
			}

		}
		long l = System.currentTimeMillis();
		System.out.println(l - currentTimeMillis);

PlatformDevelopers.java

public class PlatformDevelopers 
{
	//id	
	private java.lang.Integer id;

	@NotBlank
	@Email
	//开发者email	
	private java.lang.String email;

	@NotBlank
	@Size(min = 6, max = 32)
	//登陆密码
	private java.lang.String password;
}

ValidateUtil.java

/**
 * 
 * 项目名称:ej 	<br><br>
 * 
 * 类名称:ValidateUtil 		<br><br>
 * 
 * 创建人:LinApex@163.com 	<br><br>
 * 
 * 创建时间:2014-2-26 下午1:10:03 	<br><br>
 * 
 * 版本:1.0					<br><br>
 * 
 * 功能描述:验证工具类,后台校验对象
 */
public class ValidateUtil
{
	static Validator validator;

	static
	{
		//消息国际化对象
		//		ReloadableResourceBundleMessageSource localMessageSource = new ReloadableResourceBundleMessageSource();
		//		localMessageSource.setBasename("classpath:i18n/messages");
		//		localMessageSource.setDefaultEncoding("UTF-8");
		//		localMessageSource.setCacheSeconds(60);

		LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
		localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
		//		localValidatorFactoryBean.setValidationMessageSource(localMessageSource);	//消息国际化对象
		localValidatorFactoryBean.afterPropertiesSet();
		validator = localValidatorFactoryBean.getValidator();
	}

	public static <T> Map<String, String> validate(T t)
	{
		Map<String, String> resultMap = new HashMap<String, String>(0);
		Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
		if (constraintViolations.size() > 0)
		{
			for (ConstraintViolation<T> constraintViolation : constraintViolations)
			{
				resultMap.put(constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());
			}
		}
		return resultMap;
	}

}

程序执行300次,测试得到的平均时间为:630ms左右。

 

有没有更优的解决方式?

你们在开发里一般使用什么方式?

有没有更有经验的朋友来分享一下你的看法?

 

 

 

 

 

 

 

展开阅读全文
打赏
1
12 收藏
分享
加载中
linapex博主

引用来自“cpanmac”的评论

代码就不能写到代码块?还还是开源中国不支持?
代码块是哪种形式?
2016/08/18 09:50
回复
举报
linapex博主

引用来自“jeffsui”的评论

我有两个疑问:
1. 前面使用的两个方法,类都是new出来的,也就是没有使用反射?那么和validation这类用反射实现的对比,是否有点牵强?按照我的理解,反射本身就牺牲了一部分performance。
2.如果都是main方法,单线程顺序执行,这样的对比通常没有太多说服力,你可以尝试在多线程下不同方式的执行时间。
1.没错,对象都是New出来的,validation 反射是用于注解做验证, 这部分是很大的性能开销,但它使用方式简单,可作为对比方式的一种,只是这种方式采用了反射而已。
2.main方法 单线程就已经够了,多线程跑去对比,除非validation对于class类的注解做了缓存,才能提高性能优化。
2016/08/18 09:50
回复
举报
代码就不能写到代码块?还还是开源中国不支持?
2016/08/18 07:45
回复
举报
该评论暂时无法显示,详情咨询 QQ 群:912889742
更多评论
打赏
4 评论
12 收藏
1
分享
返回顶部
顶部