内容简介:jSqlBox3.0.0 发布 jSqlBox 是一个建立在 DbUtils 内核上的 Java 全功能数据库持久层工具,具备跨数据库(80 多种方言)、DD L生成、分页、多种SQL写法、分库分表、声明式事务、分布式事务、主从、实体 CURD、实体...
jSqlBox3.0.0 发布
jSqlBox 是一个建立在 DbUtils 内核上的 Java 全功能数据库持久层工具,具备跨数据库(80 多种方言)、DD L生成、分页、多种 SQL 写法、分库分表、声明式事务、分布式事务、主从、实体 CURD、实体关联查询、ActiveRecord、Sql 模板等功能。
本次更新主要内容:支持分库分表的分布式事务
Gtx 事务是 jSqlBox3.0.0 新增的分布式事务模块,它的总体思路和 Seata 类似,也是通过生成反向记录来自动回滚,减小对业务的侵入,但 jSqlBox 采用的思路是将分布式事务建立在 ORM 工具之上,不是分析SQL 内容,而是记录实体的插入、删除、修改操作,以生成回滚记录。这样一来,在实现难度上就降低了一个等级,以牺牲 SQL 支持来达到最好的跨数据库兼容性,支持所有数据库。在具体实现上,它通过采用最大保证完成模式结合全局记录锁的方案,架构请参见 Bag 分布式事务对 SAGA 分布式事务的改进一文。
以下为一个分布式事务的配置和演示:
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
以上所述就是小编给大家介绍的《jSqlBox 3.0.0发布, 自带分布式事务的 Java ORM 工具》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- laravel自带用户认证
- Mac自带apache配置
- opencv自带例子学习-图像混合
- Golang中自带的强大命令工具
- Android调用系统自带的分享功能
- 使用oracle自带的命令进行导入导出
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。