Mysql 实现upsert已有更新操作

1 篇文章 0 订阅

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

实现操作

参考mongoTemplate,创建一个update.java类,方便两款db之间转换

import java.util.HashMap;
import java.util.Map;

public class Update {

    private Map<String, Object> sets = new HashMap<>();
    private Map<String, Object> increases = new HashMap<>();
    private Map<String, Object> decreases = new HashMap<>();

    //省略get set操作
}

只依赖一个包

compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.39'

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, Map<String, Object> query, Update update) {
        List<String> names = new ArrayList<>();
        List<Object> params = new ArrayList<>();

        names.addAll(query.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.getIncreases().keySet().stream().map(item -> String.format("`%s`", item)).collect(Collectors.toList()));
        names.addAll(update.getDecreases().keySet().stream().map(item -> String.format("`%s`", item)).collect(Collectors.toList()));

        List<String> values = new ArrayList<>();
        values.addAll(query.values().stream().map(item -> " ? ").collect(Collectors.toList()));
        params.addAll(query.values());

        values.addAll(update.getSets().values().stream().map(item -> " ? ").collect(Collectors.toList()));
        params.addAll(update.getSets().values());

        values.addAll(update.getIncreases().values().stream().map(item -> " ? ").collect(Collectors.toList()));
        params.addAll(update.getIncreases().values());

        values.addAll(update.getDecreases().values().stream().map(item -> " ? ").collect(Collectors.toList()));
        params.addAll(update.getDecreases().values());

        List<String> updates = new ArrayList<>();
        update.getSets().forEach((key, value) -> {
            updates.add(String.format(" `%s` = ? ", key));
            params.add(value);
        });
        update.getIncreases().forEach((key, value) -> {
            updates.add(String.format(" `%s` = `%s` + %s", key, key, value));
        });
        update.getDecreases().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 = 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.increase("active", 1);
        update.decrease("value", 1);
        mysqlClient.upsert("test", new HashMap<String, Object>() {
            {
                put("name", "'abc'");
            }
        }, 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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值