使用spring typeConverter造成的数据错乱(多线程环境)

在线上环境碰到一个问题,经由数据库查询并进行数据处理转换之后的数据在界面显示时随机出现数据错位。由于该问题不可重现(重新清除缓存并操作一次问题即解决),并且由于缓存的存在(缓存了错误的数据),导致此问题严重并且很难查找。

业务场景描述如下:

数据库查询数据->一次处理->类型转换->二次处理->界面显示

由于每个步骤都涉及到很多代码,因此在处理时通过在不同的点设定潜在出错点,并通过判断数据变化进行log。尝试在本地环境重现此问题。经过一次偶然的场景,发现一个本该是8位数字的字符串在转换过程中报错,由此找出了真正的问题。

//报错的业务代码 假定数据为 20141111
str = s.substring(0,4) + "/" + s.substring(4,6) + "/" + s.substring(6,8)
//报错异常 indexOutofBound,即字符串不足8位...

经过断点,加层层回溯,终于发现数据在经过一次类型转换之后被修改了。转换代码如下所示:

private static TypeConverter typeConverter = new SimpleTypeConverter();
        public <T> T convertValue(Object value) {
            return (T)typeConverter.convertIfNecessary(value, Integer.class);
        }

初看起来,这个方法调用并没有什么问题,即将数据值转换为整数类型.重点的问题在于在这个方法(由spring提供)的内部实现并不是线程安全的。附API说明:

public interface TypeConverter
Interface that defines type conversion methods. Typically (but not necessarily) implemented in conjunction with the PropertyEditorRegistry interface.
Note: Since TypeConverter implementations are typically based on PropertyEditors which aren't thread-safe, TypeConverters themselves are not to be considered as thread-safe either.

typeConverter内部会使用propertyEditor来进行类型转换。这种转换在spring3.0之后已不再推荐使用。见 使用线程安全的spring类型转换器ConversionService VS TypeConverter

解决方法也简单,将其更换为conversionService即可(为什么不自己写?不想重复发明轮子)。spring3.0之后,为conversionService内置了常见类型之间的转换,相当于整个类型转换子框架被完全重写了,重写的转换是状态无关的,即线程安全。至于原来的typeConverter及propertyEditor,忘掉它吧,遗留的东西。

附:jdk自带的simpleDateFormat也存在相同的问题,用这个类需要小心处理线程问题。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201502100002.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

电子邮件地址不会被公开。 必填项已用*标注