最近一直在使用springboot做后台系统,之前数据操作框架选型hibernate太重,mybaits又是半自动化的,怎么都感觉用着不方便,所以先用jdbctemplate快速灵活的实现业务功能,但是后来发现还是需要封装一套数据操作的基础框架,使开发更加高效,免除大量的重复劳动,jdbctemplate灵活快速并且封装好了一些基础功能,我们要做的就是对数据进行内部映射,对外提供方法接口,使得开发更加快捷高效,话不多说,下面就来具体介绍一下。
项目地址:https://gitee.com/grassprogramming/FastORM_Java
maven引用:
com.gitee.grassprogramming
fastorm
0.0.2
如果想了解发布自己的组件到maven中央仓库可以参考:https://blog.csdn.net/u013407099/article/details/85851113
orm框架基于jdbctemplate做基础查询,transactiontmplate事物处理,内部采用实体类扫描做数据映射缓存,对外提供以下一些功能
1:实体类型的数据库注解
TableName指定实体类对应的表明,未指定默认类名,Key指定表唯一键,Ignore指定类中不需要映射的字段
2:基于实体类的基础的增删改查
//增
Frame_Config frame_config = new Frame_Config();
frame_config.setConfigGuid(UUID.randomUUID().toString());
frame_config.setConfigName("test1111111");
frame_config.setConfigValue("2222222");
frame_config.setConfiIntro("hahahahhah");
frame_config.setAddDate(new Date());
dbUtil.insert(frame_config);
//删
dbUtil.delete(frame_config);
//改
frame_config.ConfigValue="222";
dbUtil.update(frame_config);
//查
Frame_Config frame_config = dbUtil.findOne("8c0648f4-c3eb-4447-a0ff-8a63c41ece3b", Frame_Config.class);
3:分页查找与多表联查
//普通列表查找
list = dbUtil.findPage("*","",null,"AddDate desc",1,1,Frame_Config.class);
list = dbUtil.findList("ConfigName","ConfigGuid=?",new Object[]{"8c0648f4-c3eb-4447-a0ff-8a63c41ece3b"},"AddDate desc",Frame_Config.class);
//分页查找
list = dbUtil.findPage("*","",null,"AddDate desc",1,1,Frame_Config.class);
//多表联查
List
4:批量插入
List batchlist = new ArrayList<>();
for (int i=0;i<10;i++){
Frame_Config f = new Frame_Config();
f.setConfigGuid(UUID.randomUUID().toString());
f.setConfigName("test1111111");
f.setConfigValue("2222222");
f.setConfiIntro("hahahahhah");
f.setAddDate(new Date());
batchlist.add(f);
}
dbUtil.insertBatch(batchlist);
5:基于标识主键或其他唯一键的单条记录对象查找
public T findOne(String keyName,String keyGuid, Class tClass)
6:直接执行sql语句
dbUtil.executeSQL("update frame_userextend set Email=? where userguid=?",new Object[]{"aaaaaaaa","d33ea591-93d4-4f74-bc9e-392db05995c0"});
7:获取执行结果操作(executescar)
String loginid = dbUtil.executeSQLToString("select loginid from frame_user where userguid=?",new Object[]{"e7c8f780-ae53-4cd0-b0a7-0a857132f7fe"});
8:每个数据操作方法都提供指定数据源的操作重载
//测试单个操作指定的库
DriverManagerDataSource source =
dbUtil.getDataSource("jdbc:mysql://127.0.0.1:3306/orm?
useUnicode=true&characterEncoding=UTF-
8&allowMultiQueries=true","root","11111","com.mysql.jdbc.Driver");
Frame_User frame_user = dbUtil.findOne("3333", Frame_User.class,source);
9.提供委托形式的事务操作(事物中的操作需要使用同一数据源)
DriverManagerDataSource transitionDataSource = dbUtil.getTransitionDataSource();
dbUtil.executeTransition(transitionDataSource, new TransitionAction() {
@Override
public void doTransitionOption(DriverManagerDataSource dataSource){
try {
Frame_Config frame_config = new Frame_Config();
frame_config.setConfigGuid(UUID.randomUUID().toString());
frame_config.setConfigName("test1111111");
frame_config.setConfigValue("2222222");
frame_config.setConfiIntro("hahahahhah");
frame_config.setAddDate(new Date());
dbUtil.insert(frame_config,dataSource);
throw new RuntimeException();
}
catch (Exception e){
e.printStackTrace();
throw new RuntimeException();
}
}
});
10:提供全局的SQL语句跟踪
//测试SQL日志追踪
dbUtil.OpenTrace();;
frame_config = dbUtil.findOne("8c0648f4-c3eb-4447-a0ff-8a63c41ece3b",
Frame_Config.class);
dbUtil.CloseTrace();
功能大概就是这么多,更多详细请查看项目ReadMe,接下来就说以下开发中一些功能或者问题的解决
1.如何实现SQL监控
可能如果简单来做就是在底层的jdbcteplate的每个执行方法中加入手动日志,但是这样不利于后续扩展,所以就采用了cglib中的动态代理,我有一个Command执行类,我就不使用new的方式,而是使用代理方式进行初始化,就可以对类的执行方法进行拦截
public class CommandFactory {
public static Command getCommand(){
CommandProxy commandProxy = new CommandProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Command.class);
enhancer.setCallback(commandProxy);
Command command = (Command)enhancer.create();
command.setJdbcTemplate(Config.GetInstance().getJdbcTemplate());
return command;
}
}
public class CommandProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//追踪指定的方法
if(method.isAnnotationPresent(TraceMethod.class)){
Command command = (Command)o;
//开启sql跟踪,打印sql语句及参数
if(command.isTraceSQL()){
LogUtil.writeLog("=========================================================");
LogUtil.writeLog("SQL语句:"+command.getSQLText());
}
}
return methodProxy.invokeSuper(o, objects);
}
}
2.如何进行反射效率优化
反射其实效率已经很快了,我们这里做的就是对一些重复操作进行优化,最重要的就是实体类字段和类名的缓存,我们首先要做的就是在项目启动时进行扫描,获取所有继承我们定义的基类BaseEntity的类,进行类数据缓存,扫描类我这里就不贴了,在项目util目录下的ScanUtil,就看下初始化的方法,后续所有的Mapper操作就都从缓存中取就可以了
public static void initClassCache(Class runClass) throws Exception{
if(null==cacheMap){
cacheMap = new HashMap();
}else{
cacheMap.clear();
}
List classfilter = new ArrayList();
classfilter.add(BaseEntity.class);
classfilter.add(BaseExtendEntity.class);
List> clsList = ScanUtil.getAllClassByPackageName(runClass.getPackage(),classfilter);
//进行所有class类的缓存
for(Class item:clsList){
ClassCache classCache = new ClassCache();
String tableName = InitTableName(item);
Field keyField = initKeyField(item);
String keyFieldName = "";
if(null!=keyField){
keyFieldName = keyField.getName();
}
List fs = Arrays.asList(item.getDeclaredFields());
//去除标记Ignore的字段不映射
fs = fs.stream().filter(((Field f)-> !f.isAnnotationPresent(Ignore.class))).collect(Collectors.toList());
classCache.setTableName(tableName);
classCache.setKeyField(keyField);
classCache.setKeyFieldName(keyFieldName);
classCache.setFields(fs);
cacheMap.put(item,classCache);
}
System.out.println("初始化ORM缓存成功,共缓存"+cacheMap.size()+"个class");
}
说明:本项目适用于springboot,mysql数据库,未经过严格测试,学习型项目,还希望大家多提意见,共同进步,如果可以,请给个Starspi