Neo是一個基於JDBC開發的至簡化框架,名字源於《黑客帝國》男主角名字,寓意爲連接虛擬與現實。開發源頭,源於之前接觸的一些ORM框架,思想很不錯但是沒開源無法使用,而且自己也有很多想法因此設計了該框架。
使用文檔
快速入門
該框架秉承大道至簡理念,採用一個Neo對象對應一個DataSource方式,然後這個Neo對象擁有對錶的各種操作。
maven引入
當前已經發布到maven中央倉庫,直接使用即可,目前最低版本0.3.0,不同版本的api差距不小,建議使用最新版本。目前版本還未脫離實驗階段,如果有什麼問題請及時反饋
<dependency>
<groupId>com.github.simonalong</groupId>
<artifactId>Neo</artifactId>
<!-- 請替換具體的版本-->
<version>${latest.release.version}</version>
</dependency>
快速入門
一個DB對應的一個對象Neo,操作表,則填入對應的表名即可
public void testDemo1() {
String url = "jdbc:mysql://127.0.0.1:3306/neo?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
String user = "neo_test";
String password = "neo@Test123";
String tableName = "neo_table1";
// 連接
Neo neo = Neo.connect(url, user, password);
// 插入
NeoMap data = neo.insert(tableName, NeoMap.of("group", "value"));
data.put("group", "value1");
// 更新
neo.update(tableName, data);
// 刪除
neo.delete(tableName, data);
// 查詢一行
neo.one(tableName, data);
// 查詢多行
neo.list(tableName, data);
// 查詢指定列的一個值
neo.value(tableName, "group", data);
// 查詢指定列的多個值
neo.values(tableName, "group", data);
// 查詢分頁
neo.page(tableName, data, NeoPage.of(1, 20));
// 分頁個數
table.count(tableName, data);
// 執行sql
neo.execute("select * from %s where `group` =?", tableName, "group1");
// 事務
neo.tx(()->{
neo.update(tableName, NeoMap.of("id", 12, "group", "value1"));
neo.one(tableName, 12);
neo.update("neo_table2", NeoMap.of("name", 12));
});
// 批量
List<NeoMap> list = new ArrayList<>();
list.add(NeoMap.of("group", "v1"));
list.add(NeoMap.of("group", "v2"));
list.add(NeoMap.of("group", "v3"));
list.add(NeoMap.of("group", "v4"));
neo.batchInsert(tableName, list);
// 批量更新
table.batchUpdate(tableName, list, Columns.of("group"));
}
指定表的話,就更簡單,一個表對應一個對象NeoTable
public void testDemo2() {
String url = "jdbc:mysql://127.0.0.1:3306/neo?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
String user = "neo_test";
String password = "neo@Test123";
String tableName = "neo_table1";
// 連接
Neo neo = Neo.connect(url, user, password);
NeoTable table = neo.getTable(tableName);
// 插入
NeoMap data = table.insert(NeoMap.of("group", "value"));
data.put("group", "value1");
// 更新
table.update(data);
// 刪除
table.delete(data);
// 查詢一行
table.one(data);
// 查詢多行
table.list(data);
// 查詢指定列的一個值
table.value("group", data);
// 查詢指定列的多個值
table.values("group", data);
// 查詢分頁
table.page(data, NeoPage.of(1, 20));
// 分頁個數
table.count(data);
// 批量插入
List<NeoMap> list = new ArrayList<>();
list.add(NeoMap.of("group", "v1"));
list.add(NeoMap.of("group", "v2"));
list.add(NeoMap.of("group", "v3"));
list.add(NeoMap.of("group", "v4"));
table.batchInsert(list);
// 批量更新
table.batchUpdate(list, Columns.of("group"));
}
注意
生成一個Neo對象除了可以通過url、user和password,還可以通過DataSource方式
// 連接
Neo neo = Neo.connect(datasource);
指定實體
上面我們對數據的操作全都是基於map,下面我們基於實體DO對數據庫進行操作
/**
* 指定表的話,就更簡單
*/
@Test
public void testDemo3() {
String url = "jdbc:mysql://127.0.0.1:3306/neo?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
String user = "neo_test";
String password = "neo@Test123";
String tableName = "neo_table1";
// 連接
Neo neo = Neo.connect(url, user, password);
NeoTable table = neo.getTable(tableName);
// 實體數據
DemoEntity3 entity = new DemoEntity3().setGroup("group1").setUsName("name1");
// 插入
DemoEntity3 result = table.insert(entity);
result.setUsName("name2");
// 更新
table.update(result);
// 刪除
table.delete(result);
// 查詢一行
table.one(result);
// 查詢多行
table.list(result);
// 查詢指定列的
table.value("group", NeoMap.of("user_name", "name2"));
// 查詢指定列的多個值
table.values("group", NeoMap.of("user_name", "name2"));
// 查詢分頁,第一個參數是搜索條件
table.page(NeoMap.of("user_name", "name2"), NeoPage.of(1, 20));
// 分頁個數
table.count(data);
// 批量插入
List<DemoEntity3> list = new ArrayList<>();
list.add(new DemoEntity3().setGroup("group1").setUsName("name1"));
list.add(new DemoEntity3().setGroup("group2").setUsName("name2"));
list.add(new DemoEntity3().setGroup("group3").setUsName("name3"));
list.add(new DemoEntity3().setGroup("group4").setUsName("name4"));
table.batchInsertEntity(list);
// 批量更新
table.batchUpdateEntity(list, Columns.of("group"));
}
實體和DB字段映射
實體和DB中字段的映射,可以有三種方式進行配置
1.NeoMap
全局配置:NeoMap.setDefaultNamingChg(xxx)
2.NeoMap
實體單獨配置:neoMap.setNamingChg(xxx)
3.通過註解@Column
對應配置:每個屬性上面添加@Column
其中是DB中的屬性名
下面介紹@Column
的用法,以後表字段修改時候,實體就不用修改,如果有屬性上面沒有添加註解,則默認按照類型NamingChg.UNDERLINE
進行轉換
/**
* @author robot
*/
@Data
@Accessors(chain = true)
public class NeoTable1DO {
@Column("id")
private Long id;
/**
* 數據來源組,外鍵關聯lk_config_group
*/
@Column("group")
private String group;
/**
* 任務name
*/
@Column("name")
private String name;
/**
* 修改人名字
*/
@Column("user_name")
private String userName;
@Column("age")
private Integer age;
@Column("sl")
private Long sl;
@Column("data_name")
private String dataName;
}
sql字段
CREATE TABLE `neo_table1` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`group` char(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '數據來源組,外鍵關聯lk_config_group',
`name` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '任務name',
`user_name` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '修改人名字',
`age` int(11) DEFAULT NULL,
`sl` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `group_index` (`group`)
) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
業務使用
也可以繼承使用,針對業務接入,可以直接繼承類AbstractBizService
即可具備一個表的常見的所有功能,只需要實現如下兩個方法即可
public class BizServiceTest extends AbstractBizService {
public BizServiceTest() throws SQLException {
}
@Override
public DbSync getDb() {
String url = "jdbc:mysql://127.0.0.1:3306/neo?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
String user = "neo_test";
String password = "neo@Test123";
return Neo.connect(url, user, password);
}
@Override
public String getTableName() {
return "neo_table1";
}
@Test
public void testInsert() {
TestEntity entity = new TestEntity()
.setGroup("ok")
.setUserName("me")
.setName("hello");
insert(entity);
}
}
實體代碼生成器
本框架也支持實體生成器,如下,即可生成如上所示的類NeoTable1DO
就是如下生成的
public class CodeGenTest {
@Test
public void test1(){
EntityCodeGen codeGen = new EntityCodeGen()
// 設置DB信息
.setDb("neo_test", "neo@Test123", "jdbc:mysql://127.0.0.1:3306/neo?useUnicode=true&characterEncoding=UTF-8&useSSL=false")
// 設置項目路徑
.setProjectPath("/Users/zhouzhenyong/project/private/Neo")
// 設置實體生成的包路徑
.setEntityPath("com.simonalong.neo.entity")
// 設置表前綴過濾
// .setPreFix("t_")
// 設置要排除的表
//.setExcludes("xx_test")
// 設置只要的表
.setIncludes("neo_table1")
// 設置屬性中數據庫列名字向屬性名字的轉換,這裏設置下劃線,比如:data_user_base -> dataUserBase
.setFieldNamingChg(NamingChg.UNDERLINE);
// 代碼生成
codeGen.generate();
}
}
分佈式ID生成器
我們這裏也提供了分佈式ID生成器方案,採用的是改進版雪花算法,徹底解決了雪花算法存在的常見問題(時間回撥問題,workerId回收問題),對於如何解決的,具體方案可見文檔,也可見我的另外一個項目Butterfly(Neo框架中的發號器方案是Butterfly中的一個使用選項)。
採用的是改進版雪花算法,不僅沒有時間回撥問題,性能還比雪花算法還要高十幾倍,普通機器QPS都可以達到1000w/s。
使用
先建表,如果沒有請創建
CREATE TABLE `neo_uuid_generator` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
`namespace` varchar(128) DEFAULT '' COMMENT '命名空間',
`work_id` int(16) NOT NULL DEFAULT '0' COMMENT '工作id',
`last_expire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '下次失效時間',
`uid` varchar(128) DEFAULT '0' COMMENT '本次啓動唯一id',
`ip` bigint(20) NOT NULL DEFAULT '0' COMMENT 'ip',
`process_id` varchar(128) NOT NULL DEFAULT '0' COMMENT '進程id',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_name_work` (`namespace`,`work_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@Test
public void generateTest1() {
UuidGenerator generator = UuidGenerator.getInstance(neo);
// 註冊(聲明)命令空間(在業務空間對應的集羣,最多可以有8192臺機器跑同一個業務,對大部分業務來說,足夠了)
generator.addNamespaces("test1", "test2");
System.out.println(generator.getUUid("test1"));
}
多表join
@Test
public void testJoin1() {
// 首先獲取join的處理器,支持查詢one,list, value, values, page, count
NeoJoiner neoJoiner = neo.joiner();
// 配置的列
Columns columns = Columns.of(neo);
columns.table("neo_table1", "age");
// 配置所有列,可以爲columns.table("neo_table2", "*")
columns.table("neo_table2", "name", "group");
// 配置多表join
TableJoinOn tableJoinOn = new TableJoinOn("neo_table1");
tableJoinOn.leftJoin("neo_table1", "neo_table2").on("id", "n_id");
tableJoinOn.leftJoin("neo_table2", "neo_table3").on("n_id", "n_id");
// 配置查詢條件
TableMap searchMap = TableMap.of();
searchMap.put("neo_table1", "name", "nihao");
searchMap.put("neo_table2", "group", "ok");
// select
// neo_table1.`age` as neo_table1_dom_age,
// neo_table2.`group` as neo_table2_dom_group,
// neo_table2.`name` as neo_table2_dom_name
//
// from
// neo_table1 left join neo_table2 on neo_table1.`id`=neo_table2.`n_id`
// left join neo_table3 on neo_table2.`n_id`=neo_table3.`n_id`
//
// where neo_table2.`group` = ? and neo_table1.`name` = ?
// [ok, nihao]
show(neoJoiner.one(columns, tableJoinOn, searchMap));
}
異步
所有的api都有對應的異步api,列舉其中幾個接口api,接口太多,這裏不再列舉。其中線程池中的默認方式中,拒絕策略採用新的方式(重寫了拒絕策略),即:如果線程池全部都滿了,則任務阻塞在任務隊列中
CompletableFuture<NeoMap> insertAsync(String tableName, NeoMap dataMap, Executor executor);
CompletableFuture<NeoMap> insertAsync(String tableName, NeoMap dataMap);
<T> CompletableFuture<T> insertAsync(String tableName, T object, Executor executor);
<T> CompletableFuture<T> insertAsync(String tableName, T object);
CompletableFuture<Integer> deleteAsync(String tableName, NeoMap dataMap, Executor executor);
CompletableFuture<Integer> deleteAsync(String tableName, NeoMap dataMap);
<T> CompletableFuture<Integer> deleteAsync(String tableName, T object, Executor executor);
<T> CompletableFuture<Integer> deleteAsync(String tableName, T object);
CompletableFuture<Integer> deleteAsync(String tableName, Number id, Executor executor);
CompletableFuture<Integer> deleteAsync(String tableName, Number id);
CompletableFuture<NeoMap> updateAsync(String tableName, NeoMap dataMap, NeoMap searchMap, Executor executor);
CompletableFuture<NeoMap> updateAsync(String tableName, NeoMap dataMap, NeoMap searchMap);
<T> CompletableFuture<T> updateAsync(String tableName, T setEntity, NeoMap searchMap, Executor executor);
...
更多功能
- 數據庫連接
- 基本功能
- DB異步
- 結構信息
- 批量功能
- 命名轉換
- 事務
- 單機事務
- 分佈式XA事務(測試中)
- sql監控
- 主從
- join
- 實體代碼生成器
- 分佈式
- 全局id
- 動態分庫分表(待支持)
- 多數據源(待驗證)
技術討論羣:
請先加WX(zhoumo187108),並註明來源