jdbc操做根據bean類自動組裝sql,天啦,我感受我實現了hibernate

場景:須要將從ODPS數倉中計算獲得的大額可疑交易信息導入到業務系統的mysql中供業務系統審覈。最簡單的方式是用阿里雲的組件自動進行數據同步了。可是本系統是開放是爲了產品化,要保證不一樣環境的可移植性,同時同步的表也就6個表,那麼就利用現有的基於jdbc的規則引擎工程來本身實現數據的同步。java

完整的工程代碼能夠參考個人github  https://github.com/intsmaze/SqlAdaptermysql

 JDBC手動將一個庫的數據導入到另外一個數據庫中,如何避免人工映射操做,提升開發效率

討厭的方式

查詢數據,將結果映射到javabean對象中
ps = conn.prepareStatement(select id,name,age from intsmaze);
rs = ps.executeQuery();
Intsmaze intsmaze = null;
while (rs.next()) {
    intsmaze = new Intsmaze();
    intsmaze.setId(rs.getInt(1));
    intsmaze.setName(rs.getString(2));
    intsmaze.setAge(rs.getInt(3));
}
添加數據,將javabean對象字段映射到對應的表列
String sql = "insert into intsmaze(id,name,age)  values (?,?,?)";
ps = conn.prepareStatement(sql);
ps.setInt(1, intsmaze.getId());
ps.setString(2, intsmaze.getName());
ps.setInt(3, intsmaze.getAge());
ps.executeUpdate();

使用JDBC你們都會使用上面的方式進行開發,可是若是咱們的表的字段有50個,並且查詢不能使用 select * from 必須指定列名呢?添加數據不能使用insert into intsmaze values()必須指定插入的列名呢?你乾脆殺了我吧。git

50個字段你要作2次字段列名映射,稍有不慎就會將字段列名映射到錯誤的位置,致使最後數據錯誤,最可怕的是,還要編寫sql語句,若是後面有新增或刪除列名,那麼你又要去看一眼映射關係,看看是否影響到。這就是一種費力卻沒有技術含量的事情,並且還很容易出錯。下面就是咱們要作的各類映射,你真的很考驗個人眼神。github

result.getObjectByName("FieldName")

javabean.setFieldValue()

PreparedStatement.setString(number,FieldVale)

根據javabean自動生成insert,select語句,完成字段列名映射

 

根據javabean自動生成insert,select語句,完成字段列名映射sql

 

當初開發時,一看到這麼多字段映射我煩躁不安,而後花了半天用反射把代碼從新編寫了下,後面有新的表要進行同步時,用一個工具類生成javabean的java文件,而後直接就在下面模板代碼中替換javabean類就完成了數據同步,整個操做10分鐘搞定,是否是很爽。數據庫

固然你能夠引入orm框架,可是除了hibernate框架,mybatis框架雖然免去了select和insert的映射,可是仍是要編寫前綴列名,並且我就一個小工程,我再引入ORM框架,麻不麻煩啊,有這時間還不如本身寫一寫。mybatis

public class ModelServer extends ApplicationServer {

    private static final Logger logger = LoggerFactory.getLogger(ExportBlockCustomerServer.class);
    private final static String SQL = "get_customer_infor";
    private MysqlService<TestGroup> mysqlService = new MysqlService<TestGroup>();
    @Override
    public String[] getPaths() {
        return new String[] { "com/hand/service/exe/blocktrade/blocktrade.xml" };
    }

    private int date = 1;
    @Override
    public void addOptions(Options options) {
        options.addOption("date", true, "天數");
    }
    @Override
    public void setupOptionValue(CommandLine cmd) {
        date = Integer.parseInt(cmd.getOptionValue("date", "1"));
        logger.debug("date is {}", date);
    }

    public void service() throws Exception {
        mysqlService.setMysqlDao(this.getMysqlDao());
        AmlException exception = null;
        for (int i = 1; i <= date; i++) {

            String exeSql = (String) this.getSqlMap().get(SQL);
            Result result = this.getSqlAdapter().select(this.getDao(),"SELECT * from test_group");//向odps數據倉庫查詢數據,並導入到mysql中

            String[] names = FilesNameUtils.getFiledName(new TestGroup());//獲得這個bean類的全部字段名稱,要保證bean類的字段名稱和數據庫表的列名一致
            String insertSql = SqlUtils.getInsertSql("test_group", names);//組裝成insert into test_group (id,cny,d,party_id,age) values (?,?,?,?,?)語句
            
            List<TestGroup> list = new ArrayList<TestGroup>(100);
            int number = 0;
            while (result.hasNext()) {
                result.next();
                TestGroup br = (TestGroup) tableToBean(result, i,names);//將odps查詢的數據反射到TestGroup類中,不用反射見重載函數
                list.add(br);
                number++;
                if (number % 100 == 0) {
                    try {
                        mysqlService.insert(insertSql, list, names);
                    } catch (Exception e) {
                        exception = new AmlException(e);
                    } finally {
                        list.clear();
                    }
                }
            }
            try {
                mysqlService.insert(insertSql, list, names);
                logger.info("insert data number is {}", number);
            } catch (Exception e) {
                logger.info("insert data number is {}", number);
                exception = new AmlException(e);
            } finally {
                result.close();
            }

        }
        if (exception != null) {
            throw exception;
        }
    }

    public static void main(String[] args) throws Exception {
        ModelServer applicationServer = new ModelServer();
        applicationServer.run(args);
        logger.info("execute sucess......");
        System.exit(0);
    }

