jdbc-plus简介

jdbc-plus是一款基于JdbcTemplate增强工具包,

基于JdbcTemplate已实现分页、多租户、动态表名等插件,可自定义扩展插件,可与mybatis、mybatis-plus等混合使用。项目地址:https://github.com/deeround/jdbc-plus

特性

  • 使用简单,对代码入侵很小,可与mybatis、mybatis-plus等混合使用。
  • 可自定义任意扩展插件
  • 免费开源,可任意使用修改代码
  • 是对ORM框架的增强不做任何改变,当需要动态执行SQL不是很方面使用ORM框架执行SQL时,jdbc-plus就能发挥作用

插件(持续扩展中)

已内置以下插件,开箱即用,还可以自行扩展插件,扩展插件方法十分简单。

  • 分页插件:与PageHelper使用方法一致,还可以注册不支持的数据库
  • 多租户插件:与mybatis-plus多租户插件使用方法一致,理论上与mybatis-plus多租户插件支持度一样
  • 动态表名插件:与mybatis-plus动态表名插件使用方法一致
  • 更多插件:持续关注jdbc-plus仓库,仓库包含所有插件源代码以及使用示例

快速开始

  1. 引入jdbc-plus-spring-boot-starter
<dependency>
<groupId>com.github.deeround</groupId>
<artifactId>jdbc-plus-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
  1. 注入需要使用的插件(需要哪个注入哪个,不需要的注释掉即可)
@Configuration
public class JdbcPlusConfig { /**
* TenantLineInterceptor是内置的多租户插件
*/
@Bean
@Order(1)
public IInterceptor tenantLineInterceptor() {
return new TenantLineInterceptor(new TenantLineHandler() {
/**
* 当前租户ID
*/
@Override
public Expression getTenantId() {
String currentTenantId = "test_tenant_1";//可以从请求上下文中获取(cookie、session、header等)
return new StringValue(currentTenantId);
} /**
* 租户字段名
*/
@Override
public String getTenantIdColumn() {
return "tenant_id";
} /**
* 根据表名判断是否忽略拼接多租户条件
*/
@Override
public boolean ignoreTable(String tableName) {
return TenantLineHandler.super.ignoreTable(tableName);
}
});
} /**
* DynamicTableNameInterceptor是内置的动态表名插件
*/
@Bean
@Order(2)
public IInterceptor dynamicTableNameInterceptor() {
return new DynamicTableNameInterceptor(new TableNameHandler() {
@Override
public String dynamicTableName(String sql, String tableName) {
if ("test_log".equals(tableName)) {
return tableName + "_" + LocalDateTime.now().getYear();
}
return tableName;
}
});
} /**
* PaginationInterceptor是内置的分页插件(分页插件一般情况放置最后)
*/
@Bean
@Order(9)
public IInterceptor paginationInterceptor() {
return new PaginationInterceptor();
} /**
* 自定义插件注入,注入位置按实际情况
*/
@Bean
@Order(0)
public IInterceptor myStatInterceptor() {
return new MyStatInterceptor();
}
}
  1. 正常使用JdbcTemplate执行SQL语句,代码零入侵,使用体验超棒
    @Autowired
JdbcTemplate jdbcTemplate; public void insert() {
this.jdbcTemplate.update("insert into test_user(id,name) values('1','wangwu')");
//最终执行SQL:insert into test_user(id,name,tenant_id) values('1','wangwu','test_tenant_1')
} public void delete() {
this.jdbcTemplate.update("delete from test_user where id='1'");
//最终执行SQL:delete from test_user where id='1' and tenant_id='test_tenant_1'
} public void update() {
this.jdbcTemplate.update("update test_user set name='lisi' where id='1'");
//最终执行SQL:update test_user set name='lisi' where id='1' and tenant_id='test_tenant_1'
} public List<Map<String, Object>> query() {
return this.jdbcTemplate.queryForList("select * from test_user");
//最终执行SQL:select * from test_user where tenant_id='test_tenant_1'
} public PageInfo<Map<String, Object>> page1() {
PageHelper.startPage(1, 2);
List<Map<String, Object>> list = this.jdbcTemplate.queryForList("select * from test_user");
//最终执行SQL:select * from test_user LIMIT 0,2
PageInfo<Map<String, Object>> page = new PageInfo<>(list);
//PageInfo对象包含了分页信息(总行数等)
return page;
}

