多线程下谨慎对待基类(抽象类)中的成员变量
有这么个需求:
做开发一套在oracle和mysql中做业务数据复制,其中具体的业务还没确定,目前需要开发一套
框架,需要在业务确定后,只需做少了开发即可实现,我使用了ibatis+spring
,以后扩展时,只需增加ibatis的配置文件即可,而配置文件中的每个ID都是由以下规则生成:
业务识别码+新增/删除等统一的后缀。
如下结构:
1、DAO部分
public abstract class Base{ private String name; private String code; public String getName(){return name;} public String getCode(){return code;} public void setName(String name){this.name=name;} public void setCode(String code){this.code = code;} public String getInsertSqlName() { return this.code+"insert"; } public abstract insert(...); public abstract query(...);}public class ADao extends Base{ public map insert(...) { String sqlName = this.getInsertSqlName(); //用ibatis操作数据库 } public map query(...) { xxxxx }}public class BDao extends Base{ public map insert(...) { String sqlName = this.getInsertSqlName(); //用ibatis操作数据库 } public map query(...) { xxxxx }}public class CDao extends Base{ public map insert(...) { String sqlName = this.getInsertSqlName(); //用ibatis操作数据库 } public map query(...) { xxxxx }}2、Service部分
根据数据库配置动态创—AO,大概如下:
String name=从数据库读取 String code = 从数据库读取 Base dao = ServFactory.getDao(name,code); dao.insert(xxx); dao.query(xxx);
3、为了重用DAO,如上面Service部分,使用ServFactory创—AO,
原理就是将创建的DAO放到map中,在getDao前先检查map中有没有DAO,没有则创建。
单线程运行下没问题。
但是在并发处理时,发现查询出来的数据错位了,明明查A的数据,结果返回了B的数据。
使用debug跟踪发现,DAO中的name和code会在执行insert后的query被突然改变,原来在并发下有其他请求的code被其他获取相同DAO的线程改变,导致最后执行的SQL不是预期的SQL。
解决方法有2:
1、不缓存DAO,每次创建个新DAO
2、不适用Base的成员变量,直接将name和code通过参数传入到insert和query中
我选择了后者。