    private Object tableToBean(Result result, int i, String[] names) throws Exception {
        Class clazz = TestGroup.class;
        TestGroup testGroup = (TestGroup) clazz.newInstance();
        for (int j = 0; j < names.length; j++) {
            Object object = result.getObjectByName(names[j]);
            if (object instanceof  String) {
                 Field f = clazz.getDeclaredField(names[j]);
                 f.setAccessible(true);
                 f.set(testGroup, object);
            } else if (object instanceof  Date) {
                 Field f = clazz.getDeclaredField(names[j]);
                 f.setAccessible(true);
                 f.set(testGroup, new java.sql.Date(((Date)object).getTime()));
            }
            else if (object instanceof Long) {
                 Field f = clazz.getDeclaredField(names[j]);
                 f.setAccessible(true);
                 f.set(testGroup, object);
            } 
        }
        return testGroup;
    }

    private Bigamountreport tableToBean(Result result, int i)
            throws SQLException {
        Bigamountreport bigamountreport = new Bigamountreport();
        bigamountreport.setSeqno((String) result.getObjectByName("aml_id"));
        bigamountreport.setCustomerId((String) result
                .getObjectByName("party_id"));
        ......瘋狂的set操做return bigamountreport;
    }

}

得到傳入對象的字段名稱的字符串數據,爲了拼接sql使用app

    public static String[] getFiledName(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

拼接insert的sql語句框架

public static String getInsertSql(String tableName ,String[] names)
    {
        String insertSql = StringUtils.join("insert into ",tableName ," (#{field_name}) values (#{field_value})");
        String fieldName="";
        String fieldValue="";
        for(int j = 0; j < names.length; j++)
        {
            if(j==names.length-1)
            {
                fieldName=StringUtils.join(fieldName,names[j]);
                fieldValue=StringUtils.join(fieldValue,"?");
            }
            else
            {
                fieldName=StringUtils.join(fieldName,names[j],",");
                fieldValue=StringUtils.join(fieldValue,"?",",");
            }
        }
        insertSql=insertSql.replace("#{field_name}", fieldName).replace("#{field_value}", fieldValue);
        logger.debug("the insert sql is :{}",insertSql);
        return insertSql;
    }

 

最重要的是assembleBeantoPS方法,用於根據映射字段列名ide

public class MysqlService<T> {
	private static final Logger logger = LoggerFactory.getLogger(MysqlService.class);

	private MysqlDao mysqlDao;

	public void assembleBeantoPS(PreparedStatement ps, int number,
			String FileName, Object bean) throws Exception {
		Type fileType = FilesNameUtils.getFieldType(FileName, bean);//根據屬性名稱返回字段類型
		if (fileType == String.class) {
			ps.setString(number + 1,
					(String) FilesNameUtils.getFieldValueByName(FileName, bean));
		}
		else if ("long".equals(fileType.toString()+"")) {
			ps.setLong(number + 1,(Long) FilesNameUtils.getFieldValueByName(FileName, bean));
		}
		else if (fileType == Long.class) {
			ps.setLong(number + 1,(Long) FilesNameUtils.getFieldValueByName(FileName, bean));
		}
		else if (fileType == Date.class) {
			ps.setDate(number + 1,new java.sql.Date(((Date)FilesNameUtils.getFieldValueByName(FileName, bean)).getTime()));
		}
	}

	/**
	 * @author:YangLiu
	 * @date:2017年12月25日 下午3:52:20
	 * @describe:
	 */
	public void insert(String sql, List<T> list,
			String[] names) throws Exception {
		boolean iserror=false;
		PreparedStatement ps = null;
		try {
			ps = mysqlDao.getConnection().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			for (int i = 0; i < list.size(); i++) {
				T bigamount = list.get(i);
				try{
					for (int j = 0; j < names.length; j++) {
						assembleBeantoPS(ps, j, names[j], bigamount);
					}
					ps.executeUpdate();
				}catch (Exception e) {
					iserror=true;
					logger.error("插入數據發生錯誤, occur {} ", e);
					logger.error("異常數據 {} ", bigamount);
				}
			}
		} catch (Exception e) {
			mysqlDao.getInstance().free(null, ps, mysqlDao.getConnection());
			logger.error("the sql: {} occur {} ", sql, e);
			throw new AmlException("mysql創建鏈接時發生異常");
		} finally {
			mysqlDao.getInstance().free(null, ps);
			if(iserror)
			{
				throw new AmlException("向mysql中導入數據時發生異常");
			}
		}
	}
	
	/**
	 * @deprecated
	 * @author:YangLiu
	 * @date:2017年12月25日 下午3:52:20
	 * @describe:SB寫法
	 */
	public boolean insertBatchBigamountrecord(String sql,
			List<Bigamountrecord> list) throws Exception {
		PreparedStatement ps = null;
		try {

   		    // dseqno,transOrgId,policyNo,antPolicyNo,periodPrem,transactionAmountCny,transactionAmountUsd
			ps = mysqlDao.getConnection().prepareStatement(sql,
					Statement.RETURN_GENERATED_KEYS);
			for (int i = 0; i < list.size(); i++) {
				Bigamountrecord bigamountrecord = list.get(i);
				int j = 1;
				ps.setString(j++, bigamountrecord.getDseqno());
				ps.setString(j++, bigamountrecord.getTransOrgId());
				ps.setString(j++, bigamountrecord.getPolicyNo());
				......瘋狂的set操做
				ps.addBatch();
			}
			ps.executeBatch();
		} catch (SQLException e) {
			mysqlDao.getInstance().free(null, ps, mysqlDao.getConnection());
			return false;
		} finally {
			mysqlDao.getInstance().free(null, ps);
		}
		return true;
	}
}
相關文章
相關標籤/搜索