在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:BeetlSQL开源软件地址:https://gitee.com/xiandafu/beetlsql开源软件介绍:数据访问框架BeetlSQL的目标是提供开发高效,维护高效,运行高效的数据库访问框架,在一个系统多个库的情况下,提供一致的编写代码方式。支持如下数据平台
BeetlSQL 不仅仅是简单的类似MyBatis或者是Hibernate,或者是俩着的综合,BeetlSQL远大理想是对标甚至超越Spring Data,是实现数据访问统一的框架,无论是传统数据库,还是大数据,还是查询引擎或者时序库,内存数据库。
BeetlSQL 3.x 使用说明,当前版本](https://www.kancloud.cn/xiandafu/beetlsql3_guide) 社区提供的文档 https://beetlsql-doc.vercel.app/ <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetlsql</artifactId> <version>3.${version}</version></dependency> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetlsql</artifactId> <version>2.13.3.RELEASE</version></dependency> 适合用户
编译源码git clone https://gitee.com/xiandafu/beetlsqlmvn clean packagemvn clean install #如果想修改源码 注意:BeetlSQL3 集成了Spring,以及支持大数据等,就算配置了国内镜像,也可能需要很长时间下载大数据依赖包,为了让编译快速通过,你需要进入pom.xml ,屏蔽sql-integration,sql-db-support,sql-jmh三个模块 <modules><!--核心功能 --><module>sql-core</module><module>sql-mapper</module><module>sql-util</module><module>sql-fetech</module><!-- 打包到一起 --><module>beetlsql</module><module>sql-gen</module><module>sql-test</module><module>sql-samples</module><!-- 集成和扩展太多的数据库,可以被屏蔽,以加速项目下载jar --><!-- <module>sql-integration</module>--><!-- <module>sql-jmh</module>--><!-- <module>sql-db-support</module>--></modules> 阅读源码例子可以从模块 以 sql-samples 又包含了三个模块大约100个例子
以usage模块为例子,包含如下代码
BeetlSQL提供了saga事物管理一种思路,但目前还是试验版本,欢迎不怕死的人尝试,和我一起完善这部分,其例子可以在saga模块的单元测试中找到 代码示例例子1,内置方法,无需写SQL完成常用操作UserEntity user = sqlManager.unique(UserEntity.class,1);user.setName("ok123");sqlManager.updateById(user);UserEntity newUser = new UserEntity();newUser.setName("newUser");newUser.setDepartmentId(1);sqlManager.insert(newUser); 输出日志友好,可反向定位到调用的代码 ┏━━━━━ Debug [user.selectUserAndDepartment] ━━━┣ SQL: select * from user where 1 = 1 and id=?┣ 参数: [1]┣ 位置: org.beetl.sql.test.QuickTest.main(QuickTest.java:47)┣ 时间: 23ms┣ 结果: [1]┗━━━━━ Debug [user.selectUserAndDepartment] ━━━ 例子2 使用SQLString sql = "select * from user where id=?";Integer id = 1;SQLReady sqlReady = new SQLReady(sql,new Object[id]);List<UserEntity> userEntities = sqlManager.execute(sqlReady,UserEntity.class);//Map 也可以作为输入输出参数List<Map> listMap = sqlManager.execute(sqlReady,Map.class); 例子3 使用模板SQLString sql = "select * from user where department_id=#{id} and name=#{name}";UserEntity paras = new UserEntity();paras.setDepartmentId(1);paras.setName("lijz");List<UserEntity> list = sqlManager.execute(sql,UserEntity.class,paras);String sql = "select * from user where id in ( #{join(ids)} )";List list = Arrays.asList(1,2,3,4,5); Map paras = new HashMap();paras.put("ids", list);List<UserEntity> users = sqlManager.execute(sql, UserEntity.class, paras); 例子4 使用Query类支持重构 LambdaQuery<UserEntity> query = sqlManager.lambdaQuery(UserEntity.class);List<UserEntity> entities = query.andEq(UserEntity::getDepartmentId,1) .andIsNotNull(UserEntity::getName).select(); 例子5 把数十行SQL放到sql文件里维护//访问user.md#selectSqlId id = SqlId.of("user","select");Map map = new HashMap();map.put("name","n");List<UserEntity> list = sqlManager.select(id,UserEntity.class,map); 例子6 复杂映射支持支持像mybatis那样复杂的映射
@Data@ResultProvider(AutoJsonMapper.class) public static class MyUserView { Integer id; String name; DepartmentEntity dept; }
{ "id": "id", "name": "name", "dept": { "id": "dept_id", "name": "dept_name" }, "roles": { "id": "r_id", "name": "r_name" }} 例子7 最好使用mapper来作为数据库访问类@SqlResource("user") /*sql文件在user.md里*/public interface UserMapper extends BaseMapper<UserEntity> { @Sql("select * from user where id = ?") UserEntity queryUserById(Integer id); @Sql("update user set name=? where id = ?") @Update int updateName(String name,Integer id); @Template("select * from user where id = #{id}") UserEntity getUserById(Integer id); @SpringData/*Spring Data风格*/ List<UserEntity> queryByNameOrderById(String name); /** * 可以定义一个default接口 * @return */ default List<DepartmentEntity> findAllDepartment(){ Map paras = new HashMap(); paras.put("exlcudeId",1); List<DepartmentEntity> list = getSQLManager().execute("select * from department where id != #{exlcudeId}",DepartmentEntity.class,paras); return list; } /** * 调用sql文件user.md#select,方法名即markdown片段名字 * @param name * @return */ List<UserEntity> select(String name); /** * 翻页查询,调用user.md#pageQuery * @param deptId * @param pageRequest * @return */ PageResult<UserEntity> pageQuery(Integer deptId, PageRequest pageRequest); @SqlProvider(provider= S01MapperSelectSample.SelectUserProvider.class) List<UserEntity> queryUserByCondition(String name); @SqlTemplateProvider(provider= S01MapperSelectSample.SelectUs List<UserEntity> queryUserByTemplateCondition(String name); @Matcher /*自己定义个Matcher注解也很容易*/ List<UserEntity> query(Condition condition,String name);}
例子8 使用Fetch 注解可以在查询后根据Fetch注解再次获取相关对象,实际上@FetchOne和 @FetchMany是自定义的,用户可自行扩展 @Data @Table(name="user") @Fetch public static class UserData { @Auto private Integer id; private String name; private Integer departmentId; @FetchOne("departmentId") private DepartmentData dept; } /** * 部门数据使用"b" sqlmanager */ @Data @Table(name="department") @Fetch public static class DepartmentData { @Auto private Integer id; private String name; @FetchMany("departmentId") private List<UserData> users; } 例子9 不同数据库切换可以自行扩展ConditionalSQLManager的decide方法,来决定使用哪个SQLManager SQLManager a = SampleHelper.init(); SQLManager b = SampleHelper.init(); Map<String, SQLManager> map = new HashMap<>(); map.put("a", a); map.put("b", b); SQLManager sqlManager = new ConditionalSQLManager(a, map); //不同对象,用不同sqlManager操作,存入不同的数据库 UserData user = new UserData(); user.setName("hello"); user.setDepartmentId(2); sqlManager.insert(user); DepartmentData dept = new DepartmentData(); dept.setName("dept"); sqlManager.insert(dept); 使用注解 @TargetSQLManager来决定使用哪个SQLManger @Data @Table(name = "department") @TargetSQLManager("b") public static class DepartmentData { @Auto private Integer id; private String name; } 例子10 如果想给每个sql语句增加一个sqlId标识这样好处是方便数据库DBA与程序员沟通 public static class SqlIdAppendInterceptor implements Interceptor{ @Override public void before(InterceptorContext ctx) { ExecuteContext context = ctx.getExecuteContext(); String jdbcSql = context.sqlResult.jdbcSql; String info = context.sqlId.toString(); //为发送到数据库的sql增加一个注释说明,方便数据库dba能与开发人员沟通 jdbcSql = "/*"+info+"*/\n"+jdbcSql; context.sqlResult.jdbcSql = jdbcSql; } } 例子11 代码生成框架可以使用内置的代码生成框架生成代码何文档,也可以自定义的,用户可自行扩展SourceBuilder类 List<SourceBuilder> sourceBuilder = new ArrayList<>(); SourceBuilder entityBuilder = new EntitySourceBuilder(); SourceBuilder mapperBuilder = new MapperSourceBuilder(); SourceBuilder mdBuilder = new MDSourceBuilder(); //数据库markdown文档 SourceBuilder docBuilder = new MDDocBuilder(); sourceBuilder.add(entityBuilder); sourceBuilder.add(mapperBuilder); sourceBuilder.add(mdBuilder); sourceBuilder.add(docBuilder); SourceConfig config = new SourceConfig(sqlManager,sourceBuilder); //只输出到控制台 ConsoleOnlyProject project = new ConsoleOnlyProject(); String tableName = "USER"; config.gen(tableName,project); 例子13 定义一个Beetl函数 GroupTemplate groupTemplate = groupTemplate(); groupTemplate.registerFunction("nextDay",new NextDayFunction()); Map map = new HashMap(); map.put("date",new Date()); String sql = "select * from user where create_time is not null and create_time<#{nextDay(date)}"; List<UserEntity> count = sqlManager.execute(sql,UserEntity.class,map); nextDay函数是一个Beetl函数,非常容易定义,非常容易在sql模板语句里使用 public static class NextDayFunction implements Function { @Override public Object call(Object[] paras, Context ctx) { Date date = (Date) paras[0]; Calendar c = Calendar.getInstance(); c.setTime(date); c.add(Calendar.DAY_OF_YEAR, 1); // 今天+1天 return c.getTime(); } } 例子14 更多可扩展的例子根据ID或者上下文自动分表,toTable是定义的一个Beetl函数, static final String USER_TABLE="${toTable('user',id)}"; @Data @Table(name = USER_TABLE) public static class MyUser { @AssignID private Integer id; private String name; } 定义一个Jackson注解,@Builder是注解的注解,表示用Builder指示的类来解释执行,可以看到BeetlSQL的注解可扩展性就是来源于@Build注解 @Retention(RetentionPolicy.RUNTIME)@Target(value = {ElementType.METHOD, ElementType.FIELD})@Builder(JacksonConvert.class)public @interface Jackson {} 定义一个@Tenant 放在POJO上,BeetlSQL执行时候会给SQL添加额外参数,这里同样使用了@Build注解 /** * 组合注解,给相关操作添加额外的租户信息,从而实现根据租户分表或者分库 */@Retention(RetentionPolicy.RUNTIM@@Target(value = {ElementType.TYPE})@Builder(TenantContext.class)public @interface Tenant {} 使用XML而不是JSON作为映射 @Retention(RetentionPolicy.RUNTIME)@Target(value = {ElementType.TYPE})@Builder(ProviderConfig.class)public @interface XmlMapping { String path() default "";}
例子15 微服务事务BeetlSQL除了集成传统的事务管理器外,也提供Saga事务支持,支持多库事务和微服务事务。 其原理是自动为每个操作提供反向操作,如insert的反向操作是deleteById,并把这些操作作为任务交给Saga—Server调度。实现了通过Kafka作为客户端(各个APP)与SagaServer 交互的媒介保证任务可靠传递并最终被系统执行。 String orderAddUrl = "http://127.0.0.1:8081/order/item/{orderId}/{userId}/{fee}";String userBalanceUpdateUrl = "http://127.0.0.1:8082/user/fee/{orderId}/{userId}/{fee}";..........SagaContext sagaContext = SagaContext.sagaContextFactory.current();try { sagaContext.start(gid); //模拟调用俩个微服务,订单和用户 rest.postForEntity(orderAddUrl, null,String.class, paras); rest.postForEntity(userBalanceUpdateUrl, null,String.class, paras); if (1 == 1) { throw new RuntimeException("模拟失败,查询saga-server 看效果"); }} catch (Exception e) { log.info("error " + e.getMessage()); log.info("start rollback " + e.getMessage()); sagaContext.rollback(); return e.getMessage();} 以用户系统为例(源码是DemoController),userBalanceUpdateUrl对应如下扣费逻辑 @AutowiredUserMapper userMapper;@Transactional(propagation= Propagation.NEVER)public void update(String orderId,String userId,Integer fee){ SagaContext sagaContext = SagaContext.sagaContextFactory.current(); try{ sagaContext.start(orderId); UserEntity user = userMapper.unique(userId); user.setBalance(user.getBalance()-fee); userMapper.upd |
请发表评论