JaVers:一個(gè)強(qiáng)大的Java版本控制框架
JaVers:一個(gè)強(qiáng)大的Java版本控制框架
引言
JaVers是一個(gè)開(kāi)源的Java版本控制框架,旨在幫助開(kāi)發(fā)者更輕松地管理和跟蹤應(yīng)用程序中的對(duì)象版本。它提供了一種簡(jiǎn)單且強(qiáng)大的方式來(lái)處理對(duì)象的創(chuàng)建、修改和刪除,以及版本控制和歷史記錄。JaVers適用于各種應(yīng)用程序,包括但不限于Web應(yīng)用程序、桌面應(yīng)用程序和移動(dòng)應(yīng)用程序。
JaVers使用場(chǎng)景
- 版本控制:JaVers可以幫助開(kāi)發(fā)者對(duì)應(yīng)用程序中的對(duì)象進(jìn)行版本控制,以便更好地跟蹤和管理對(duì)象的修改歷史。
- 事務(wù)管理:JaVers提供了一個(gè)簡(jiǎn)單的事務(wù)管理API,可以幫助開(kāi)發(fā)者在事務(wù)中執(zhí)行操作并處理異常。
- 合并沖突:當(dāng)多個(gè)開(kāi)發(fā)者同時(shí)對(duì)同一對(duì)象進(jìn)行修改時(shí),JaVers可以幫助解決合并沖突,確保數(shù)據(jù)的一致性。
- 數(shù)據(jù)庫(kù)遷移:使用JaVers,開(kāi)發(fā)者可以輕松地將對(duì)象從舊版本遷移到新版本,而無(wú)需手動(dòng)處理復(fù)雜的數(shù)據(jù)庫(kù)遷移過(guò)程。
JaVers優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 簡(jiǎn)單易用:JaVers框架簡(jiǎn)單易用,學(xué)習(xí)曲線平緩,開(kāi)發(fā)者可以快速上手。
- 強(qiáng)大功能:JaVers提供了豐富的功能,如版本控制、事務(wù)管理、合并沖突和數(shù)據(jù)庫(kù)遷移等。
- 靈活擴(kuò)展:JaVers框架具有良好的擴(kuò)展性,開(kāi)發(fā)者可以根據(jù)需要自定義和擴(kuò)展框架的功能。
- 社區(qū)活躍:JaVers擁有一個(gè)活躍的開(kāi)源社區(qū),可以為開(kāi)發(fā)者提供支持和幫助。
- 缺點(diǎn):
- 技術(shù)門檻高:JaVers框架相對(duì)較復(fù)雜,需要一定的學(xué)習(xí)成本。對(duì)于初學(xué)者來(lái)說(shuō),可能需要花費(fèi)較長(zhǎng)時(shí)間來(lái)理解和掌握框架的使用。
- 對(duì)數(shù)據(jù)庫(kù)性能的影響:JaVers在進(jìn)行版本控制時(shí)需要存儲(chǔ)大量的歷史數(shù)據(jù),這可能會(huì)對(duì)數(shù)據(jù)庫(kù)性能產(chǎn)生一定的影響。在處理大量數(shù)據(jù)時(shí),需要注意性能優(yōu)化。
- 可能產(chǎn)生大量的數(shù)據(jù)冗余:由于JaVers需要保存對(duì)象的完整歷史記錄,因此可能會(huì)產(chǎn)生大量的數(shù)據(jù)冗余。對(duì)于一些不需要長(zhǎng)時(shí)間保留歷史記錄的應(yīng)用場(chǎng)景,使用JaVers可能會(huì)浪費(fèi)存儲(chǔ)資源。
JaVers示例代碼
下面是兩個(gè)個(gè)簡(jiǎn)單的JaVers示例代碼,展示了如何使用JaVers實(shí)現(xiàn)數(shù)據(jù)比對(duì)以及對(duì)對(duì)象進(jìn)行版本控制:
首先,需要在項(xiàng)目中引入JaVers的相關(guān)依賴,如果需要對(duì)結(jié)果持久化,還需要額外引入對(duì)應(yīng)的依賴:
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>7.3.6</version>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-persistence-sql</artifactId>
<version>7.3.6</version>
</dependency>
- Compare
通過(guò)JaVers我們可以實(shí)現(xiàn)兩個(gè)值對(duì)象的比較,通過(guò)下面的示例可以看到效果:
Person p1 = new Person("1","junly",22);
Person p2 = new Person("2","rose",22);
Javers javers = JaversBuilder.javers().build();
Diff diff = javers.compare(p1, p2);
if (diff.hasChanges()) {
Changes changes = diff.getChanges();
changes.forEach(change->{
System.out.println(change.toString());
});
}
System.out.println( diff.prettyPrint() );
執(zhí)行上面的代碼,會(huì)得到如下的輸出,反映了一個(gè)對(duì)象修改前后具體屬性進(jìn)行了怎樣的變化,之前做的數(shù)據(jù)采集的項(xiàng)目中,用戶提交的數(shù)據(jù)是一個(gè)大json對(duì)象, 由于用戶可以進(jìn)行多次修改,但又需要記錄每次修改的明細(xì),如果自己寫功能則需要寫大量的代碼來(lái)處理,而JaVers可以幫助開(kāi)發(fā)者完美解決了這類問(wèn)題。
ValueChange{ property: 'id', left:'1', right:'2' }
ValueChange{ property: 'name', left:'junly', right:'rose' }
Diff:
* changes on com.sucl.blog.tool.javers.entity.Person/ :
- 'id' changed: '1' -> '2'
- 'name' changed: 'junly' -> 'rose'
- Commit
通過(guò)Commit我們可以實(shí)現(xiàn)對(duì)對(duì)象進(jìn)行版本控制,通過(guò)下面的示例可以看到效果:
public static void main(String[] args) {
Javers javers = JaversBuilder.javers().build();
Person p1 = new Person("1","junly",22);
javers.commit("u1", p1);
Person p2 = new Person("1","junly",20);
javers.commit("u1", p2);
Person p3 = new Person("1","tom",22);
javers.commit("u1", p3);
JqlQuery query = QueryBuilder.byInstanceId("1", Person.class).build();
System.out.println("===========================");
//
List<Shadow<Object>> shadows = javers.findShadows(query);
shadows.forEach(shadow-> System.out.println( shadow.get() ));
System.out.println("===========================");
//
List<CdoSnapshot> snapshots = javers.findSnapshots(query);
snapshots.forEach(snapshot-> System.out.println( snapshot.getChanged() ));
System.out.println("===========================");
//
Changes changes = javers.findChanges(query);
changes.forEach(change-> System.out.println( change.toString() ));
}
通過(guò)上面的例子,我們可以借用JaVers對(duì)對(duì)象進(jìn)行版本控制,并可以獲取到對(duì)象歷史數(shù)據(jù)。在實(shí)體變化時(shí)記錄歷史版本、變更過(guò)程以及變化明細(xì)。
===========================
Person(id=1, name=tom, age=22)
Person(id=1, name=junly, age=20)
Person(id=1, name=junly, age=22)
===========================
[name, age]
[age]
[name, id, age]
===========================
ValueChange{ property: 'name', left:'junly', right:'tom' }
ValueChange{ property: 'age', left:'20', right:'22' }
ValueChange{ property: 'age', left:'22', right:'20' }
NewObject{ new object: com.sucl.blog.tool.javers.entity.Person/1 }
InitialValueChange{ property: 'id', left:'', right:'1' }
InitialValueChange{ property: 'name', left:'', right:'junly' }
InitialValueChange{ property: 'age', left:'', right:'22' }
Process finished with exit code 0
Shadow和Changes是JaVers提供的兩種查詢方式,通過(guò)它們可以獲取到實(shí)體的歷史版本。
Snapshot是JaVers提供的一種查詢方式,通過(guò)它可以獲取到實(shí)體的歷史版本。
JaVers還提供了JQL查詢語(yǔ)言,可以幫助開(kāi)發(fā)者實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的各種查詢,比如基于變化的屬性、提交人、時(shí)間等等。
JaVers持久化
JaVers提供了兩種持久化方式,一種是內(nèi)存持久化,另一種是數(shù)據(jù)庫(kù)持久
目前可以支持的數(shù)據(jù)庫(kù)有:
- H2
- MySQL
- PostgreSQL
- Oracle
- SQL Server
- MongoDB
在上面的例子當(dāng)中,你可以通過(guò)配置Repository來(lái)實(shí)現(xiàn)變更過(guò)程的持久化,例如使用Mysql數(shù)據(jù)庫(kù),可以配置如下:
JaversRepository javersRepository = SqlRepositoryBuilder.sqlRepository()
.withConnectionProvider(()-> getConnection())
.withDialect(DialectName.MYSQL)
.build();
Javers javers = JaversBuilder.javers()
.registerJaversRepository(javersRepository)
.build();
這樣我們通過(guò)JQL查詢就可以按需獲取更多的歷史數(shù)據(jù)了。
結(jié)束語(yǔ)
Javers在做數(shù)據(jù)對(duì)比以及數(shù)據(jù)變更追蹤的過(guò)程中,提供了豐富的功能,如版本控制、事務(wù)管理、合并沖突和數(shù)據(jù)庫(kù)遷移等。同時(shí),JaVers的擴(kuò)展性也非常好,開(kāi)發(fā)者可以根據(jù)需要自定義和擴(kuò)展框架的功能。