脱离实体类操作数据库(mysql版本)
原理很简单:
1、利用mysql的information_schema库,获取对用表的信息;
2、使用DataSource,建立数据库连接,并执行sql脚本;
3、Map的keySet和values集合是顺序一致的;
4、" on duplicate key update "这里摸了个鱼,将新增和修改整合在一起了;
直接上代码:
package com.modern.client.core; import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import org.springframework.util.Assert; import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors; /**
* 数据库脱离实体操作助手
*/
public class MybatisHelper { /**
* 获取所有列
*
* @param ds
* @param tableName
* @return
*/
@SneakyThrows
private static List<String> tableColumns(DataSource ds, String tableName) {
Connection connection = ds.getConnection();
try {
ResultSet set = connection.prepareCall("select column_name from information_schema.`COLUMNS` where table_name = '" + tableName + "'").executeQuery();
ArrayList<String> list = Lists.newArrayList();
while (set.next()) {
list.add(set.getString(1));
}
return list;
} finally {
connection.close();
}
} /**
* 获取主键
*
* @param ds
* @param tableName
* @return
*/
@SneakyThrows
private static String tablePrimarykey(DataSource ds, String tableName) {
Connection connection = ds.getConnection();
try {
ResultSet set = connection.prepareCall("select column_name from information_schema.`COLUMNS` where table_name = '" + tableName + "' and COLUMN_key = 'PRI'").executeQuery();
Assert.isTrue(set.next(),"表"+tableName+"未找到主键!");
return set.getString(1);
} finally {
connection.close();
}
} @SneakyThrows
private static void callSql(DataSource ds, String sql) {
Connection connection = ds.getConnection();
try {
connection.prepareCall(sql).execute();
} finally {
connection.close();
}
} /**
* 删除
*
* @param ds
* @param tableName
* @param jsonStr
* @throws SQLException
*/
public static void delete(DataSource ds, String tableName, String jsonStr) throws SQLException {
String primarykey = tablePrimarykey(ds, tableName);
Assert.notNull(primarykey, "表" + tableName + "无主键,执行删除失败!");
String value = null;
JSONObject object = JSON.parseObject(jsonStr);
for (Map.Entry<String, Object> entry : object.entrySet()) {
if (entry.getKey().equalsIgnoreCase(primarykey.replaceAll("_", ""))) {
value = entry.getValue().toString();
break;
}
}
Assert.notNull(value, "表" + tableName + "无主键 值,执行删除失败!");
StringBuilder builder = new StringBuilder();
builder.append(" delete from ");
builder.append(tableName);
builder.append(" where ");
builder.append(primarykey);
builder.append(" = ");
builder.append("'");
builder.append(value);
builder.append("'");
callSql(ds, builder.toString());
} /**
* 新增或修改
*
* @param ds
* @param tableName
* @param jsonStr
*/
public static void insertOrUpdate(DataSource ds, String tableName, String jsonStr) {
List<String> columns = tableColumns(ds, tableName);
JSONObject object = JSON.parseObject(jsonStr);
MapBuilder<Object, Object> mapBuilder = MapUtil.builder();
for (Map.Entry<String, Object> entry : object.entrySet()) {
List<String> res = columns.stream().filter(p -> entry.getKey().equalsIgnoreCase(p.replaceAll("_", ""))).collect(Collectors.toList());
if (res.size() <= 0) continue;
mapBuilder.put(res.get(0), entry.getValue());
}
Map<Object, Object> map = mapBuilder.build();
StringBuilder builder = new StringBuilder();
//insert
builder.append(" insert into ");
builder.append(tableName);
builder.append(keyBunch(map.keySet()));
builder.append(" values ");
builder.append(valueBunch(map.values()));
//update
builder.append(updateBunch(map.keySet()));
callSql(ds, builder.toString());
} /**
* insertOrUpdate 分支
* @param c
* @return
*/
private static String keyBunch(Collection<?> c) {
StringBuilder builder = new StringBuilder("(");
Iterator<?> iterator = c.iterator();
while (iterator.hasNext()) {
builder.append(iterator.next());
if(iterator.hasNext()) builder.append(",");
}
builder.append(")");
return builder.toString();
} /**
* insertOrUpdate 分支
* @param c
* @return
*/
private static String valueBunch(Collection<?> c) {
StringBuilder builder = new StringBuilder("(");
Iterator<?> iterator = c.iterator();
while (iterator.hasNext()) {
builder.append("'");
builder.append(iterator.next().toString());
builder.append("'");
if(iterator.hasNext()) builder.append(",");
}
builder.append(")");
return builder.toString();
} /**
* insertOrUpdate 分支
* @param c
* @return
*/
private static String updateBunch(Collection<?> c) {
StringBuilder builder = new StringBuilder(" on duplicate key update ");
Iterator<?> iterator = c.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
builder.append(next);
builder.append(" =values( ");
builder.append(next);
builder.append(")");
if(iterator.hasNext()) builder.append(",");
}
return builder.toString();
}
public static void main(String[] args) {
Map<String, String> map = MapUtil.builder(new HashMap<String,String>())
.put("id", "1")
.put("organization_id", "9")
.put("c", "9")
.put("d", "9")
.put("x", "2024-01-01").build();
StringBuilder builder = new StringBuilder();
//insert
builder.append(" insert into ");
builder.append("aaaa");
builder.append(keyBunch(map.keySet()));
builder.append(" values ");
builder.append(valueBunch(map.values()));
//update
builder.append(updateBunch(map.keySet()));
System.out.println("args = " + builder.toString());
}
}
最后拼接效果:
INSERT INTO aaaa ( c, d, organization_id, x, id )
VALUES
( '9', '9', '9', '2024-01-01', '1' )
ON DUPLICATE KEY UPDATE c =
VALUES
( c ),
d =
VALUES
( d ),
organization_id =
VALUES
( organization_id ),
x =
VALUES
( x ),
id =
VALUES
(
id
)
脱离实体类操作数据库(mysql版本)的更多相关文章
- PDF.NET数据开发框架实体类操作实例
PDF.NET数据开发框架实体类操作实例(MySQL)的姊妹篇,两者使用了同一个测试程序,不同的只是使用的类库和数据库不同,下面说说具体的使用过程. 1,首先在App.config文件中配置数据库连接 ...
- 解决mybatis实体类和数据库列名不匹配的两种办法
我们在实际开发中,会遇到实体类与数据库类不匹配的情况,在开发中就会产生各种各样的错误,那么我们应该怎么去解决这一类的错误呢?很简单,下面我们介绍两种解决方法: 首先我们看一下数据库和实体类不匹配的情况 ...
- ASP.NET Core EFCore 之DBFirst 自动创建实体类和数据库上下文
通过引用Nuget包添加实体类 运行 Install-Package Microsoft.EntityFrameworkCore.SqlServer 运行 Install-Package Micros ...
- 在Code First中使用Migrations对实体类和数据库做出变更
在Code First中使用Migrations对实体类和数据库做出变更,Mirgration包含一系列命令. 工具--库程序包管理器--程序包管理器控制台 运行命令:Enable-Migration ...
- ef-codefirst方式配置实体类,生成数据库
做项目的时候,如果我们如果用orm方式来做数据库持久化操作的话.微软官方首先会向我们推荐ef,而我们用ado.net的话,似乎也需要建立实体类来接传值,那么我们用codefirst就有一举两得的效果了 ...
- php 通过mysqli 操作数据库mysql
目录 php mysqli 操作数据库 连接数据库 通过mysqli 创建数据库 通过mysqi 创建数据表 通过mysqli向数据表中插入信息 通过mysqli 读取数据 where语句的应用 通过 ...
- YbSoftwareFactory 代码生成插件【十九】:实体类配合数据库表字段进行属性扩展的小技巧
实体类通常需要和数据库表进行了ORM映射,当你需要添加新的属性时,往往同时也需要在数据库中添加相应的字段并配置好映射关系,同时可能还需对数据访问组件进行重新编译和部署才能有效.而当你开始设计一个通用数 ...
- 就这么 来ADO.net类操作数据库
使用ADO.net操作数据库其实也是很简单,而且使用频率蛮高的一种方式.话不多说,上代码才更容易理解. 首先,先要引入数据库操作相关的命名空间,这样才能使用下面的代码 //数据库连接引用的命名空间 u ...
- MyBatis入门实例-包括实体类与数据库字段对应&CLOB字段处理
1.我的开发环境是 jdk1.7+ecplise+oracle 11g 用到的jar包:mybatis-3.1.1.jar ojdbc6.jar 2.项目整体结构 3.首先配置conf.xml ...
- 6-2 python 操作数据库mysql
1.python操作MySQL的 查询(select操作) 步骤 import pymysql # 1.建立数据库连接 conn = pymysql.connect(host='118.24.3.40 ...
随机推荐
- isObject:判断数据是不是引用类型的数据 (例如: arrays, functions, objects, regexes, new Number(0),以及 new String(''))
function isObject(value) { let type = typeof value; return value != null && (type == 'object ...
- atcoder ABC237-E Skiing
atcoder ABC237-E Skiing 传送门 这题把一个点到另外一个点的开心值变为这条边的权值,就可以化为求最大路.因为有负边权,所以要用\(SPFA\),但\(SPFA\)这玄学的时间复杂 ...
- 成本立降50%!在EKS上借助Karpenter部署大模型
原文链接: https://aws.amazon.com/cn/blogs/containers/scaling-a-large-language-model-with-nvidia-nim-on-a ...
- The Bento Box Adventure
题目来源:codeforces 2041A 题目名称:The Bento Box Adventure 题目链接:https://codeforces.com/contest/2041/problem/ ...
- 【实战问题】-- 并发的时候分布式锁setnx细节
前面讲解到实战问题]-- 设计礼品领取的架构设计以及多次领取现象解决?,如果出现网络延迟的情况下,多个请求阻塞,那么恶意攻击就可以全部请求领取接口成功,而针对这种做法,我们使用setnx来解决,确保只 ...
- 【多线程】Java并发中的锁(草稿)
可重入锁Synchronized 1 public class DemoTest { 2 public static void main(String[] args) { 3 final DemoTe ...
- ThreeJs-05纹理材质高级操作
1.纹理操作 1.1 重复.旋转.位移.缩放 重复 但是要在水平方向上重复,还得允许 按照刚才的重复方式 如果设置为镜像重复 位移 旋转 1.2 翻转与alpha生成颜色 正常的图 不翻转默认是翻转的 ...
- 鸿蒙UI开发快速入门 —— part12: 渲染控制
1.前言 在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数据快速生成组件的循环渲染语句. 2.条件渲染 ...
- Flutter showModalBottomSheet改变高度
showModalBottomSheet改变高度 将isScrollControlled设置为true,此时弹窗会全屏展示,再返回一个带高度的SizedBox,就可以指定弹窗的高度了 showModa ...
- MyBatis-Plus乐观锁: Parameter ‘MP_OPTLOCK_VERSION_ORIGINAL‘ not found. Available parameters are [
新版本的 mybatisplus-plus 会出现这个问题,当我们根据官方文档使用乐观锁的相关代码时会出现这个问题:注意 OptimisticLockerInterceptor 不要写成 Optimi ...