2018-09-27 16:25:51 +08:00
package com.nms.thread ;
import java.sql.SQLException ;
import java.util.ArrayList ;
import java.util.Date ;
import java.util.List ;
import org.apache.log4j.Logger ;
import com.alibaba.fastjson.JSON ;
import com.jfinal.aop.Before ;
import com.jfinal.plugin.activerecord.Db ;
import com.jfinal.plugin.activerecord.IAtom ;
import com.jfinal.plugin.activerecord.Record ;
import com.nms.interceptor.SyncDataInterceptor ;
import com.nms.model.SyncDbInfo ;
import com.jfinal.plugin.activerecord.tx.Tx ;
/ * *
* 数据同步功能线程
*
* @author Administrator
*
* /
2018-09-29 11:38:05 +08:00
@Before ( { SyncDataInterceptor . class , Tx . class } )
2018-09-27 16:25:51 +08:00
public class SyncThread implements Runnable {
private Logger logger = Logger . getLogger ( this . getClass ( ) ) ;
private SyncDbInfo syncDbInfo ;
public SyncThread ( ) {
super ( ) ;
}
public SyncThread ( SyncDbInfo syncDbInfo ) {
super ( ) ;
this . syncDbInfo = syncDbInfo ;
}
@Override
public void run ( ) {
try {
logger . info ( " 开始主库数据同步分库任务 " ) ;
// 获取url路径
2018-09-29 11:38:05 +08:00
final StringBuffer url = new StringBuffer ( ) ;
url . append ( " jdbc:mysql:// " + syncDbInfo . get ( " ip " ) + " : " + syncDbInfo . get ( " port " ) + " / "
2018-10-17 09:47:57 +08:00
+ syncDbInfo . get ( " database_name " ) + " ?useUnicode=true&characterEncoding=utf-8&useOldAliasMetadataBehavior=true&rewriteBatchedStatements=true " ) ;
2018-09-27 16:25:51 +08:00
logger . info ( " 获取分库数据库连接信息 " + url ) ;
List < Record > find = Db . use ( " masterDataSource " ) . find ( " select * from table_sync_info where db_id=? " ,
syncDbInfo . get ( " id " ) ) ;
2018-10-17 14:32:34 +08:00
//logger.info("查询主库须向分库同步数据信息"+JSON.toJSONString(find));
2018-09-27 16:25:51 +08:00
if ( find ! = null & & find . size ( ) > 0 ) {
for ( final Record record : find ) {
2018-10-26 10:54:47 +08:00
logger . info ( " 主库数据同步到分库 正在操作的表名为: " + record . getStr ( " table_name " ) ) ;
2018-10-17 18:59:31 +08:00
//如果设定指定字段 则只操作指定字段数据 无则操作全部
final StringBuffer columns = new StringBuffer ( ) ;
columns . append ( " * " ) ;
if ( null ! = record . getStr ( " columns " ) & & ! " " . equals ( record . getStr ( " columns " ) ) ) {
columns . setLength ( 0 ) ;
columns . append ( record . getStr ( " columns " ) ) ;
}
2018-09-27 16:25:51 +08:00
// 循环同步数据标识
boolean flag = true ;
// 判断表中的event事件 1代表insert 2代表update 3代表delete
if ( record . getInt ( " event " ) = = 1 ) {
//根据mode判断主键产生方式
2018-10-16 16:25:30 +08:00
if ( record . getInt ( " mode " ) . equals ( 1 ) | | record . getInt ( " mode " ) . equals ( 2 ) ) {
2018-09-27 16:25:51 +08:00
while ( flag ) {
// 查询增量数据
final List < Record > data = Db . use ( " masterDataSource " )
2018-10-17 18:59:31 +08:00
. find ( " select " + columns . toString ( ) + " from " + record . getStr ( " table_name " ) + " where "
2018-09-27 16:25:51 +08:00
+ record . getStr ( " id_name " ) + " > ? order by " + record . getStr ( " id_name " ) + " asc limit " + record . getInt ( " batch_size " ) ,
record . getLong ( " last_id " ) ) ;
//logger.info("主库同步分库新增数据增量更新的数据信息"+JSON.toJSONString(data));
if ( data ! = null & & data . size ( ) > 0 ) {
2018-10-15 09:53:52 +08:00
final Object lastInsertId = data . get ( data . size ( ) - 1 ) . get ( record . getStr ( " id_name " ) ) ;
2018-10-16 16:25:30 +08:00
if ( record . getInt ( " mode " ) . equals ( 2 ) ) {
for ( Record entity : data ) {
entity . remove ( record . getStr ( " id_name " ) ) ;
}
2018-10-15 09:53:52 +08:00
}
2018-09-27 16:25:51 +08:00
//多数据源事务 主数据源嵌套子数据源
Db . use ( ) . tx ( new IAtom ( ) {
@Override
public boolean run ( ) throws SQLException {
2018-09-29 11:38:05 +08:00
return Db . use ( url . toString ( ) ) . tx ( new IAtom ( ) {
2018-09-27 16:25:51 +08:00
@Override
public boolean run ( ) throws SQLException {
2018-09-29 11:38:05 +08:00
Db . use ( url . toString ( ) ) . batchSave ( record . getStr ( " table_name " ) , data , record . getInt ( " batch_size " ) ) ;
2018-09-27 16:25:51 +08:00
// 同步完成后 取出最后一条数据的id 更新到table_sync_info表中 用作下次使用
logger . info ( " 增量更新结束 获取最后一条更新数据的id信息 " + JSON . toJSONString ( lastInsertId ) ) ;
record . set ( " last_id " , lastInsertId ) ;
record . set ( " last_date " , new Date ( ) ) ;
Db . use ( " masterDataSource " ) . update ( " table_sync_info " , record ) ;
return true ;
}
} ) ;
}
} ) ;
logger . info ( " 增量更新数据任务结束 " ) ;
} else {
flag = false ;
}
}
} else if ( record . getInt ( " mode " ) . equals ( 0 ) ) {
//当数据库表结构主键不是自增时 增量更新的操作步骤
while ( flag ) {
// 新增操作 取出最后更新id信息 查询增量数据
final List < Record > data = Db . use ( " masterDataSource " )
. find ( " select * from table_event_log where table_name = ' " + record . getStr ( " table_name " )
+ " ' and id > " + record . getLong ( " last_id " ) + " and event = "
+ record . getInt ( " event " ) + " order by id asc limit " + record . getInt ( " batch_size " ) ) ;
//logger.info("主库同步分库新增数据增量更新的数据信息"+JSON.toJSONString(data));
if ( data ! = null & & data . size ( ) > 0 ) {
//多数据源事务 主数据源嵌套子数据源
Db . use ( ) . tx ( new IAtom ( ) {
@Override
public boolean run ( ) throws SQLException {
2018-09-29 11:38:05 +08:00
return Db . use ( url . toString ( ) ) . tx ( new IAtom ( ) {
2018-09-27 16:25:51 +08:00
@Override
public boolean run ( ) throws SQLException {
2018-10-24 18:53:05 +08:00
List < Long > insertIds = new ArrayList < Long > ( ) ;
2018-09-27 16:25:51 +08:00
StringBuffer insertStr = new StringBuffer ( ) ;
for ( int i = 0 ; i < data . size ( ) ; i + + ) {
2018-10-24 18:53:05 +08:00
insertIds . add ( data . get ( i ) . getLong ( " target_id " ) ) ;
2018-09-27 16:25:51 +08:00
if ( i = = 0 ) {
insertStr . append ( " ? " ) ;
} else {
insertStr . append ( " ,? " ) ;
}
}
List < Record > insertDatas = Db . use ( " masterDataSource " )
2018-10-17 18:59:31 +08:00
. find ( " select " + columns . toString ( ) + " from " + record . getStr ( " table_name " ) + " where "
2018-09-27 16:25:51 +08:00
+ record . getStr ( " id_name " ) + " in ( " + insertStr + " ) " ,
insertIds . toArray ( ) ) ;
for ( Record insertData : insertDatas ) {
2018-09-29 11:38:05 +08:00
Record seqData = Db . use ( url . toString ( ) ) . findFirst ( " select nextval('seq_ " + record . getStr ( " table_name " ) + " ') seqId from dual " ) ;
2018-09-28 09:44:38 +08:00
if ( record . getStr ( " table_name " ) . equals ( " event_record_library " ) ) {
2018-10-08 15:44:24 +08:00
//设置数据状态为同步数据
2018-09-28 09:44:38 +08:00
insertData . set ( " sync_status " , 1 ) ;
2018-10-08 15:44:24 +08:00
//设置同步数据所在数据库的id以及所在原来表的id 用于修改和删除 -1为中心或主库
insertData . set ( " old_id " , insertData . getLong ( record . getStr ( " id_name " ) ) ) ;
insertData . set ( " db_id " , - 1 ) ;
2018-09-28 09:44:38 +08:00
}
2018-10-08 15:44:24 +08:00
insertData . set ( record . getStr ( " id_name " ) , seqData . getLong ( " seqId " ) ) ;
2018-09-27 16:25:51 +08:00
}
2018-09-29 11:38:05 +08:00
Db . use ( url . toString ( ) ) . batchSave ( record . getStr ( " table_name " ) , insertDatas , record . getInt ( " batch_size " ) ) ;
2018-09-27 16:25:51 +08:00
// 同步完成后 取出最后一条数据的id 更新到table_sync_info表中 用作下次使用
Object lastInsertId = data . get ( data . size ( ) - 1 ) . get ( " id " ) ;
logger . info ( " 增量更新结束 获取最后一条更新数据的id信息 " + JSON . toJSONString ( lastInsertId ) ) ;
record . set ( " last_id " , lastInsertId ) ;
record . set ( " last_date " , new Date ( ) ) ;
Db . use ( " masterDataSource " ) . update ( " table_sync_info " , record ) ;
return true ;
}
} ) ;
}
} ) ;
logger . info ( " 增量更新数据任务结束 " ) ;
} else {
flag = false ;
}
}
}
} else if ( record . getInt ( " event " ) = = 2 | | record . getInt ( " event " ) = = 3 ) {
2018-10-17 18:59:31 +08:00
2018-09-27 16:25:51 +08:00
// table_event_log sync_db_info两表查询获取修改数据信息 进行数据修改
while ( flag ) {
final List < Record > datas = Db . find (
" select * from table_event_log where table_name = ' " + record . getStr ( " table_name " )
+ " ' and id > " + record . getLong ( " last_id " ) + " and event = "
+ record . getInt ( " event " ) + " order by id asc limit " + record . getInt ( " batch_size " ) ) ;
//logger.info("获取主库删除或者修改数据的数据信息"+JSON.toJSONString(datas));
if ( datas ! = null & & datas . size ( ) > 0 ) {
//多数据源事务 主数据源嵌套子数据源
Db . use ( ) . tx ( new IAtom ( ) {
@Override
public boolean run ( ) throws SQLException {
2018-09-29 11:38:05 +08:00
return Db . use ( url . toString ( ) ) . tx ( new IAtom ( ) {
2018-09-27 16:25:51 +08:00
@Override
public boolean run ( ) throws SQLException {
2018-10-24 18:53:05 +08:00
List < Long > updateIds = new ArrayList < Long > ( ) ;
2018-10-09 14:45:58 +08:00
List < Record > deleteRecords = new ArrayList < Record > ( ) ;
StringBuilder handleStr = new StringBuilder ( ) ;
2018-09-27 16:25:51 +08:00
for ( int i = 0 ; i < datas . size ( ) ; i + + ) {
2018-10-24 18:53:05 +08:00
updateIds . add ( datas . get ( i ) . getLong ( " target_id " ) ) ;
2018-10-09 14:45:58 +08:00
if ( i = = 0 ) {
2018-10-08 15:44:24 +08:00
handleStr . append ( " ? " ) ;
2018-10-09 14:45:58 +08:00
} else {
2018-10-08 15:44:24 +08:00
handleStr . append ( " ,? " ) ;
2018-09-27 16:25:51 +08:00
}
}
logger . info ( " 获取所有操作的数据id信息为 " + JSON . toJSONString ( updateIds ) ) ;
if ( record . getInt ( " event " ) = = 2 ) {
List < Record > updateDatas = Db . use ( " masterDataSource " )
2018-10-17 18:59:31 +08:00
. find ( " select " + columns . toString ( ) + " from " + record . getStr ( " table_name " ) + " where "
2018-10-08 15:44:24 +08:00
+ record . getStr ( " id_name " ) + " in ( " + handleStr + " ) " ,
2018-09-27 16:25:51 +08:00
updateIds . toArray ( ) ) ;
//logger.info("获取所有修改数据的数据信息为"+JSON.toJSONString(updateDatas));
if ( updateDatas ! = null & & updateDatas . size ( ) > 0 ) {
2018-10-08 15:44:24 +08:00
if ( record . getStr ( " table_name " ) . equals ( " event_record_library " ) ) {
for ( Record updateData : updateDatas ) {
2018-10-17 14:32:34 +08:00
updateData . set ( " old_id " , updateData . getLong ( record . getStr ( " id_name " ) ) ) ;
2018-10-08 15:44:24 +08:00
updateData . set ( " db_id " , - 1 ) ;
2018-10-17 17:06:01 +08:00
updateData . remove ( record . getStr ( " id_name " ) ) ;
2018-10-17 09:47:57 +08:00
updateData . remove ( " sync_status " ) ;
2018-10-08 15:44:24 +08:00
}
Db . use ( url . toString ( ) ) . batchUpdate ( record . getStr ( " table_name " ) , " old_id,db_id " , updateDatas , record . getInt ( " batch_size " ) ) ;
} else {
Db . use ( url . toString ( ) ) . batchUpdate ( record . getStr ( " table_name " ) , record . getStr ( " id_name " ) ,
updateDatas , record . getInt ( " batch_size " ) ) ;
}
2018-09-27 16:25:51 +08:00
}
logger . info ( " 分库对主库修改操作的数据同步任务完成 " ) ;
} else if ( record . getInt ( " event " ) = = 3 ) {
2018-10-09 14:45:58 +08:00
for ( int i = 0 ; i < datas . size ( ) ; i + + ) {
Record deleteRecord = new Record ( ) ;
2018-10-24 18:53:05 +08:00
deleteRecord . set ( record . getStr ( " id_name " ) , datas . get ( i ) . getLong ( " target_id " ) ) ;
2018-10-09 14:45:58 +08:00
//如果是针对 event_record_library 下两行数据使用 不是则仅仅赋值 无意义
2018-10-24 18:53:05 +08:00
deleteRecord . set ( " old_id " , datas . get ( i ) . getLong ( " target_id " ) ) ;
2018-10-09 14:45:58 +08:00
deleteRecord . set ( " db_id " , - 1 ) ;
deleteRecords . add ( deleteRecord ) ;
}
2018-10-08 15:44:24 +08:00
if ( record . getStr ( " table_name " ) . equals ( " event_record_library " ) ) {
2018-10-09 14:45:58 +08:00
Db . use ( url . toString ( ) ) . batch ( " delete from event_record_library where old_id=? and db_id=? " , " old_id,db_id " , deleteRecords , record . getInt ( " batch_size " ) ) ;
2018-10-08 15:44:24 +08:00
} else {
2018-10-09 14:45:58 +08:00
Db . use ( url . toString ( ) ) . batch ( " delete from " + record . getStr ( " table_name " ) + " where " + record . getStr ( " id_name " ) + " =? " , record . getStr ( " id_name " ) , deleteRecords , record . getInt ( " batch_size " ) ) ;
2018-10-08 15:44:24 +08:00
}
2018-09-27 16:25:51 +08:00
logger . info ( " 分库对主库删除操作的数据同步完成 " ) ;
}
Object lastUpdateId = datas . get ( datas . size ( ) - 1 ) . get ( " id " ) ;
logger . info ( " 获取最后一次修改或者删除操作的数据ID信息 " + JSON . toJSONString ( lastUpdateId ) ) ;
record . set ( " last_id " , lastUpdateId ) ;
record . set ( " last_date " , new Date ( ) ) ;
Db . use ( " masterDataSource " ) . update ( " table_sync_info " , record ) ;
logger . info ( " 修改table_sync_info记录结果 用于下次同步完成 " ) ;
return true ;
}
} ) ;
}
} ) ;
} else {
flag = false ;
}
}
}
}
}
logger . info ( " 主库数据同步分库结束 " ) ;
2018-10-16 16:25:30 +08:00
logger . info ( " ***************************************************** " ) ;
2018-09-27 16:25:51 +08:00
} catch ( Exception e ) {
2018-10-23 19:34:15 +08:00
logger . error ( " 主库数据同步分库发生错误 异常信息为: " + e . getMessage ( ) ) ;
2018-09-27 16:25:51 +08:00
e . printStackTrace ( ) ;
}
}
public SyncDbInfo getSyncDbInfo ( ) {
return syncDbInfo ;
}
public void setSyncDbInfo ( SyncDbInfo syncDbInfo ) {
this . syncDbInfo = syncDbInfo ;
}
}