多租户插件

  1. 注入多租户插件
    /**
* TenantLineInterceptor是内置的多租户插件插件
*/
@Bean
@Order(1)
public IInterceptor tenantLineInterceptor() {
return new TenantLineInterceptor(new TenantLineHandler() {
/**
* 当前租户ID
*/
@Override
public Expression getTenantId() {
String currentTenantId = "test_tenant_1";//可以从请求上下文中获取(cookie、session、header等)
return new StringValue(currentTenantId);
} /**
* 租户字段名
*/
@Override
public String getTenantIdColumn() {
return "tenant_id";
} /**
* 根据表名判断是否忽略拼接多租户条件
*/
@Override
public boolean ignoreTable(String tableName) {
return TenantLineHandler.super.ignoreTable(tableName);
}
});
}
  1. service层执行SQL时自动添加租户字段
    public void insert() {
this.jdbcTemplate.update("insert into test_user(id,name) values('1','wangwu')");
//最终执行SQL:insert into test_user(id,name,tenant_id) values('1','wangwu','test_tenant_1')
} public void delete() {
this.jdbcTemplate.update("delete from test_user");
//最终执行SQL:delete from test_user where tenant_id='test_tenant_1'
} public void update() {
this.jdbcTemplate.update("update test_user set name='lisi' where id='1'");
//最终执行SQL:update test_user set name='lisi' where id='1' and tenant_id='test_tenant_1'
} public List<Map<String, Object>> query() {
return this.jdbcTemplate.queryForList("select * from test_user");
//最终执行SQL:select * from test_user where tenant_id='test_tenant_1'
}

分页插件

  1. 注入分页插件
    /**
* PaginationInterceptor是内置的分页插件(分页插件一般情况放置最后)
*/
@Bean
@Order(9)
public IInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
  1. service层执行SQL时自动对SQL进行分页查询
    public PageInfo<Map<String, Object>> page1() {
PageHelper.startPage(1, 2);
List<Map<String, Object>> list = this.jdbcTemplate.queryForList("select * from test_user");
//最终执行SQL:select * from test_user LIMIT 0,2
PageInfo<Map<String, Object>> page = new PageInfo<>(list);
//PageInfo对象包含了分页信息(总行数等)
return page;
} public PageInfo<Map<String, Object>> page2() {
PageHelper.startPage(2, 2);
List<Map<String, Object>> list = this.jdbcTemplate.queryForList("select * from test_user");
//最终执行SQL:select * from test_user LIMIT 2,2
PageInfo<Map<String, Object>> page = new PageInfo<>(list);
//PageInfo对象包含了分页信息(总行数等)
return page;
}
  1. 自定义分页

当插件不支持的数据库分页,可以通过PageHelper.registerDialectAlias(String alias, Class clazz) 注册一个自己分页实现类即可,也可以覆盖已支持的数据库分页。

动态表名插件

  1. 注入分页插件
    /**
* DynamicTableNameInterceptor是内置的动态表名插件
*/
@Bean
@Order(2)
public IInterceptor dynamicTableNameInterceptor() {
return new DynamicTableNameInterceptor(new TableNameHandler() {
@Override
public String dynamicTableName(String sql, String tableName) {
if ("test_log".equals(tableName)) {
return tableName + "_" + LocalDateTime.now().getYear();
}
return tableName;
}
});
}
  1. service层执行SQL时自动对SQL进行分页查询
    public List<Map<String, Object>> getTestLogList() {
return this.jdbcTemplate.queryForList("select * from test_log");
//最终执行SQL:select * from test_log_2023
}

自定义插件

示例:写一个打印SQL语句、执行参数、以及执行SQL耗时的监控插件。

  1. 编写MyStatInterceptor插件
