java同步mysql数据

java同步mysql数据

同步表数据和修改java程序的过程,将这些记录下来:

  • 业务说明
  • 解决方案
  • 表信息
  • 同步程序
  • 遇到的问题

业务说明

由于业务变更,系统内涉及到使用aid的程序都要求替换为bid,一共涉及多张表的数据需要清洗,下面以其中一张表rule来讲述。

解决方案

1.创建相同表结构rules
2.同步表rule到表rules
3.将应用程序中使用表rule替换为表rules

表信息

rule 表结构如下:

字段说明
id主键,自动增长列
rule_id规则编号
create_id创建人Id
create_time创建时间
update_id更新人Id
update_time更新时间

rule_id字段存的值需要替换,有aid替换为bid,具体数据如下:

aidbid
201409C2000000003KS1201506CG230000049
201311CM010000171KS1201506CG230000050

创建表rules
为了不影响线上环境,创建了表rules,结构同表rule,好处在于清理数据时不影响线上正常业务数据。

rules 表结构如下:

字段说明
id主键,自动增长列
rule_id规则编号
create_id创建人Id
create_time创建时间
update_id更新人Id
update_time更新时间

同步程序

业务逻辑如下:
* 1.同步数据,一次读取表rule的1000条记录,且替换aid为bid,写入表rules
* 2.判断新增or更新
* 3.如果rule.id在rules表不存在,则insert
* 4.如果rule.id在rules表存在,且rules.update_time<>rules.update_time,则update

程序如下:

public void synchronizeCouponRulesDddc(){
        logger.info("synchronizeCouponRulesDddc---开始");
        Map<String, Object> param = new HashMap<String, Object>();
        Map<String, Object> param2 = new HashMap<String, Object>();
        int total = couponOldForNewMapper.synchronizeCouponRulesCount();
        if (total > 0) {
            int startIndex = 0, batchSize = 1000;
            while (startIndex < total) {
                param.put("startIndex", startIndex);
                param.put("batchSize", batchSize);
                List<com.feiniu.coupon.entity.newCoupon.CouponRule> couponRulesList = couponOldForNewMapper.synchronizeCouponRules(param);
                Set<Integer> idsSet = new HashSet<Integer>();
                //插入数据导关联表
                if (CollectionUtils.isNotEmpty(couponRulesList)) {
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule couponRules : couponRulesList) {
                        String type = couponRules.getType();
                        if ("3".equals(type) || "4".equals(type) || "12".equals(type) || "13".equals(type)) {
                            String typeSeq = couponRules.getTypeSeq();
                            couponRules.setTypeSeq(this.replaceSmId(typeSeq));
                        }
                        idsSet.add(couponRules.getId());
                    }
                }
                String idsStr ="'"+ StringUtils.join(idsSet, "','") +"'";
                param2.put("ids", idsStr);
                List<com.feiniu.coupon.entity.newCoupon.CouponRule> couponRulesDddcList = couponOldForNewMapper.synchronizeCouponRulesDddc(param2);

                List<com.feiniu.coupon.entity.newCoupon.CouponRule> updateList = new ArrayList<com.feiniu.coupon.entity.newCoupon.CouponRule>();
                if (CollectionUtils.isNotEmpty(couponRulesDddcList)) {
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule couponRules : couponRulesList) {
                        for (com.feiniu.coupon.entity.newCoupon.CouponRule couponRulesDddc : couponRulesDddcList) {
                            if (couponRules.getId().equals(couponRulesDddc.getId())
                                    && couponRules.getUpdateTime().getTime() != couponRulesDddc.getUpdateTime().getTime()) {
                                    updateList.add(couponRules);
                            }
                        }
                    }
                }

                List<com.feiniu.coupon.entity.newCoupon.CouponRule> insertList = new ArrayList<com.feiniu.coupon.entity.newCoupon.CouponRule>();;
                if (CollectionUtils.isNotEmpty(couponRulesDddcList)) {
                    Set<Integer> dddcSet = new HashSet<Integer>();
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule couponRulesDddc : couponRulesDddcList) {
                        dddcSet.add(couponRulesDddc.getId());
                    }
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule couponRules : couponRulesList) {
                        if (!dddcSet.contains(couponRules.getId())) {
                            insertList.add(couponRules);
                        }
                    }
                } else {
                    insertList = couponRulesList;
                }

                if (CollectionUtils.isNotEmpty(insertList)) {
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule insertCouponRules : insertList) {
                        couponOldForNewMapper.insertCouponRulesDddc(insertCouponRules);
                    }
                } 
                if (CollectionUtils.isNotEmpty(updateList)) {
                    for (com.feiniu.coupon.entity.newCoupon.CouponRule updateCouponRules : updateList) {
                        couponOldForNewMapper.updateCouponRulesDddc(updateCouponRules);
                    }
                }
                startIndex += batchSize;
                logger.info("synchronizeCouponData.synchronizeCouponRulesDddc---"+startIndex);
            }
        }
    }

