[开源]Java真正智慧的ORM框架,兼具Hibernate、MyBatis双重优点

一飞开源,介绍创意、新奇、有趣、实用的免费开源应用、系统、软件、硬件及技术,一个探索、发现、分享、使用与互动交流的开源技术社区平台。致力于打造活力开源社区,共建开源新生态!

一、开源项目简介

sqltoy-orm是什么

sqltoy-orm是比hibernate+myBatis(plus)更加贴合项目的orm框架(依赖spring),具有jpa式的对象CRUD的同时具有比myBatis(plus)更直观简洁性能强大的查询功能,越复杂优势越凸显。 支持以下数据库:

二、开源协议

使用Apache-2.0开源协议

三、界面展示

技术架构

架构原则:sqltoy-orm是协助开发者的工具之一,目标是要解决99.5%的问题而不是覆盖100%的问题(目前从复杂的ERP项目、数据分析报表项目的实践角度看基本100%覆盖)。

四、功能概述

Java真正智慧的ORM框架!支持mysql、oracle、postgresql、sqlserver、db2、dm、mongodb、elasticsearch、tidb、kingbase、oceanbase、guassdb、greenplum、StarRocks、impala(kudu)、clickhouse、sqlite、h2、polardb。

sqltoy-orm是基于java语言开发的,兼有hibernate面向对象操作和myBatis灵活查询的优点,同时更贴切项目、更贴切开发者的一个关系型数据库ORM框架,支持oracle、mysql、postgresql、sqlserver、db2、sqlite、sybase iq、elasticsearch、mongodb等数据库。

与sqltoy-orm配套的有一个quickvo工具,协助通过数据库表产生POJO对象类。Quickvo工具摈弃了hibernate-tools工具的不足(如模块化配置、主键策略配置、级联加载、修改、删除的逻辑),可以让开发者通过配置文件进行灵活控制POJO的生成,而不用担心自己对POJO类的修改被覆盖。

sqltoy最大的特点在于贴切项目、了解开发者,试图实实在在的帮助开发者简化数据库交互过程中的大量看似很重要其实是机械的重复工作,同时sqltoy将大量第一手项目最佳实践模式抽象成工具带给开发者。

sqltoy究竟能给你带来什么?

五、技术选型

1、基于Java语言开发

2. 快速特点说明

2.1 对象操作跟jpa类似并有针对性加强(包括级联)

   StaffInfoVO staffInfo = new StaffInfoVO(); 
   //保存
   sqlToyLazyDao.save(staffInfo);
   //删除
   sqlToyLazyDao.delete(new StaffInfoVO("S2007"));

   //public Long update(Serializable entity, String... forceUpdateProps);
   // 这里对photo 属性进行强制修改,其他为null自动会跳过
   sqlToyLazyDao.update(staffInfo, "photo");

   //深度修改,不管是否null全部字段修改
   sqlToyLazyDao.updateDeeply(staffInfo);

   List staffList = new ArrayList();
   StaffInfoVO staffInfo = new StaffInfoVO();
   StaffInfoVO staffInfo1 = new StaffInfoVO();
   staffList.add(staffInfo);
   staffList.add(staffInfo1);
   //批量保存或修改
   sqlToyLazyDao.saveOrUpdateAll(staffList);
   //批量保存
   sqlToyLazyDao.saveAll(staffList);
   ...............
   sqlToyLazyDao.loadByIds(StaffInfoVO.class,"S2007")
   //唯一性验证
   sqlToyLazyDao.isUnique(staffInfo, "staffCode");

2.2 支持代码中对象查询

/**
 * @todo 通过对象传参数,简化paramName[],paramValue[] 模式传参
 * @param 
 * @param sqlOrNamedSql 可以是具体sql也可以是对应xml中的sqlId
 * @param entity        通过对象传参数,并按对象类型返回结果
 */
 public  List findBySql(final String sqlOrNamedSql, final T entity);