/**
* SQL监控插件
*/
@Slf4j
public class MyStatInterceptor implements IInterceptor {
/**
* 自定义插件是否支持
*/
@Override
public boolean supportMethod(final MethodInvocationInfo methodInfo) {
return IInterceptor.super.supportMethod(methodInfo);
} /**
* SQL执行前方法(主要用于对SQL进行修改)
*/
@Override
public void beforePrepare(final MethodInvocationInfo methodInfo, JdbcTemplate jdbcTemplate) {
log.info("执行SQL开始时间:{}", LocalDateTime.now());
log.info("原始SQL:{}", Arrays.toString(methodInfo.getBatchSql()));
log.info("调用方法名称:{}", methodInfo.getName());
log.info("调用方法入参:{}", Arrays.toString(methodInfo.getArgs())); methodInfo.putUserAttribute("startTime", LocalDateTime.now());
} /**
* SQL执行完成后方法(主要用于对返回值修改)
*
* @param result 原始返回对象
* @return 处理后的返回对象
*/
@Override
public Object beforeFinish(Object result, final MethodInvocationInfo methodInfo, JdbcTemplate jdbcTemplate) {
log.info("执行SQL结束时间:{}", LocalDateTime.now());
LocalDateTime startTime = (LocalDateTime) methodInfo.getUserAttribute("startTime");
log.info("执行SQL耗时:{}毫秒", Duration.between(startTime, LocalDateTime.now()).toMillis());
return result;
}
}
  1. 注入自定义插件
    /**
* 自定义插件注入,注入位置按实际情况
*/
@Bean
@Order(0)
public IInterceptor myStatInterceptor() {
return new MyStatInterceptor();
}
  1. 查看效果(查看打印日志)
c.g.d.j.p.s.config.MyStatInterceptor     : 原始SQL:select * from test_user
c.g.d.j.p.s.config.MyStatInterceptor : 入参:[select * from test_user]
c.g.d.j.p.s.config.MyStatInterceptor : 执行SQL开始时间:2023-04-23T16:35:58.151
c.g.d.j.p.s.config.MyStatInterceptor : 执行SQL结束时间:2023-04-23T16:35:58.655
c.g.d.j.p.s.config.MyStatInterceptor : 执行SQL耗时:503毫秒

★ 鸣谢 ★

欢迎各路好汉一起来参与完善 jdbc-plus,感兴趣的可以在github点个 ,有任何问题和建议欢迎提交 Issue !

https://github.com/baomidou/mybatis-plus

https://github.com/pagehelper/Mybatis-PageHelper

https://github.com/deeround/jdbc-plus

🚀 jdbc-plus是一款基于JdbcTemplate增强工具包, 已实现分页、多租户、动态表名等插件,可与mybatis、mybatis-plus等混合使用的更多相关文章

  1. jdbc-plus是一款基于JdbcTemplate增强工具包, 基于JdbcTemplate已实现分页、多租户等插件,可自定义扩展插件

    jdbc-plus简介 jdbc-plus是一款基于JdbcTemplate增强工具包, 基于JdbcTemplate已实现分页.多租户等插件,可自定义扩展插件.项目地址: https://githu ...

  2. nakadi 一款基于kafka 的http event broker

    nakadi 是zalando 开源的一款基于kafka 的event broker ,我们可以方便的使用http 协议进行操作 支持一些特性: stream 操作,我们可以流的方式订阅event e ...

  3. PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品,产品设计严格遵循国际数据挖掘标准CRISP-DM(跨行业数据挖掘过程标准),具备完备的数据准备、模型构建、模型评估、模型管理、海量数据处理和高纬数据可视化分析能力。

    http://www.meritdata.com.cn/article/90 PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品, ...

  4. QQ 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件

    QQ 编辑 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件.腾讯QQ支持在线聊天.视频通话.点对点断点续传文件.共享文件.网络硬盘.自定义面板.QQ邮箱等多种功 ...

  5. Processon 一款基于HTML5的在线作图工具

    CSDN的蒋涛不久前在微博上评价说ProcessOn是web版的visio,出于好奇私下对ProcessOn进行了一番研究.最后发现无论是在用户体验上,还是在技术上,ProcessOn都比微软的Vis ...

  6. 一款基于jQuery轮播切换焦点图,可播放多张图片

    今天给大家分享一款基于jQuery轮播切换焦点图,可播放多张图片,在这个组件中,你可以任意指定8张图片,然后插件就会帮你自动生成缩略图,并且自动开始切换播放图片.当然,你也可以手动切换图片,只要点击缩 ...

  7. 9款基于CSS3 Transitions实现的鼠标经过图标悬停特效

    之前给大家分享了很多css3实现的按钮特效.今天给大家分享9款基于CSS3 Transitions实现的鼠标经过图标悬停特效.这款特效适用浏览器:360.FireFox.Chrome.Safari.O ...

  8. 一款基于css3的3D图片翻页切换特效

    今天给大家分享一款基于css3的3D图片翻页切换特效.单击图片下方的滑块会切换上方的图片.动起你的鼠标试试吧,效果图如下: 在线预览   源码下载 实现的代码. html代码: <div id= ...

  9. 一款基于jquery的下拉点击改变背景图片

    今天给大家介绍一款基于jquery的下拉点击改变背景图片.单击右上角的图片,下拉显示可选择的背景图片,单击图片变为背景图.效果图下: 在线预览   源码下载 实现的代码. html代码: <a ...

  10. 一款基于jQuery饼状图比例分布数据报表

    今天给大家带来一款基于jQuery饼状图比例分布数据报表.这款报表插件适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗.效果图如下: 在线预览  ...

