今天在看分布式事務的時候,突然收到app不能簽到的消息,趕緊解決。
具體解決方法:
1、把執行錯誤的處理方法提取出來,作為測試方法
2、這個方法里面有兩個插入語句,一條查詢語句,一個更新語句,涉及到三張表。
3、報錯信息為
"nested exception is org.apache.ibatis.exceptions.PersistenceException: \n### Error committing transaction. Cause: java.lang.NullPointerException: Can't serialize null\n### Cause: java.lang.NullPointerException: Can't serialize null
4、今天只是為了做集群,將Mybatis的緩存由默認的內存緩存改為了Memcached,突然就報這個錯。
思路
- 插入語句一般不會緩存,只有Select語句才會緩存。不能持久化,我只用了一個選擇語句,這個語句是執行正常的啊,查看日志,發現問題。
Flushing keys: [_mybatis_22a025828e62efbe0adda93d10f748e15fe8cecd]
Flushing group: _mybatis_2610d3ffc622c90f08b859a4e787189c9230d66e
- 每次插入或更新語句的時候都會Flush cache,導致剛查詢的緩存結果為清空,因為加了事務注解,所以等方法執行完畢的時候,緩存為null,然后報錯。
教訓
在事務處理的時候,如果是使用Memcache做緩存,盡量不要把Select語句和Insert語句放到一起。
如果是使用Redis作為Mybatis的緩存,則未發現問題。
額外
Mybatis二級緩存的擴展包中文件數量較少,并且官方的Mybatis-Redis直接使用,當前版本也會報錯,無法集成。
解決方案:
-
將所有Mybatis-redis擴展包拷貝到當前項目
二級緩存包中文件 修改Rediscache的構建方法
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();
pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(),
redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getPassword(),
redisConfig.getDatabase(), redisConfig.getClientName(),false,null,null,null);
}
- 可以使用Redis作為Mybatis的二級緩存,在Mybatis全局配置與Mapper文件中配置好即可。
集成Mybatis-Memecache也類似,可以拷貝二級緩存包內容,進行擴展