public Page findStaff(Page pageModel, StaffInfoVO staffInfoVO) {
     // sql可以直接在代码中编写,复杂sql建议在xml中定义
     // 单表entity查询场景下sql字段可以写成java类的属性名称
     return findPageEntity(pageModel, StaffInfoVO.class, EntityQuery.create()
	.where("#[staffName like :staffName]#[and createTime>=:beginDate]#[and createTime<=:endDate]")
	.values(staffInfoVO));
}
//演示代码中非直接sql模式设置条件模式进行记录修改
public Long updateByQuery() {
     return sqlToyLazyDao.updateByQuery(StaffInfoVO.class,
		EntityUpdate.create().set("createBy", "S0001")
                     .where("staffName like ?").values("张"));
}

//代码中非直接sql模式设置条件模式进行记录删除
sqlToyLazyDao.deleteByQuery(StaffInfoVO.class, EntityQuery.create().where("status=?").values(0));

2.3 极致朴素的sql编写方式

//1、 条件值处理跟具体sql分离
//2、 将条件值前置通过filters 定义的通用方法加工规整(大多数是不需要额外处理的)


   
   

=:beginAndEndDate[0]]
		  #[and t.TRANS_DATE<:beginAndEndDate[1]]    
	]]>

2.4 天然防止sql注入,执行过程:

select 	*
from sqltoy_device_order_info t 
where #[t.ORGAN_ID in (:authedOrganIds)]
      #[and t.TRANS_DATE>=:beginDate]
      #[and t.TRANS_DATE<:endDate] 
sqlToyLazyDao.findBySql(sql, MapKit.keys("authedOrganIds","beginDate", "endDate").values(authedOrganIdAry,beginDate,null),
                          DeviceOrderInfoVO.class);
select 	*
from sqltoy_device_order_info t 
where t.ORDER_ID=?
      and t.ORGAN_ID in (?,?,?)
      and t.TRANS_DATE>=?	

2.5 最为极致的分页

2.5.1 分页特点说明

2.5.2 分页sql示例



	
	
	
	
	
		
	
	
	
	

2.5.3 分页java代码调用

/**
 *  基于对象传参数模式
 */
public void findPageByEntity() {
	StaffInfoVO staffVO = new StaffInfoVO();
	// 作为查询条件传参数
	staffVO.setStaffName("陈");
	// 使用了分页优化器
	// 第一次调用:执行count 和 取记录两次查询
        // 第二次调用:在特定时效范围内count将从缓存获取,只会执行取单页记录查询
	Page result = sqlToyLazyDao.findPageBySql(new Page(), "sqltoy_fastPage", staffVO);
}

2.6 极为巧妙的缓存翻译,将多表关联查询尽量变成单表

//支持对象属性注解模式进行缓存翻译
@Translate(cacheName = "dictKeyName", cacheType = "DEVICE_TYPE", keyField = "deviceType")
private String deviceTypeName;

@Translate(cacheName = "staffIdName", keyField = "staffId")
private String staffName;

	
	
	
	
	
		
		
	
	
	
	

2.7 并行查询

// parallQuery 面向查询(不要用于事务操作过程中),sqltoy提供强大的方法,但是否恰当使用需要使用者做合理的判断
/**
  * @TODO 并行查询并返回一维List,有几个查询List中就包含几个结果对象,paramNames和paramValues是全部sql的条件参数的合集
  * @param parallQueryList
  * @param paramNames
  * @param paramValues
  */
public  List> parallQuery(List parallQueryList, String[] paramNames,
			Object[] paramValues);
//定义参数
String[] paramNames = new String[] { "userId", "defaultRoles", "deployId", "authObjType" };
Object[] paramValues = new Object[] { userId, defaultRoles, GlobalConstants.DEPLOY_ID,
		SagacityConstants.TempAuthObjType.GROUP };
// 使用并行查询同时执行2个sql,条件参数是2个查询的合集
List> list = super.parallQuery(
		Arrays.asList(
		        ParallQuery.create().sql("webframe_searchAllModuleMenus").resultType(TreeModel.class),
				ParallQuery.create().sql("webframe_searchAllUserReports").resultType(TreeModel.class)),
		paramNames, paramValues);
		

2.8 跨数据库支持

   
   
   
	
		
			
		
	
        
	
		
			
		
	

2.9 提供行列转换、分组汇总、同比环比等

品类

销售月份

销售笔数

销售数量(吨)

销售金额(万元)

苹果

2019年5月

12

2000

2400

苹果

2019年4月

11

1900

2600

苹果

2019年3月

13

