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 上传到服务器并解压
- 修改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
- 修改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数据消费的样例工程,包含数据编解码的功能
4.1 CanalKafkaClient.java是我实际的业务代码
中间夹着很多业务处理的代码,可以用于参考。
选几个重要的地方说明一下。
- 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);
}
-
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); } } } ... }
-
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("liushaomr@163.com","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;
}
}
}
觉得有用的话,点赞一下呀!