alibaba-canal 开源数据监听实战,附上业务代码

canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
canal 作为 MySQL binlog 增量获取和解析工具,可将变更记录投递到 MQ 系统中,比如 Kafka/RocketMQ,可以借助于 MQ 的多语言能力

【第四节为业务代码说明】

canal官网https://github.com/alibaba/canal/
早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

  • 基于日志增量订阅和消费的业务包括
  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

1.项目背景

做了一个教培机构的运营管理平台(以下称为A),机构还有另外一个系统是专门做教学服务的授课平台(以下称为B)。在业务场景下B平台中,所有的基础业务数据都来自于A平台。
所以当A平台数据增加,修改,删除等等发生业务扭转时都需要通知B平台。
业务数据修改的地方太多,如果将同步触发写在代码中地方太多找不清楚也会不便于后期维护,所以开始了解canal数据源监听。

2.环境版本

  • 操作系统:Constos 6.8
  • java版本:jdk1.8.0_181 (jdk-8u11-linux-x64.tar.gz)
  • canal 版本: canal 1.1.4 (canal.deployer-1.1.4.tar.gz)
  • MySQL版本 :mysql 5.6
    对于自建 MySQL , 需要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下
    注意:针对阿里云 RDS for MySQL , 默认打开了 binlog , 并且账号默认具有 binlog dump 权限 , 不需要任何权限或者 binlog 设置,可以直接跳过这一步
    [mysqld]
    log-bin=mysql-bin # 开启 binlog
    binlog-format=ROW # 选择 ROW 模式
    server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
    
  • kafka版本:kafka_2.11-1.1.1 (kafka_2.11-1.1.1.tgz)
  • zk版本:zookeeper-3.4.10 (zookeeper-3.4.10.tar.gz)

注意 : 关闭所有机器的防火墙,同时注意启动可以相互telnet ip 端口

3.最新版canal安装(canal+kafka)

官方参考:https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart

3.1 canal安装

将canal.deployer-1.1.4.tar.gz 上传到服务器并解压

  1. 修改instance 配置文件 vi conf/example/instance.properties
    #################################################
    ## mysql serverId , v1.0.26+ will autoGen
    canal.instance.mysql.slaveId=12345
    
    # enable gtid use true/false
    canal.instance.gtidon=false
    
    # position info
    canal.instance.master.address=192.168.1.20:3306
    # username/password,数据库的用户名和密码
    canal.instance.dbUsername=root
    canal.instance.dbPassword=root
    canal.instance.connectionCharset = UTF-8
    
    # enable druid Decrypt database password
    canal.instance.enableDruid=false
    
    # table regex (白名单)
    #canal.instance.filter.regex=.*\\..*
    canal.instance.filter.regex =  库名.表名,库名.表名
    test.user,test.dept
    
    # table black regex(黑名单)
    #canal.instance.filter.black.regex=mysql\\..*,db_user_0\\..*
    canal.instance.filter.black.regex=mysql\\..*,test2_eplus\\..*
    
    # mq config  配置MQ的参数
    # 配置使用的topic,和topic的分区数
    canal.mq.topic=example 
    
    # dynamic topic route by schema or table regex
    #canal.mq.dynamicTopic=mytest1.user,mytest2\\..*,.*\\..*
    canal.mq.partition=0 
    
  2. 修改canal 配置文件vi …/canal/conf/canal.properties
    # ...
    # 可选项: tcp(默认), kafka, RocketMQ
    canal.serverMode = kafka
    # ...
    # kafka/rocketmq 集群配置: 192.168.1.117:9092,192.168.1.118:9092,192.168.1.119:9092 
    canal.mq.servers = 127.0.0.1:6667
    canal.mq.retries = 0
    # flagMessage模式下可以调大该值, 但不要超过MQ消息体大小上限
    canal.mq.batchSize = 16384
    canal.mq.maxRequestSize = 1048576 消息大小,超过会抛出异常( org.apache.kafka.common.errors.RecordTooLargeException)
    # flatMessage模式下请将该值改大, 建议50-200
    canal.mq.lingerMs = 1
    canal.mq.bufferMemory = 33554432
    # Canal的batch size, 默认50K, 由于kafka最大消息体限制请勿超过1M(900K以下)
    canal.mq.canalBatchSize = 50
    # Canal get数据的超时时间, 单位: 毫秒, 空为不限超时
    canal.mq.canalGetTimeout = 100
    # 是否为flat json格式对象
    canal.mq.flatMessage = false (为true时,运行代码过程中会出现反序列化失败)
    canal.mq.compressionType = none
    canal.mq.acks = all
    # kafka消息投递是否使用事务
    canal.mq.transaction = false
    
    