2000

2500

香蕉

2019年5月

10

2000

2000

香蕉

2019年4月

12

2400

2700

香蕉

2019年3月

13

2300

2700

2.9.1 行转列(列转行也支持)



	
	
	
	
	

品类

2019年3月

2019年4月

2019年5月

笔数

数量

总金额

笔数

数量

总金额

笔数

数量

总金额

香蕉

13

2300

2700

12

2400

2700

10

2000

2000

苹果

13

2000

2500

11

1900

2600

12

2000

2400

2.9.2 分组汇总、求平均(可任意层级)


	
		
	
		
	
		
		
		
	

品类

销售月份

销售笔数

销售数量(吨)

销售金额(万元)

总计


71

12600

14900

小计


36

5900

7500

苹果

2019年5月

12

2000

2400

苹果

2019年4月

11

1900

2600

苹果

2019年3月

13

2000

2500

小计


35

6700

7400

香蕉

2019年5月

10

2000

2000

香蕉

2019年4月

12

2400

2700

香蕉

2019年3月

13

2300

2700

2.9.3 先行转列再环比计算



	
	
	
	
	
	
	

品类

2019年3月

2019年4月

2019年5月

笔数

数量

比上月

总金额

比上月

笔数

数量

比上月

总金额

比上月

笔数

数量

比上月

总金额

比上月

香蕉

13

2300


2700


12

2400

4.30%

2700

0.00%

10

2000

-16.70%

2000

-26.00%

苹果

13

2000


2500


11

1900

-5.10%

2600

4.00%

12

2000

5.20%

2400

-7.70%

2.10 分库分表

2.10.1 查询分库分表(分库和分表策略可以同时使用)

   sql参见quickstart项目:com/sqltoy/quickstart/sqltoy-quickstart.sql.xml 文件
   
	
		
		
			=:beginDate]
			#[and t.log_date<=:endDate]
				]]>
		
	

	
	
		
		
			=:beginDate
			#[and t.trans_date<=:endDate]
				]]>
		
	
        

2.10.2 操作分库分表(vo对象由quickvo工具自动根据数据库生成,且自定义的注解不会被覆盖)

@Sharding 在对象上通过注解来实现分库分表的策略配置

参见:com.sqltoy.quickstart.ShardingSearchTest 进行演示

package com.sqltoy.showcase.vo;
import java.time.LocalDate;
import java.time.LocalDateTime;
import org.sagacity.sqltoy.config.annotation.Sharding;
import org.sagacity.sqltoy.config.annotation.SqlToyEntity;
import org.sagacity.sqltoy.config.annotation.Strategy;
import com.sagframe.sqltoy.showcase.vo.base.AbstractUserLogVO;

/*
 * db则是分库策略配置,table 则是分表策略配置,可以同时配置也可以独立配置
 * 策略name要跟spring中的bean定义name一致,fields表示要以对象的哪几个字段值作为判断依据,可以一个或多个字段
 * maxConcurrents:可选配置,表示最大并行数 maxWaitSeconds:可选配置,表示最大等待秒数
 */
@Sharding(db = @Strategy(name = "hashBalanceDBSharding", fields = { "userId" }),
		// table = @Strategy(name = "hashBalanceSharding", fields = {"userId" }),
		maxConcurrents = 10, maxWaitSeconds = 1800)
@SqlToyEntity
public class UserLogVO extends AbstractUserLogVO {
	
	private static final long serialVersionUID = 1296922598783858512L;

	/** default constructor */
	public UserLogVO() {
		super();
	}
}

2.11 五种非数据库相关主键生成策略(可自扩展)

2.11.1 shortNanoTime 22位有序安全ID,格式: 13位当前毫秒+6位纳秒+3位主机ID

2.11.2 nanoTimeId 26位有序安全ID,格式:15位:yyMMddHHmmssSSS+6位纳秒+2位(线程Id+随机数)+3位主机ID

2.11.3 uuid:32 位uuid

2.11.4 SnowflakeId 雪花算法ID

2.11.5 redisId 基于redis 来产生规则的ID主键

根据对象属性值,产生规则有序的ID,比如:订单类型为采购:P 销售:S,贸易类型:I内贸;O 外贸; 订单号生成规则为:1位订单类型+1位贸易类型+yyMMdd+3位流水(超过3位自动扩展) 最终会生成单号为:SI191120001

