Spring Boot MyBatis 使用 Redis 作为二级缓存遇到的问题

拈花ヽ惹草 提交于 2019-11-29 09:39:59

在 Spring Boot MyBatis使用 Redis 作为二级缓存的时候,遇到了一个令人诡异的问题,在 MyBatis 从 Redis 中取出缓存并反序列的时候总是报这个错误

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: hello.entity.User cannot be cast to hello.entity.User
java.lang.ClassCastException: hello.entity.User cannot be cast to hello.entity.User
....

根据异常可以看出是类型不匹配的异常,但是同样的类名,同样的字段,怎么就不匹配了呢?

我首先 MyBatis Redis cache 库是不是有BUG,已经它一直带着个 beta 的字眼,而且已经4年没更新了

        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-beta2</version>
        </dependency>

但是我换成 MyBatis Memcache cache 用 Memcached 做二级缓存也是同样的问题,感觉应该不是 MyBatis 的问题了,

然后我转换思路搜索 Spring Boot ClassCastException 终于找到了问题所在,原来是 spring-boot-devtools 的锅

https://stackoverflow.com/questions/37977166/java-lang-classcastexception-dtoobject-cannot-be-cast-to-dtoobject

When you use DevTools with caching, you need to be aware of this limitation.

When the object is serialized into the cache, the application class loader is C1. Then after you change some code/configuration, devtools automatically restart the context and creates a new classloader (C2). When you hit that cache method, the cache abstraction finds an entry in the cache and it deserializes it from the store. If the cache library doesn't take the context classloader into account, that object will have the wrong classloader attached to it (which explains that weird exception A cannot be cast to A).

TL;DR do not serialize classes with devtools if the cache library doesn't use the context classloader. Or put your cache library in the application classloader:

干掉 spring-boot-devtools 终于搞定了

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!