随机推荐

  1. Hash中的bucket什么意思?

    这个好理解.无序容器的内部是由一个个的bucket(桶)构成的,每个bucket里面由相同hash的元素构成. 因此无序容器的搜索是先根据hash值,定位到bucket,然后再在bucket里面搜索符 ...

  2. spring事务不生效8种原因

    1.数据库引擎不支持事务 这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB. 根据 MySQL 的官方文档: ...

  3. 什么是5G垂直行业?

    什么是垂直行业呢? 感觉"垂直行业"这个词在太多地方遇到,但是这个词的涵盖范围到底是什么呢? 垂直这一概念源于两条直线(或平面)的直角交叉,两条直线是相互作为参照物的.比如,我们可 ...

  4. adb 全局

    win10: 我的电脑-右键属性--系统保护--高级--环境变量--选择path--编辑--点击新建 在新建条目下输入 C:\Users\GL\platform-tool--重新打开cmd 测试adb ...

  5. vs2010 Windows程序打包成安装包方法

    1.  在vs2010 选择"新建项目"--"其他项目类型"--"Visual Studio Installerà"安装项目": ...

  6. node使用multer进行文件上传

    开场白 在平时的业务中,我们很多使用都会有文件上传这个功能. 今天分享一下使用 node+element-ui实现一下文件上传. 请个人大佬指点一番~~~.批评的时候稍微轻一点. 毕竟我心里承受能力弱 ...

  7. idea 调试小心得

    1.为什么需要Debug 目的:开发过程中 查找或定位错误或者阅读源码 程序运行的结果(4种情况) 情况1:没有任何bug,程序执行正确! 情况2: 运行以后,出现了错误或异常信息.但是通过 日志文件 ...

  8. Python学习笔记--循环的知识以及应用

    while循环 代码: 结果: 案例:求1-100的和 实现: 案例:while循环猜数字 实现: while循环的嵌套使用 案例:打印九九乘法表 (注意:要是想要输出不换行,代码可以这样写:prin ...

  9. 一个.Net Core开源缓存中间件,让你更加简单、方便使用缓存

    上次给大家推荐过一个缓存中间件<一个C#开发的非常实用的缓存中间件>,今天再给大家推荐一个缓存中间件,两者功能差不多,都是提供统一接口.多级缓存.分布式缓存.支持多种Provider等. ...

  10. Windows7系统显存只有4GB

    Windows7安装后,专用视屏内存只有4GB可用,是不是Windows7不支持4G以上显存的显卡呢?之前在网上有人说,虽然系统显示可用只有4G显存,但是游戏内实际可以超过4G.本人没有特地去试验过. ...