This release fixes a few bugs
- Fix SQLReady page turning bug fix
- bug that upsertByTemplate should return false instead of int
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetlsql</artifactId>
<version>3.0.6-RELEASE</version>
</dependency>
The goal of BeetlSQL is to provide a database access framework that is efficient in development, efficient in maintenance, and efficient in operation, and provides a consistent way of writing code in the case of multiple libraries in a system. Support the following data platforms
- Traditional database: MySQL, MariaDB, Oralce, Postgres, DB2, SQL Server, H2, SQLite, Derby, Magic Power, Dream, Huawei Goss, Renda Jincang, PolarDB, etc.
- Big data: HBase, ClickHouse, Cassandar, Hive
- IoT time series database: Machbase, TD-Engine, IotDB
- SQL query engine: Drill, Presto, Druid
- In-memory database: ignite, CouchBase
Read the documentation source code and examples
BeetlSQL3 performance test
The test dimension is ops/ms, the number of calls per millisecond
Benchmark Mode Cnt Score Error Units
JMHMain.beetlsqlComplexMapping thrpt 5 212.378 ± 26.222 ops/ms
JMHMain.beetlsqlExecuteJdbc thrpt 5 428.713 ± 66.192 ops/ms
JMHMain.beetlsqlExecuteTemplate thrpt 5 374.943 ± 20.214 ops/ms
JMHMain.beetlsqlFile thrpt 5 433.001 ± 65.448 ops/ms
JMHMain.beetlsqlInsert thrpt 5 236.244 ± 112.102 ops/ms
JMHMain.beetlsqlLambdaQuery thrpt 5 247.289 ± 19.310 ops/ms
JMHMain.beetlsqlOne2Many thrpt 5 108.132 ± 10.934 ops/ms
JMHMain.beetlsqlPageQuery thrpt 5 203.751 ± 9.395 ops/ms
JMHMain.beetlsqlSelectById thrpt 5 393.437 ± 15.685 ops/ms
JMHMain.jdbcExecuteJdbc thrpt 5 1083.310 ± 80.947 ops/ms
JMHMain.jdbcInsert thrpt 5 308.341 ± 231.163 ops/ms
JMHMain.jdbcSelectById thrpt 5 1019.370 ± 92.946 ops/ms
JMHMain.jpaExecuteJdbc thrpt 5 94.600 ± 15.624 ops/ms
JMHMain.jpaExecuteTemplate thrpt 5 133.017 ± 12.954 ops/ms
JMHMain.jpaInsert thrpt 5 81.232 ± 26.971 ops/ms
JMHMain.jpaOne2Many thrpt 5 101.506 ± 11.301 ops/ms
JMHMain.jpaPageQuery thrpt 5 117.748 ± 4.512 ops/ms
JMHMain.jpaSelectById thrpt 5 335.945 ± 27.186 ops/ms
JMHMain.mybatisComplexMapping thrpt 5 102.402 ± 11.129 ops/ms
JMHMain.mybatisExecuteTemplate thrpt 5 202.619 ± 16.978 ops/ms
JMHMain.mybatisFile thrpt 5 151.151 ± 4.251 ops/ms
JMHMain.mybatisInsert thrpt 5 141.469 ± 43.092 ops/ms
JMHMain.mybatisLambdaQuery thrpt 5 15.558 ± 1.481 ops/ms
JMHMain.mybatisPageQuery thrpt 5 63.705 ± 7.592 ops/ms
JMHMain.mybatisSelectById thrpt 5 197.130 ± 19.461 ops/ms
JMHMain.weedExecuteJdbc thrpt 5 416.941 ± 22.256 ops/ms
JMHMain.weedExecuteTemplate thrpt 5 439.266 ± 57.130 ops/ms
JMHMain.weedFile thrpt 5 477.561 ± 37.926 ops/ms
JMHMain.weedInsert thrpt 5 231.444 ± 92.598 ops/ms
JMHMain.weedLambdaQuery thrpt 5 422.707 ± 64.716 ops/ms
JMHMain.weedPageQuery thrpt 5 246.018 ± 18.724 ops/ms
JMHMain.weedSelectById thrpt 5 380.348 ± 20.968 ops/ms
Code example
Example 1, built-in method, no need to write SQL to complete common operations
UserEntity user = sqlManager.unique(UserEntity.class,1);
user.setName("ok123");
sqlManager.updateById(user);
UserEntity newUser = new UserEntity();
newUser.setName("newUser");
newUser.setDepartmentId(1);
sqlManager.insert(newUser);
The output log is friendly, and the called code can be located backward
┏━━━━━ Debug [user.selectUserAndDepartment] ━━━
┣ SQL: select * from user where 1 = 1 and id=?
┣ 参数: [1]
┣ 位置: org.beetl.sql.test.QuickTest.main(QuickTest.java:47)
┣ 时间: 23ms
┣ 结果: [1]
┗━━━━━ Debug [user.selectUserAndDepartment] ━━━
Example 2 Using SQL
String sql = "select * from user where id=?";
Integer id = 1;
SQLReady sqlReady = new SQLReady(sql,new Object[id]);
List<UserEntity> userEntities = sqlManager.execute(sqlReady,UserEntity.class);
//Map 也可以作为输入输出参数
List<Map> listMap = sqlManager.execute(sqlReady,Map.class);
Example 3 Using template SQL
String sql = "select * from user where department_id=#{id} and name=#{name}";
UserEntity paras = new UserEntity();
paras.setDepartmentId(1);
paras.setName("lijz");
List<UserEntity> list = sqlManager.execute(sql,UserEntity.class,paras);
String sql = "select * from user where id in ( #{join(ids)} )";
List list = Arrays.asList(1,2,3,4,5); Map paras = new HashMap();
paras.put("ids", list);
List<UserEntity> users = sqlManager.execute(sql, UserEntity.class, paras);
Example 4 Using the Query class
Support refactoring
LambdaQuery<UserEntity> query = sqlManager.lambdaQuery(UserEntity.class);
List<UserEntity> entities = query.andEq(UserEntity::getDepartmentId,1)
.andIsNotNull(UserEntity::getName).select();
Example 5 Put dozens of lines of SQL into sql file for maintenance
//访问user.md#select
SqlId id = SqlId.of("user","select");
Map map = new HashMap();
map.put("name","n");
List<UserEntity> list = sqlManager.select(id,UserEntity.class,map);
Example 6 Complex mapping support
Supports complex mapping like mybatis
- Automatic mapping
@Data
@ResultProvider(AutoJsonMapper.class)
public static class MyUserView {
Integer id;
String name;
DepartmentEntity dept;
}
- Configuration mapping, easier to understand than MyBatis, more detailed error information
{
"id": "id",
"name": "name",
"dept": {
"id": "dept_id",
"name": "dept_name"
},
"roles": {
"id": "r_id",
"name": "r_name"
}
}
Example 7 It is best to use mapper as a database access class
@SqlResource("user") /*sql文件在user.md里*/
public interface UserMapper extends BaseMapper<UserEntity> {
@Sql("select * from user where id = ?")
UserEntity queryUserById(Integer id);
@Sql("update user set name=? where id = ?")
@Update
int updateName(String name,Integer id);
@Template("select * from user where id = #{id}")
UserEntity getUserById(Integer id);
@SpringData/*Spring Data风格*/
List<UserEntity> queryByNameOrderById(String name);
/**
* 可以定义一个default接口
* @return
*/
default List<DepartmentEntity> findAllDepartment(){
Map paras = new HashMap();
paras.put("exlcudeId",1);
List<DepartmentEntity> list = getSQLManager().execute("select * from department where id != #{exlcudeId}",DepartmentEntity.class,paras);
return list;
}
/**
* 调用sql文件user.md#select,方法名即markdown片段名字
* @param name
* @return
*/
List<UserEntity> select(String name);
/**
* 翻页查询,调用user.md#pageQuery
* @param deptId
* @param pageRequest
* @return
*/
PageResult<UserEntity> pageQuery(Integer deptId, PageRequest pageRequest);
@SqlProvider(provider= S01MapperSelectSample.SelectUserProvider.class)
List<UserEntity> queryUserByCondition(String name);
@SqlTemplateProvider(provider= S01MapperSelectSample.SelectUs
List<UserEntity> queryUserByTemplateCondition(String name);
@Matcher /*自己定义个Matcher注解也很容易*/
List<UserEntity> query(Condition condition,String name);
}
The annotations you see on Mapper can be customized and extended by yourself
Example 8 Using Fetch annotation
You can get related objects again according to the Fetch annotations after querying. In fact, @FetchOne and @FetchMany are customized and users can extend them by themselves
@Data
@Table(name="user")
@Fetch
public static class UserData {
@Auto
private Integer id;
private String name;
private Integer departmentId;
@FetchOne("departmentId")
private DepartmentData dept;
}
/**
* 部门数据使用"b" sqlmanager
*/
@Data
@Table(name="department")
@Fetch
public static class DepartmentData {
@Auto
private Integer id;
private String name;
@FetchMany("departmentId")
private List<UserData> users;
}
Example 9 Switching between different databases
You can extend the decide method of ConditionalSQLManager to decide which SQLManager to use
SQLManager a = SampleHelper.init();
SQLManager b = SampleHelper.init();
Map<String, SQLManager> map = new HashMap<>();
map.put("a", a);
map.put("b", b);
SQLManager sqlManager = new ConditionalSQLManager(a, map);
//不同对象,用不同sqlManager操作,存入不同的数据库
UserData user = new UserData();
user.setName("hello");
user.setDepartmentId(2);
sqlManager.insert(user);
DepartmentData dept = new DepartmentData();
dept.setName("dept");
sqlManager.insert(dept);
Use the annotation @TargetSQLManager to decide which SQLManger to use
@Data
@Table(name = "department")
@TargetSQLManager("b")
public static class DepartmentData {
@Auto
private Integer id;
private String name;
}
Example 10 If you want to add a sqlId identifier to each sql statement
This benefit is to facilitate communication between the database DBA and the programmer
public static class SqlIdAppendInterceptor implements Interceptor{
@Override
public void before(InterceptorContext ctx) {
ExecuteContext context = ctx.getExecuteContext();
String jdbcSql = context.sqlResult.jdbcSql;
String info = context.sqlId.toString();
//为发送到数据库的sql增加一个注释说明,方便数据库dba能与开发人员沟通
jdbcSql = "/*"+info+"*/\n"+jdbcSql;
context.sqlResult.jdbcSql = jdbcSql;
}
}
Example 11 Code generation framework
You can use the built-in code generation framework to generate code and documentation, or you can customize it. Users can extend the SourceBuilder class by themselves
List<SourceBuilder> sourceBuilder = new ArrayList<>();
SourceBuilder entityBuilder = new EntitySourceBuilder();
SourceBuilder mapperBuilder = new MapperSourceBuilder();
SourceBuilder mdBuilder = new MDSourceBuilder();
//数据库markdown文档
SourceBuilder docBuilder = new MDDocBuilder();
sourceBuilder.add(entityBuilder);
sourceBuilder.add(mapperBuilder);
sourceBuilder.add(mdBuilder);
sourceBuilder.add(docBuilder);
SourceConfig config = new SourceConfig(sqlManager,sourceBuilder);
//只输出到控制台
ConsoleOnlyProject project = new ConsoleOnlyProject();
String tableName = "USER";
config.gen(tableName,project);
Example 13 Define a Beetl function
GroupTemplate groupTemplate = groupTemplate();
groupTemplate.registerFunction("nextDay",new NextDayFunction());
Map map = new HashMap();
map.put("date",new Date());
String sql = "select * from user where create_time is not null and create_time<#{nextDay(date)}";
List<UserEntity> count = sqlManager.execute(sql,UserEntity.class,map);
The nextDay function is a Beetl function, very easy to define, very easy to use in the SQL template statement
public static class NextDayFunction implements Function {
@Override
public Object call(Object[] paras, Context ctx) {
Date date = (Date) paras[0];
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DAY_OF_YEAR, 1); // 今天+1天
return c.getTime();
}
}
Example 14 More extensible examples
Automatically divide tables according to ID or context, toTable is a Beetl function defined,
static final String USER_TABLE="${toTable('user',id)}";
@Data
@Table(name = USER_TABLE)
public static class MyUser {
@AssignID
private Integer id;
private String name;
}
Define a Jackson annotation, @Builder is the annotation of the annotation, which means that the class indicated by the Builder is used to explain the execution. You can see that the extensibility of BeetlSQL's annotations is derived from the @Build annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.FIELD})
@Builder(JacksonConvert.class)
public @interface Jackson {
}
Define a @Tenant and place it on the POJO. When BeetlSQL is executed, additional parameters will be added to the SQL. The @Build annotation is also used here.
/**
* 组合注解,给相关操作添加额外的租户信息,从而实现根据租户分表或者分库
*/
@Retention(RetentionPolicy.RUNTIM@
@Target(value = {ElementType.TYPE})
@Builder(TenantContext.class)
public @interface Tenant {
}
Use XML instead of JSON as the mapping
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Builder(ProviderConfig.class)
public @interface XmlMapping {
String path() default "";
}
Refer to the source code example PluginAnnotationSample to learn how to define custom annotations. In fact, half of BeetlSQL's annotations are extended through core annotations
BeetlSQL architecture
Except SQLManager and ClassAnnoations, any part can be extended