2.12 elastic原生查询支持

2.13 elasticsearch-sql 插件模式sql模式支持

2.14 sql文件变更自动重载,方便开发和调试

2.15 公共字段统一赋值,针对创建人、创建时间、修改人、修改时间等

2.16 提供了查询结果日期、数字格式化、安全脱敏处理,让复杂的事情变得简单

3.集成说明

3.1 参见trunk 下面的quickstart,并阅读readme.md进行上手

package com.sqltoy.quickstart;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 
 * @project sqltoy-quickstart
 * @description quickstart 主程序入口
 * @author zhongxuchen
 * @version v1.0, Date:2020年7月17日
 * @modify 2020年7月17日,修改说明
 */
@SpringBootApplication
@ComponentScan(basePackages = { "com.sqltoy.config", "com.sqltoy.quickstart" })
@EnableTransactionManagement
public class SqlToyApplication {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SpringApplication.run(SqlToyApplication.class, args);
	}
}

3.2 application.properties sqltoy部分配置

# sqltoy config
spring.sqltoy.sqlResourcesDir=classpath:com/sqltoy/quickstart
spring.sqltoy.translateConfig=classpath:sqltoy-translate.xml
spring.sqltoy.debug=true
#spring.sqltoy.reservedWords=status,sex_type
#dataSourceSelector: org.sagacity.sqltoy.plugins.datasource.impl.DefaultDataSourceSelector
#spring.sqltoy.defaultDataSource=dataSource
# 提供统一公共字段赋值(源码参见quickstart)
spring.sqltoy.unifyFieldsHandler=com.sqltoy.plugins.SqlToyUnifyFieldsHandler
#spring.sqltoy.printSqlTimeoutMillis=200000

3.3 缓存翻译的配置文件sqltoy-translate.xml

<?xml version="1.0" encoding="UTF-8"?>

	
	
		
		
			
			
			
		

		
		
			
			
			
		
		
		
			
			
			
		
	

	
	
		
		
			=:lastUpdateTime
			]]>
		

		
		
			=:lastUpdateTime
			]]>
		

		
		
			=:lastUpdateTime
			]]>
		
	

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SqlToyApplication.class)
public class CrudCaseServiceTest {
	@Autowired
	private SqlToyCRUDService sqlToyCRUDService;

	/**
	 * 创建一条员工记录
	 */
	@Test
	public void saveStaffInfo() {
		StaffInfoVO staffInfo = new StaffInfoVO();
		staffInfo.setStaffId("S190715005");
		staffInfo.setStaffCode("S190715005");
		staffInfo.setStaffName("测试员工4");
		staffInfo.setSexType("M");
		staffInfo.setEmail("test3@aliyun.com");
		staffInfo.setEntryDate(LocalDate.now());
		staffInfo.setStatus(1);
		staffInfo.setOrganId("C0001");
		staffInfo.setPhoto(FileUtil.readAsBytes("classpath:/mock/staff_photo.jpg"));
		staffInfo.setCountry("86");
		sqlToyCRUDService.save(staffInfo);
	}
 }

4. sqltoy sql关键说明

4.1 sqltoy sql最简单规则#[] 对称符号


		
	
		
		
		
		

		
		
		 
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
			
		
		
		
	
		
	
	

	
	
	
	
	
	
	
	
	
	
	
	
        
	
	:beginDate]
			#[and t.STAFF_NAME like :staffName]
			-- 是否虚拟员工@if()做逻辑判断
			#[@if(:isVirtual==true||:isVirtual==0) and t.IS_VIRTUAL=1]
			) t1,sys_organ_info t2
        where t1.ORGAN_ID=t2.ORGAN_ID
	]]>	
	

	
	
	
	
		
		
	
	
	
	
	
	
	

5. sqltoy关键代码说明

5.1 sqltoy-orm 主要分以下几个部分:

5.2 快速阅读理解sqltoy:

六、源码地址

访问一飞开源:https://code.exmay.com/

展开阅读全文

页面更新:2024-05-30

标签:字段   开发者   缓存   香蕉   框架   优点   对象   条件   策略   智慧   代码   操作   数据库

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top