您现在的位置是:首页 > 文章详情

jSqlBox 3.0.0发布, 自带分布式事务的 Java ORM 工具

日期:2019-09-05点击:362

jSqlBox3.0.0 发布

jSqlBox 是一个建立在 DbUtils 内核上的 Java 全功能数据库持久层工具,具备跨数据库(80 多种方言)、DD L生成、分页、多种SQL写法、分库分表、声明式事务、分布式事务、主从、实体 CURD、实体关联查询、ActiveRecord、Sql 模板等功能。

本次更新主要内容:支持分库分表的分布式事务

Gtx 事务是 jSqlBox3.0.0 新增的分布式事务模块,它的总体思路和 Seata 类似,也是通过生成反向记录来自动回滚,减小对业务的侵入,但 jSqlBox 采用的思路是将分布式事务建立在 ORM 工具之上,不是分析SQL 内容,而是记录实体的插入、删除、修改操作,以生成回滚记录。这样一来,在实现难度上就降低了一个等级,以牺牲 SQL 支持来达到最好的跨数据库兼容性,支持所有数据库。在具体实现上,它通过采用最大保证完成模式结合全局记录锁的方案,架构请参见 Bag 分布式事务对 SAGA 分布式事务的改进一文。
image

以下为一个分布式事务的配置和演示:

 public class GtxTest { SqlBoxContext[] ctx = new SqlBoxContext[3]; private static DataSource newTestDataSource() { HikariDataSource ds = new HikariDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setJdbcUrl("jdbc:h2:mem:" + new Random().nextLong() // random h2 ds name + ";MODE=MYSQL;DB_CLOSE_DELAY=-1;TRACE_LEVEL_SYSTEM_OUT=0"); ds.setUsername("sa"); ds.setPassword(""); return ds; } @Before public void init() { SqlBoxContext lock = new SqlBoxContext(newTestDataSource()); lock.setName("lock"); lock.executeDDL(lock.toCreateDDL(GtxId.class)); lock.executeDDL(lock.toCreateDDL(GtxLock.class)); lock.executeDDL(lock.toCreateGtxLogDDL(Usr.class)); GtxConnectionManager lockCM = new GtxConnectionManager(lock); for (int i = 0; i < 3; i++) { ctx[i] = new SqlBoxContext(newTestDataSource()); ctx[i].setName("db"); ctx[i].setDbCode(i); ctx[i].setConnectionManager(lockCM); ctx[i].setMasters(ctx); ctx[i].executeDDL(ctx[i].toCreateDDL(GtxTag.class)); ctx[i].executeDDL(ctx[i].toCreateDDL(Usr.class)); } } public void Div0Test() { ctx[0].startTrans(); try { new Usr().insert(ctx[0]); new Usr().insert(ctx[1]); new Usr().insert(ctx[1]); new Usr().insert(ctx[2]); System.out.println(1 / 0);//强制出错 ctx[0].commitTrans(); } catch (Exception e) { TxResult result=ctx[0].rollbackTrans(); GtxUnlockServ.forceUnlock(ctx[0], result); } Assert.assertEquals(0, ctx[0].eCountAll(Usr.class)); Assert.assertEquals(0, ctx[1].eCountAll(Usr.class)); Assert.assertEquals(0, ctx[2].eCountAll(Usr.class)); } } 

上例是最简单的一个分布式事务演示,包含了数据源配置和 DDL 建表。GTX 事务如果在事务提交中出错,无论有无部分事务提交发生,只要数据库没有down机,在任意时刻网线中断,数据的最终一致性都能保证,不象 XA 协议有可能会有数据不一致的情况发生。

上例 GtxUnlockServ.forceUnlock(ctx[0], result) 方法仅用于单元测试,实际项目中应该去掉这一行,而改成用GtxUnlockServ.start(ctx, loopInterval , maxLoopQty);方法开启一个单独的解锁服务,第二个参数为解锁间隔,单位为秒,必须设置成一个远大于数据库事务超时时间的值,第三个参数可以设为 0,表示没有最大解锁次数限制。

jSqlBox 的分布式事务支持分库、分表,以及指定锁服务器的序号,这样如果没有一个高性能(云)锁服务器,可以通过配置一个锁服务器群来提高事务处理性能,当然这种情况下,锁服务器序号的指定通常是与业务相关的,例如红包转账分布式事务,可以红包的 ID 取模作为锁服务器序号。具体示例请详见 wiki 及单元测试目录下的 GtxShardDbTbLockDbTest.java

jSqlBox 分布式事务的构想几乎和 Seata 项目开源时同时提出,但从完成度来看差不多,这并不表示本人水平高,一个人干翻了 Seata,而是因为与 ORM 工具整合成一体的分布式事务,在编写难度上要远远小于Seata 这种分析 SQl 语法、从底层代理数据源的第三方工具,而且 jSqlBox 的分布式事务只支持一组直连的 DataSource,不提供微服务的调用接口。

本次更新还包括以下内容: 
1.  在 demo 目录下演示了使用 Beetl 作为 SQL 模板。例如以下是一个使用 Beetl 模板的调用,通过与 Text 类的结合使用,可以方便地利用 IDE 功能快速定位到模板文本: 
List<Map<String, Object>> usrs = ctx.tQueryForMapList(SelectUsers1.class, bind("age", 50, "name", null));

2.  JAVA8 类中引入 $,a$,c$ 静态简化写法, 例如在 Dao-benchmark 项目中,以下这种 SQL 写法是支持实体字体名重构的:
List<DemoUser> result = gctx().eFindBySample(sample, " or ", $(u::getCode), "=?", param("efg"));
其中的$(u::getCode)静态方法会返回"code"这个实体属性名,也就是数据库的列名(通常约定数据库列名命名与实体属性名一致)

3. JDBPRO 中新增 noNull 方法,用于 like 查询时的非空判断,使用示例:
ctx.iQueryForMapList("select * from a where 1=1",noNull("and name like ?","%",name,"%"));

4. 一些其它改进:
如 TinyTx 类不再使用,改名为 TinyTxAOP,jDialects 模块中 ColumnModel 类中的 length 字段被删除,并修正了 precision 和 scale 在设定浮点数的错误。

5. 另外以下与 jSqlBox 相关的子项目也一并更新到 3.0.0 版,就不再另发更新资讯了,有以下子项目:
jDialects 支持80多种数据库的分页、类型变换、DDL 生成、实体源码生成的数据库方言工具 
jTransactions 一个单独的事务工具,含分布式事务功能
jDbPro 这是 jSqlBox 的内核,建立在 DbUtils 基础上,只有 SQL 功能,不包含 ORM 等功能
MyFat 这是一个 Mybatis 插件,它将 jSqlBox 和 MyBatis 捆绑在一起,利用 jSqlBox 来补足 Mybatis 缺少的实体 CRUD 等功能

期望 | Futures

欢迎发issue提出更好的意见或提交PR,帮助完善jSqlBox

版权 | License

Apache 2.0

原文链接:https://www.oschina.net/news/109632/jsqlbox-3-0-0-released
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章