更新时间:2021年4月10日 16点18分
- 解决缓存击穿问题,通过并发类的hashcode和主键拼凑成的静态池对象
更新时间:2021年2月22日 11点44分
- 一对多关系下的id通过注解进行标识。
- id默认为long型,即使是业务层是int,但只需要自己处理即可。
更新时间:2021年2月19日 09点25分
- 一对多关系下的id自增长由自己控制,并提供便捷的方法。
- 一对多关系下的错误异常,选择将整个list清空的处理方案。
更新时间:2021年1月29日 13点59分
- 缓存一致性,解决数据回滚导致的缓存不一致。
更新时间:2021年1月25日 11点31分
- 增加了dao层的父类处理,用来简化dao层的注解设置。
- 针对性的处理异常
- 解决jar包下无法扫描到class文件
更新时间:2021年1月19日 20点59分
- 简便的缓存框架,支持集合操作中单个对象的增删改。
class DAO{
//得到单个对象
public DBObject get(Object primaryKey) {
//查找缓存
DBObject cache = getDBCache(primaryKey);
if (cache == null) {
//查找数据库
//只有这一行应该dao层自己处理
cache = getDBObject(primaryKey);
if (cache == null) {
//插入空缓存对象,防止缓存穿透
insertCache(NULL_DBOBJECT);
return null;
} else {
//插入缓存
insertCache(cache);
}
} else if (cache == NULL_DBOBJECT) {
return null;
}
return cache;
}
}
class DAO{
//得到单个对象
public DBObject getDBObject(Object primaryKey, Object secondaryKey) {
//一般会进行初始化,只调一次,不会放在这里,后续取都从缓存找
getDBListCacheObject(primaryKey);
return getDBCacheObject(primaryKey, secondaryKey);
}
//得到list管理的对象
public DBListCacheObject getDBListCacheObject(Object primaryKey) {
//查找list缓存对象
DBListCacheObject listCache = getDBListCache(primaryKey);
if (listCache == null) {
//查找数据库得到list集合
List<DBObject> dBObjectList = getDBObjectList(primaryKey);
listCache = new DBListCacheObject();
listCache.setPrimaryKey(primaryKey);
if (dBObjectList != null && dBObjectList.size() > 0) {
for (DBObject dbObject : dBObjectList) {
listCache.addDBObject(dbObject.getSecondaryKey());
//插入缓存
insertCache(dbObject);
}
}
// else 也可以做插入空集合缓存,具体结合自己业务
// listcache 插入缓存
insertCache(listCache);
}
return listCache;
}
}
对list中单个元素的修改是通过直接删除整个list,来保证缓存一致性。
@Cache(location = "fastcache1.domain.Item", primaryKey = "uid", secondaryKey = "id")
public class ItemDao implements FastCacheBaseCacheObject {
public static ItemDao dao = CglibProxyFactory.getProxy(ItemDao.class);
public ItemDao() {
}
@CacheInitList
@CacheOperation(isListOperation = true, operation = CacheOperationType.GET)
public List<Item> getList(int uid) {
//实现数据库操作
return null;
}
@CacheOperation(operation = CacheOperationType.GET)
public Item getOne(int uid, int id) {
//实现数据库操作
return null;
}
@CacheOperation(operation = CacheOperationType.UPDATE)
public void update(Item item) {
//实现数据库操作
}
@CacheOperation(operation = CacheOperationType.ADD)
public void add(Item item) {
//实现数据库操作
}
@CacheOperation(operation = CacheOperationType.DELETE)
public void delete(Item item) {
//实现数据库操作
}
}
测试方法类 是个窗口化工具,很方便测试
public class PetDao extends CacheBaseListDao<Pet, Integer, Integer> {
public static PetDao dao = CglibProxyFactory.getProxy(PetDao.class);
public PetDao() {
}
@Override
protected List<Pet> getListByPKeys(Integer uid) {
//实现数据库操作
return null;
}
@Override
protected Pet getOneByPSKeys(Integer uid, Integer id) {
//实现数据库操作
return null;
}
@Override
protected void updateOne(Pet pet) {
//实现数据库操作
}
@Override
protected void saveOne(Pet pet) {
//实现数据库操作
}
@Override
protected void deleteOne(Pet pet) {
//实现数据库操作
}
}
测试方法 是个窗口化工具,很方便测试
- 在获取数据时:
protected List<Pet> getListByPKeys(Integer uid) {
//todo 用于模拟从数据库是否取得数据
if (uid % 2 == 0) {
List<Pet> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(new Pet(uid, i));
}
return list;
}
return null;
}
- 模拟缓存一致性,设定只要更新就会发生数据库回滚
protected void updateOne(Pet pet) {
throw new NullPointerException();
}
-
test下包含两个版本的窗口化测试工具,也有业务层的简单例子。
-
先对dao层进行初始化扫描(建议,同时也是进行类的检查,也可以先测试加载全部,避免运行中出现错误),CglibProxyFactory.init(String packageName)。
-
初始化dao层中会进行检查,错误会有详细提醒。
-
建议使用2.0版本,只需要注意主副键的名称和po类一一对应。
-
Cache中的主副键要对应po类的属性名字。
-
2.0版本下dao层实现的方法和实际在业务层调取的方法并不一样,对应如下:
-
根路径不支持中文
-
dao层取出的list不能直接对其操作,因为取到的就是缓存的list,要极其小心,最好只做查找,其余操作请自己把握
-
Id注解,在一对多的关系下,必须设置,并且只能在long型上使用。
-
会自动检测是否有规范性,避免运行中出现错误。
-
取出的对象集合一定不为空,所以可以跳过判空,直接进行操作
一对一如下
dao层方法 业务层调取方法 getOneByPKey get updateOne update saveOne save deleteOne delete 一对多如下
dao层方法 业务层调取方法 getListByPKeys getList getOneByPSKeys getOne updateOne update saveOne save deleteOne delete
我现在实际项目也是spring架构,orm也是spring的架构。我把遇到的问题,罗列下:
问题1:因为FastCache没有被spring代理,没办法在FastCache任意一层取得被自动注入的对象。
解决:
@Service
public class GameService extends BaseService {
@Autowired
private SpringAutowiredClass springAutowiredClass;
private static GameService gameService;
@PostConstruct
public void init() {
gameService = this;
}
//获得被自动注入的对象,如果获取的对象多的话,建议设计类进行管理
public static SpringAutowiredClass getSpringAutowiredClass() {
return gameService.springAutowiredClass;
}
}
问题2:如何预加载class,并在jar包里对class文件进行搜索。
解决:
使用JarFile,貌似只能一个一个寻找,只有启动代价高,可以忽略;
问题3:缓存一致性,当数据回滚但是数据已被缓存的问题
解决:
先执行数据库操作,再执行缓存操作:具体如下
增:取消增加
删:取消删除
改:取消更改,但是此时缓存对象基本是被修改后的,所以需要删除,再重新从数据库读取
查:跳出缓存操作