Mysql - Upsert功能实现

 

 

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

Mysql - Upsert功能实现_第1张图片

实现操作

参考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'

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 = 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

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

你可能感兴趣的:(mysql)