Neo是一个基于JDBC开发的至简化框架,名字源于《黑客帝国》男主角名字,寓意为连接虚拟与现实。开发源头,源于之前接触的一些ORM框架,思想很不错但是没开源无法使用,而且自己也有很多想法因此设计了该框架。
Neo文档介绍
最新Neo文档介绍
该框架秉承大道至简理念,采用一个Neo对象对应一个DataSource方式,然后这个Neo对象拥有对表的各种操作。
当前已经发布到maven中央仓库,直接使用即可,目前最低版本0.3.0,不同版本的api差距不小,建议使用最新版本。目前版本还未脱离实验阶段,如果有什么问题请及时反馈
<dependency>
<groupId>com.github.simonalonggroupId>
<artifactId>NeoartifactId>
<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中字段的映射,可以有三种方式进行配置
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生成器方案,采用的是改进版雪花算法,彻底解决了雪花算法存在的常见问题(时间回拨问题,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"));
}
@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);
...
技术讨论群:
请先加WX(zhoumo187108),并注明来源