3.2 kafka 安装

参考https://github.com/alibaba/canal/wiki/Kafka-QuickStart
将kafka_2.11-1.1.1.tgz上传到服务器,并解压

vim /opt/kafka/config/server.properties

主要更改:
zookeeper.connect=10.168.3.145:2181
listeners=PLAINTEXT://:9092 
advertised.listeners=PLAINTEXT://10.168.3.145:9092 
host.name=0.0.0.0
delete.topic.enable=true
log.dirs=/opt/kafka/logs

清空log可以参考:https://blog.csdn.net/qq_39657597/article/details/84307541
./bin/kafka-topics --delete --zookeeper 10.168.3.145:2181(zk地址) --topic example (topic名字)

启动:
sh bin/kafka-server-start.sh  -daemon  config/server.properties &

关闭:
sh bin/kafka-server-stop.sh 

kafka同时支持内网外网:  
方法一: 
   用hostname
   注掉listeners,然后advertised.listeners 改为:
   advertised.listeners=PLAINTEXT://hostname:9092
   内网外网客户端,都需要把所在机器的hosts文件,写入hostname对应ip,内网对应内网ip,外网对应外网ip即可
   这种前提是外网端口也是9092,需要跟内网对应的一样;

方法二:
   注掉listeners,然后advertised.listeners 改为:
   advertised.listeners=PLAINTEXT://外网ip:外网端口
   内网自动支持。
这种方式注意事项:有安全隐患,并且kafka集群之间节点的连接会走外网, 网络抖动,导致服务出现不可用,因此按需选择

3.3 canal相关操作

  • 启动
    cd /usr/local/canal/
    sh bin/startup.sh
  • 查看日志
    a.查看 logs/canal/canal.log
    vi logs/canal/canal.log
    b. 查看instance的日志:
    vi logs/example/example.log
  • 关闭
    cd /usr/local/canal/
    sh bin/stop.sh

4.MQ数据消费

canal.client下有对应的MQ数据消费的样例工程,包含数据编解码的功能

  • kafka模式:com.alibaba.otter.canal.example.kafka.CanalKafkaClientExample

4.1 CanalKafkaClient.java是我实际的业务代码

