Mysql - Upsert功能实现


在看到了mongoTemplate的操作之后,觉得这种东西是很符合我们程序员世界的操作的,但是看到mysql的jdbc之后,瞬间一百万个小泥马从头飘过,所以就想自己实现一个mysql版本的upsert功能,有setincrease,decrease
Mysql - Upsert功能实现
文章图片

实现操作 参考mongoTemplate,创建一个update.javaquery.java类,方便两款db之间转换
import java.util.HashMap; import java.util.Map; public class Update {private Map sets = new HashMap<>(); private Map incs = new HashMap<>(); //省略get set操作 }public class Query {private Map values = new HashMap<>(); public Query equals(String name,Object value){ values.put(name,value); return this; }//省略get set操作 }

只依赖一个包
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.39'

【Mysql - Upsert功能实现】MysqlClient 客户端工具
代码非常精简,大家可以根据自己的喜好添加功能
import java.sql.*; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; public class MysqlClient {private Connection connection; private String jdbcUrl; private String driver = "com.mysql.jdbc.Driver"; public MysqlClient(String jdbcUrl) { this.jdbcUrl = jdbcUrl; this.init(); }public void init() { try { if (connection == null || connection.isClosed()) { String[] split = jdbcUrl.split("\\|"); Class.forName(driver); connection = DriverManager.getConnection(split[0], split[1], split[2]); } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }public void upsert(String table, Query query, Update update) { List names = new ArrayList<>(); List params = new ArrayList<>(); names.addAll(query.getValues().keySet().stream().map(item -> String.format("`%s`", item)).collect(Collectors.toList())); names.addAll(update.getSets().keySet().stream().map(item -> String.format("`%s`", item)).collect(Collectors.toList())); names.addAll(update.getIncs().keySet().stream().map(item -> String.format("`%s`", item)).collect(Collectors.toList())); List values = new ArrayList<>(); values.addAll(query.getValues().values().stream().map(item -> " ? ").collect(Collectors.toList())); params.addAll(query.getValues().values()); values.addAll(update.getSets().values().stream().map(item -> " ? ").collect(Collectors.toList())); params.addAll(update.getSets().values()); values.addAll(update.getIncs().values().stream().map(item -> " ? ").collect(Collectors.toList())); params.addAll(update.getIncs().values()); List updates = new ArrayList<>(); update.getSets().forEach((key, value) -> { updates.add(String.format(" `%s` = ? ", key)); params.add(value); }); update.getIncs().forEach((key, value) -> { updates.add(String.format(" `%s` = `%s` + %s", key, key, value)); }); String sql = String.format("INSERT INTO `%s` (%s) VALUES(%s) ON DUPLICATE KEY UPDATE %s", table, String.join(",", names), String.join(",", values), String.join(",", updates) ); this.execute(sql, params.toArray()); }private void fillStatement(PreparedStatement statement, Object... params) throws SQLException { for (int i = 1, len = params.length; i <= len; i++) { Object value = https://www.it610.com/article/params[i - 1]; if (value instanceof String) { statement.setString(i, value.toString()); } else if (value instanceof Integer) { statement.setInt(i, Integer.parseInt(value.toString())); } else if (value instanceof Boolean) { statement.setBoolean(i, Boolean.parseBoolean(value.toString())); } else if (value instanceof LocalDate || value instanceof LocalDateTime) { statement.setString(i, value.toString()); } else if (value instanceof Long) { statement.setLong(i, Long.parseLong(value.toString())); } else if (value instanceof Double) { statement.setDouble(i, Double.parseDouble(value.toString())); } else if (value instanceof Float) { statement.setDouble(i, Float.parseFloat(value.toString())); } else { statement.setString(i, value.toString()); } } }public void execute(String sql, Object... params) { try { PreparedStatement statement = connection.prepareStatement(sql); this.fillStatement(statement, params); statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } } }
使用方法
@Test public void testUpsert(){ MysqlClient mysqlClient = new MysqlClient("jdbc:mysql://demo.com:3306/db?useUnicode=true&useSSL=false&autoReconnect=true|root|password"); Update update = new Update(); update.set("count", 0); update.inc("active", 1); Query query = new Query(); query.equals("name", "abc"); mysqlClient.upsert("test", query, update); //含义:对相同行的`name`='abc',对其字段`count`重置为0,`active`新增1 }

解析 生成的sql语句会像这样子
INSERT INTO `test` (`name`,`count`,`active`,`value`) VALUES( ? , ? , ? , ? ) ON DUPLICATE KEY UPDATE`count` = ? , `active` = `active` + 1, `value` = `value` - 1

并且使用了占位符号,增加特殊符号的解析容错能力

    推荐阅读