遇到的问题

1.原因是数据库里面有char类型的字段其内容为空格

Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 0
    at java.lang.String.charAt(String.java:658)
    at org.apache.ibatis.type.CharacterTypeHandler.getNullableResult(CharacterTypeHandler.java:37)
    at org.apache.ibatis.type.CharacterTypeHandler.getNullableResult(CharacterTypeHandler.java:26)
    at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:55)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getPropertyMappingValue(DefaultResultSetHandler.java:393)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyPropertyMappings(DefaultResultSetHandler.java:367)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:341)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:294)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:269)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:239)
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:153)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:60)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:73)

2.mybaitis批量insert使用$ 符号

字段存放的值包含单引号和’$’前后的单引号冲突导致程序报错,使用#可以避免问题。

<insert id="insertBatchCouponRulesDddc"  useGeneratedKeys="true"  parameterType="java.util.List">
        insert into coupon.coupon_rules_dddc(id,
                                             coupon_id,
                                             type,
                                             type_seq,
                                             type_seq_name,
                                             is_use,
                                             create_id,
                                             create_time,
                                             update_id,
                                             update_time)
        values
        <foreach collection="list" item="item" index="index"  separator="," >
             '${item.id}',
             '${item.couponId}', 
             '${item.type}', 
             '${item.typeSeq}', 
             '${item.typeSeqName}',
             '${item.isUse}', 
             '${item.createId}',
             '${item.createTime}',
             '${item.updateId}',
             '${item.updateTime}')
        </foreach>
    </insert>

3.重点关注rules.id自动增长列,存在情况如下:
1)线上rule.id从1增长到了1000000;
2)这时候同步数据rule到rules,rules.id数据为1到1000000,创建自动增长列从1000000开始;
3)部署应用java程序,在此期间rule新增20000数据,rule.id增长到1020000;
4)部署应用程序后读写rules表,此时要自动同步rule新增的20000记录,这样会造成rules.id冲突,造成同步rule的数据会和新增rules表数据争用。
5)这里我们为了保险起见,在设置rules.id从1500000开始增长,这样即使rule有数据增加,也不会影响rules表读写数据。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 实现 Mysql 数据同步可以通过以下步骤实现: 1. 连接源数据库和目标数据库,获取连接对象; 2. 查询源数据库中需要同步数据; 3. 将查询结果写入到目标数据库中; 4. 关闭连接对象。 具体的实现过程可以参考以下代码: ``` import java.sql.*; public class MysqlSync { public static void main(String[] args) { Connection sourceConn = null; Connection targetConn = null; Statement sourceStmt = null; Statement targetStmt = null; ResultSet rs = null; try { // 连接源数据库 Class.forName("com.mysql.jdbc.Driver"); sourceConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/source_db", "root", "password"); sourceStmt = sourceConn.createStatement(); // 查询源数据库中需要同步数据 rs = sourceStmt.executeQuery("SELECT * FROM source_table"); // 连接目标数据库 targetConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/target_db", "root", "password"); targetStmt = targetConn.createStatement(); // 将查询结果写入到目标数据库中 while (rs.next()) { String name = rs.getString("name"); int age = rs.getInt("age"); targetStmt.executeUpdate("INSERT INTO target_table (name, age) VALUES ('" + name + "', " + age + ")"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭连接对象 try { if (rs != null) { rs.close(); } if (sourceStmt != null) { sourceStmt.close(); } if (sourceConn != null) { sourceConn.close(); } if (targetStmt != null) { targetStmt.close(); } if (targetConn != null) { targetConn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } ``` 这段代码是一个简单的示例,实际应用中需要根据具体需求进行改进和优化。同时,需要注意数据库连接的安全性和性能问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值