中间夹着很多业务处理的代码,可以用于参考。
选几个重要的地方说明一下。

  1. new KafkaCanalConnector(servers, topic, partition, groupId, 10, false);
    官方给的原文件中 是new KafkaCanalConnector(servers, topic, partition, groupId, null, false);
    在消费数据速度慢的情况下会出现org.apache.kafka.clients.consumer.CommitFailedException
    可参考线上canal、kafka异常处理org.apache.kafka.clients.consumer.CommitFailedException
 public CanalKafkaClient(String zkServers, String servers, String topic, Integer partition, String groupId){
        connector = new KafkaCanalConnector(servers, topic, partition, groupId, 10, false);
    }
  1. printEntry(message.getEntries());
    消费数据,处理业务逻辑。
    根据操作类型,表名来做不同的业务处理
    将变更的数据,存到表中供B平台同步信息,也可以使用MQ来实现。其实就是消息队列,只不过我这里偷懒用数据库做了

    
    protected void printEntry(List<Entry> entrys) {
    	...
    	//获取数据的操作类型,用作不同操作进入不通的方法
    	EventType eventType = rowChage.getEventType();      
        UpdateJWDTO updateJWDTO = new UpdateJWDTO();
        String tableName = entry.getHeader().getTableName();//获取表名
        List<UpdateJWDTO> jwdtoList = new ArrayList<UpdateJWDTO>();
        List<Column> columns =  new ArrayList<Column>();
    	//循环结果集
        if(eventType == EventType.UPDATE){
        	for (RowData rowData : rowChage.getRowDatasList()) {
        		columns = rowData.getAfterColumnsList();
        		updateJWDTO = updateColumn(tableName,columns);
        		if(updateJWDTO.getUpdateTableId() != null){
        			jwdtoList.add(updateJWDTO);
        		}
        	}
        }
    	...
    }
    
  2. private static UpdateJWDTO updateColumn(String tableName,List columns)
    当数据进行修改时,判断修改的值是不是教学系统需要的值
    是则进行数据封装,保存到临时表
    如果是需要实时通知的,可以直接通过接口方式进行通知,如:用户密码修改的操作

    String filerName = column.getName();//获取字段名
    boolean updateState = column.getUpdated();//获取字段是不是被改了
    columns.get(15);//可以直接获取当前数据的值,15为数据库字段表的下标值,下标从0开始。例如:数据库字段为 id,name,age。那么name的值就是columns.get(1);

    	/**
         * 当数据进行修改时,判断修改的值是不是教学系统需要的值
         * 
         * @author ls
         * @date 2018-12-4
         */
        private static UpdateJWDTO updateColumn(String tableName,List<Column> columns) {
        	UpdateJWDTO updateJWDTO = new UpdateJWDTO();
        	try {
        		for (Column column : columns) {
                    boolean updateState = column.getUpdated();
                    String filerName = column.getName();
                    
                    //执行修改操作的时候调用教学接口
                    
                    if(tableName.equalsIgnoreCase("class_manage")){
            			if((filerName.equalsIgnoreCase("CLASS_NAME")||filerName.equalsIgnoreCase("ENGLISHNAME")||filerName.equalsIgnoreCase("IS_ENABLED")
                    			||filerName.equalsIgnoreCase("OS_ID")||filerName.equalsIgnoreCase("PK_ADMISSIONS_SEASON")
                    			||filerName.equalsIgnoreCase("PK_USER_1")||filerName.equalsIgnoreCase("PK_ASS")
                    			||filerName.equalsIgnoreCase("CLASS_STATE")) && updateState){
            				/**
                             *  当修改表为班级时,先判断班级状态 115 建班审核通过 116 开课 117 结课 
                             */
                			if(columns.get(15) != null && columns.get(15).getValue() != null){ // 班级状态 CLASS_STATE
                				String classState = columns.get(15).getValue().toString();
                        		if(classState.equals("116") || classState.equals("117") ){
            	            		updateJWDTO.setTableNum(QsteachConstants.CLASS_MANAGE);
            	            		putUpdateJWDTO(updateJWDTO,tableName,columns);
                        		}
                			}
                    	}
                    }else if(tableName.equalsIgnoreCase("student")){
                    	//学员
                    	if((filerName.equalsIgnoreCase("STU_NAME") ||filerName.equalsIgnoreCase("CONTACT_INFO")
                    			||filerName.equalsIgnoreCase("PK_STU_STATE") || filerName.equalsIgnoreCase("ZD_STU_TYPE") ||filerName.equalsIgnoreCase("ENGLISHNAME")
                    			||filerName.equalsIgnoreCase("PASSWORD") ||filerName.equalsIgnoreCase("STUDY_NUMBER")
                    			||filerName.equalsIgnoreCase("CID") ||filerName.equalsIgnoreCase("GENDER")
                    			||filerName.equalsIgnoreCase("BIRTHDAY")) && updateState){
                    		
                			if(columns.get(14) != null && columns.get(14).getValue() != null){//学员状态 ZD_STU_TYPE
                				String studentType = columns.get(14).getValue().toString();
                        		if(studentType.equals("9")){
                        			updateJWDTO.setTableNum(QsteachConstants.STUDENT);
                            		putUpdateJWDTO(updateJWDTO,tableName,columns);
                        		}
                    		}
                			if(filerName.equalsIgnoreCase("PASSWORD")){
                				String jwId = columns.get(0).getValue();
                				String type ="2";
                				Tms.omsClientUpdatePassWord(type, jwId);
                			}
    
                    	}
                    }
                }
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
            
            return updateJWDTO;
        }
    

4.2 CanalKafkaClient.java

package tms;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import com.alibaba.otter.canal.client.kafka.KafkaCanalConnector;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;

/**
 * Kafka client example
 *
 * @author machengyuan @ 2018-6-12
 * @version 1.0.0
 */
public class CanalKafkaClient extends BaseCanalClient{

    protected final static Logger           logger  = LoggerFactory.getLogger(CanalKafkaClient.class);
    
    public static String  topic     = "example";
    public static Integer partition = null;
    public static String  groupId   = "g4";
    public static String  servers   = "127.0.0.1:9092";
    public static String  zkServers = "127.0.0.1:2181";
    private KafkaCanalConnector             connector;
    private static volatile boolean         running = false;
    private Thread                          thread  = null;
    private Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
        public void uncaughtException(Thread t, Throwable e) {
            logger.error("parse events has an error", e);
        }
    };

    public CanalKafkaClient(String zkServers, String servers, String topic, Integer partition, String groupId){
        connector = new KafkaCanalConnector(servers, topic, partition, groupId, 10, false);
    }

    public static void main(String[] args) {
    	try {
    		/*在main方法配置logback文件,kafka debug日志不会频繁刷 ----start   TODO 线上根据自身项目情况,如果不需要可以删掉此段代码--------------- 配置logback,kafka debug日志不会频繁刷 ----end-----------------------------*/
			LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
			JoranConfigurator configurator = new JoranConfigurator();
			configurator.setContext(lc);
			lc.reset();
			try {
				String path = CanalKafkaClient.class.getResource("/") + "logback.xml";
				System.out.println(path);
				configurator.doConfigure("src/main/resource/logback.xml");
			} catch (JoranException e) {
				e.printStackTrace();
			}
			StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
			
            final CanalKafkaClient kafkaCanalClient = new CanalKafkaClient(zkServers,servers,topic,partition,groupId);
            logger.info("## start the kafka consumer: {}-{}", topic, groupId);
            kafkaCanalClient.start();
            logger.info("## the canal kafka consumer is running now ......");
            Runtime.getRuntime().addShutdownHook(new Thread() {

                public void run() {
                    try {
                        logger.info("## stop the kafka consumer");
                        kafkaCanalClient.stop();
                    } catch (Throwable e) {
                        logger.warn("##something goes wrong when stopping kafka consumer:", e);
                    } finally {
                        logger.info("## kafka consumer is down.");
                    }
                }

            });
            while (running);
        } catch (Throwable e) {
            logger.error("## Something goes wrong when starting up the kafka consumer:", e);
            System.exit(0);
        }
    }

    public void start() {
        Assert.notNull(connector, "connector is null");
        thread = new Thread(new Runnable() {

            public void run() {
                process();
            }
        });
        thread.setUncaughtExceptionHandler(handler);
        thread.start();
        running = true;
    }

    public void stop() {
        if (!running) {
            return;
        }
        running = false;
        if (thread != null) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                // ignore
            }
        }
    }

    private void process() {
        while (!running) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }

        while (running) {
            try {
                connector.connect();
                connector.subscribe();
                while (running) {
                    try {
                        List<Message> messages = connector.getListWithoutAck(100L, TimeUnit.MILLISECONDS); // 获取message
                     
                        if ( CollectionUtils.isEmpty(messages) ){
//                        	 logger.info("empty, sleeping for 1 second");
                        	 Thread.sleep(1000);
                            continue;
                        }
                        for (Message message : messages) {
                            long batchId = message.getId();
                            int size = message.getEntries().size();
                            if (batchId == -1 || size == 0) {
//                            	这个分支应该不会进( 因为现在已经是kafka方式,并不再是client主动拉取canal,DB有数据更新后canal主动推到kafka)
                            	continue;
                            } else {
                            	
//                            	 TODO 这两行是打日志,线上要注掉,此类去掉extends BaseCanalClient
                                 //printSummary(message, batchId, size);
                                 //printEntry(message.getEntries());
                            	
//                            	 TODO 这里写业务逻辑,处理方式跟老的相同
                            	 //System.out.println("========"+messages);
//                               message.getEntries()
								 
								 //消费数据,处理业务逻辑
                                 printEntry(message.getEntries());
//                               logger.info(message.toString());
                            }
                        }

                        connector.ack(); // 提交确认
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    	Tms.simpleMailSend("[email protected]","tms同步数据接口调用失败",e.toString());
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        connector.unsubscribe();
        connector.disconnect();
    }
    
    //消费数据,处理业务逻辑
    protected void printEntry(List<Entry> entrys) {
    	
        for (Entry entry : entrys) {
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
                continue;
            }
            RowChange rowChage = null;
            
            try {
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
                e.printStackTrace();
            }
            
            try {
                EventType eventType = rowChage.getEventType();//操作类型
             
                UpdateJWDTO updateJWDTO = new UpdateJWDTO();
                String tableName = entry.getHeader().getTableName();//获取表名
                List<UpdateJWDTO> jwdtoList = new ArrayList<UpdateJWDTO>();
                List<Column> columns =  new ArrayList<Column>();
                
                //循环结果集
                if(eventType == EventType.UPDATE){
                	for (RowData rowData : rowChage.getRowDatasList()) {
                		columns = rowData.getAfterColumnsList();
                		updateJWDTO = updateColumn(tableName,columns);
                		if(updateJWDTO.getUpdateTableId() != null){
                			jwdtoList.add(updateJWDTO);
                		}
                	}
                }
                if(eventType == EventType.INSERT){
                	for (RowData rowData : rowChage.getRowDatasList()) {
                		columns = rowData.getAfterColumnsList();
                		updateJWDTO = insertColumn(tableName,columns);
                		if(updateJWDTO.getUpdateTableId() != null){
                			jwdtoList.add(updateJWDTO);
                		}
                	}
                }
                if(eventType == EventType.DELETE){
                	for (RowData rowData : rowChage.getRowDatasList()) {
                		columns = rowData.getBeforeColumnsList();
                		updateJWDTO = deleteColumn(tableName,columns);
                		if(updateJWDTO.getUpdateTableId() != null){
                			jwdtoList.add(updateJWDTO);
                		}
                	}
                }
                
                if(jwdtoList.size() > 0){
                	String insertSchoolSql = "insert into UPDATEJWDTO (UPDATETABLEID,TABLENUM,OPERATEFLAG,REMARK,STATUS,CREATE_DATE,GROUPID) values";
                    
                    //将内容加入数据库
                    for (UpdateJWDTO jwdto : jwdtoList) {
            			insertSchoolSql = insertSchoolSql + "("+jwdto.getUpdateTableId()+","+jwdto.getTableNum()+",'"
            							+jwdto.getOperateFlag()+"','"+jwdto.getRemark()+"','"+jwdto.getStatus()+"',now(),'"
            							+jwdto.getUpdateTableId()+jwdto.getOperateFlag()+jwdto.getTableNum()+"'),";
    				}
                    insertSchoolSql =insertSchoolSql.substring(0, insertSchoolSql.length()-1);
            		Ds.getJdbcTemplate4Mysql().update(insertSchoolSql);
            		System.out.println(insertSchoolSql);
                }
            } catch (Exception e) {
            	e.printStackTrace();
            }
        }
    }
    
    /**
     * 当数据进行添加时
     * @author ls
     * @date 2018-12-5
     */
    private static UpdateJWDTO insertColumn(String tableName,List<Column> columns){
    	UpdateJWDTO updateJWDTO = new UpdateJWDTO();
    	
    	try {
    		for (Column column : columns) {
        		if(tableName.equalsIgnoreCase("T_0_USER_INFO")){
        			//人员表
        			if(columns.get(29) != null && columns.get(29).getValue()!= null){//是否是老师  IF_TEACHER
    					String teacherId = columns.get(29).getValue().toString();
                		if(teacherId.equals("2")){
                			updateJWDTO.setTableNum(QsteachConstants.T_0_USER_INFO);
                			putInsertJWDTO(updateJWDTO,tableName,columns);
                		}
        			}
        			
        		}else if(tableName.equalsIgnoreCase("ORDER_FORM")){	//监听订单添加 调用余额、优惠券消耗方法 - hdx 20191209
        			if("ZD_OF_TYPE".equalsIgnoreCase(column.getName())) {
	        			String zd_of_type = columns.get(13).getValue();	//订单类型 785教材销售
	        			if("785".equals(zd_of_type)) {
	        				String orderId = columns.get(0).getValue();
	        				Tms.handleAccountAndCouponForOrderFromTms(orderId);
	        			}
        			}
        			
        			//转班转校订单新增调用转班发起的接口  lyh
        			if("TRANSF_TYPE".equalsIgnoreCase(column.getName())) {
            			String transfType = columns.get(66).getValue();
            			if ("1183".equals(transfType)||"1184".equals(transfType)) {
            				String orderId = columns.get(0).getValue();
            				String userId = columns.get(6).getValue();
            				//String stuId = columns.get(5).getValue();
    						String parentOrderId = columns.get(49).getValue();
    						Tms.changeClassApplyTms(orderId,parentOrderId,userId);
    					}
        			}
        			
        		}
        	}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return updateJWDTO;
    	
    }
    
    /**
     * 当数据进行删除时
     * @author ls
     * @date 2018-12-5
     */
    private static UpdateJWDTO deleteColumn(String tableName,List<Column> columns){
    	UpdateJWDTO updateJWDTO = new UpdateJWDTO();
    	
    	try {
    		for (Column column : columns) {
        		if(tableName.equalsIgnoreCase("T_0_USER_INFO")){
        			//人员
        			if(columns.get(29) != null && columns.get(29).getValue()!= null){//是否是老师  IF_TEACHER
    					String teacherId = columns.get(29).getValue().toString();
                		if(teacherId.equals("2")){
                			updateJWDTO.setTableNum(QsteachConstants.T_0_USER_INFO);
                			putDeleteJWDTO(updateJWDTO,tableName,columns);
                		}
        			}
        		}
        	}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
    	return updateJWDTO;
    }
    /**
     * 当数据进行修改时,判断修改的值是不是教学系统需要的值
     * 是则进行数据封装,保存到临时表
     * @author ls
     * @date 2018-12-4
     */
    private static UpdateJWDTO updateColumn(String tableName,List<Column> columns) {
    	UpdateJWDTO updateJWDTO = new UpdateJWDTO();
    	try {
    		for (Column column : columns) {
                boolean updateState = column.getUpdated();
                String filerName = column.getName();
                
                //执行修改操作的时候调用教学接口
                
                if(tableName.equalsIgnoreCase("class_manage")){
        			if((filerName.equalsIgnoreCase("CLASS_NAME")||filerName.equalsIgnoreCase("ENGLISHNAME")||filerName.equalsIgnoreCase("IS_ENABLED")
                			||filerName.equalsIgnoreCase("OS_ID")||filerName.equalsIgnoreCase("PK_ADMISSIONS_SEASON")
                			||filerName.equalsIgnoreCase("PK_USER_1")||filerName.equalsIgnoreCase("PK_ASS")
                			||filerName.equalsIgnoreCase("CLASS_STATE")) && updateState){
        				/**
                         *  当修改表为班级时,先判断班级状态 115 建班审核通过 116 开课 117 结课 
                         */
            			if(columns.get(15) != null && columns.get(15).getValue() != null){ // 班级状态 CLASS_STATE
            				String classState = columns.get(15).getValue().toString();
                    		if(classState.equals("116") || classState.equals("117") ){
        	            		updateJWDTO.setTableNum(QsteachConstants.CLASS_MANAGE);
        	            		putUpdateJWDTO(updateJWDTO,tableName,columns);
                    		}
            			}
                	}
                }else if(tableName.equalsIgnoreCase("student")){
                	//学员
                	if((filerName.equalsIgnoreCase("STU_NAME") ||filerName.equalsIgnoreCase("CONTACT_INFO")
                			||filerName.equalsIgnoreCase("PK_STU_STATE") || filerName.equalsIgnoreCase("ZD_STU_TYPE") ||filerName.equalsIgnoreCase("ENGLISHNAME")
                			||filerName.equalsIgnoreCase("PASSWORD") ||filerName.equalsIgnoreCase("STUDY_NUMBER")
                			||filerName.equalsIgnoreCase("CID") ||filerName.equalsIgnoreCase("GENDER")
                			||filerName.equalsIgnoreCase("BIRTHDAY")) && updateState){
                		
            			if(columns.get(14) != null && columns.get(14).getValue() != null){//学员状态 ZD_STU_TYPE
            				String studentType = columns.get(14).getValue().toString();
                    		if(studentType.equals("9")){
                    			updateJWDTO.setTableNum(QsteachConstants.STUDENT);
                        		putUpdateJWDTO(updateJWDTO,tableName,columns);
                    		}
                		}
            			if(filerName.equalsIgnoreCase("PASSWORD")){
            				String jwId = columns.get(0).getValue();
            				String type ="2";
            				Tms.omsClientUpdatePassWord(type, jwId);
            			}

                	}
                }
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
        
        return updateJWDTO;
    }
    
    /**
     * 赋值
     * @author ls
     * @date 2018-12-4
     */
    private static void putUpdateJWDTO(UpdateJWDTO updateJWDTO,String tableName,List<Column> columns) {
    	String updateRemark = "对"+tableName+"表,执行了修改操作,主键ID为:"+Long.valueOf(columns.get(0).getValue());
    	
    	/**
    	 * 班级修改为公开课时,单独处理接口
    	 */
    	if(tableName.equalsIgnoreCase("class_manage")){
    		String classState = columns.get(15).getValue().toString();
    		if(classState.equals("116")){
    			updateJWDTO.setOperateFlag("all");
    		}else{
    			updateJWDTO.setOperateFlag("update");
    		}
    	}else{
    		updateJWDTO.setOperateFlag("update");
    	}
    	
    	if(updateJWDTO.getUpdateTableId() == null){
    		updateJWDTO.setUpdateTableId(Long.valueOf(columns.get(0).getValue()));
    	}
    	
    	updateJWDTO.setRemark(updateRemark);
    	updateJWDTO.setStatus("0");
    }
    /**
     * 赋值
     * @author ls
     * @date 2018-12-4
     */
    private static void putDeleteJWDTO(UpdateJWDTO updateJWDTO,String tableName,List<Column> columns) {
    	String updateRemark = "对"+tableName+"表,执行了删除操作,主键ID为:"+Long.valueOf(columns.get(0).getValue());
    	updateJWDTO.setOperateFlag("delete");
    	if(updateJWDTO.getUpdateTableId() == null){
    		updateJWDTO.setUpdateTableId(Long.valueOf(columns.get(0).getValue()));
    	}
    	updateJWDTO.setRemark(updateRemark);
    	updateJWDTO.setStatus("0");
    }
    
    /**
     * 赋值
     * @author ls
     * @date 2018-12-4
     */
    private static void putInsertJWDTO(UpdateJWDTO updateJWDTO,String tableName,List<Column> columns) {
    	String updateRemark = "对"+tableName+"表,执行了添加操作,主键ID为:"+Long.valueOf(columns.get(0).getValue());
    	updateJWDTO.setOperateFlag("insert");
    	if(updateJWDTO.getUpdateTableId() == null){
    		updateJWDTO.setUpdateTableId(Long.valueOf(columns.get(0).getValue()));
    	}
    	updateJWDTO.setRemark(updateRemark);
    	updateJWDTO.setStatus("0");
    }
    
    /**
     * 查询单条数据
     * @author ls
     * @date 2019-1-9
     */
    public static Map<String,Object> selectOne(String tableName,String id){
		String sql = "select * from " + tableName + " where ";
		if(tableName.equalsIgnoreCase("t_0_user_info")){
			sql = sql + " user_id = " + id;
		}else if(tableName.equalsIgnoreCase("class_manage")){
			sql = sql + " c_m_id = " + id;
		}else if(tableName.equalsIgnoreCase("student")){
			sql = sql + " student_id = " + id;
		}else if(tableName.equalsIgnoreCase("class_schedule")){
			sql = sql + " c_s_id = " + id;
		}else if(tableName.equalsIgnoreCase("class_course")){
			sql = sql + " c_c_id = " + id;
		}else if(tableName.equalsIgnoreCase("SC_CLASS_TEA")){
			sql = sql + " S_C_T_ID = " + id;
		}
		try {
			return Ds.getJdbcTemplate4Mysql().queryForMap(sql);
		} catch (Exception e) {
			return null;
		}
		
	}
}

觉得有用的话,点赞一下呀!

你可能感兴趣的:(插件工具,java,数据库,mysql)