场景:需要将从ODPS数仓中计算得到的大额可疑交易信息导入到业务系统的mysql中供业务系统审核。最简单的方式是用阿里云的组件自动进行数据同步了。但是本系统是开放是为了产品化,要保证不同环境的可移植性,同时同步的表也就6个表,那么就利用现有的基于jdbc的规则引擎工程来自己实现数据的同步。

完整的工程代码可以参考我的github  https://github.com/intsmaze/SqlAdapter

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()必须指定插入的列名呢?你干脆杀了我吧。

50个字段你要做2次字段列名映射,稍有不慎就会将字段列名映射到错误的位置,导致最后数据错误,最可怕的是,还要编写sql语句,如果后面有新增或删除列名,那么你又要去看一眼映射关系,看看是否影响到。这就是一种费力却没有技术含量的事情,而且还很容易出错。下面就是我们要做的各种映射,你真的很考验我的眼神。

result.getObjectByName("FieldName")

javabean.setFieldValue()

PreparedStatement.setString(number,FieldVale)

根据javabean自动生成insert,select语句,完成字段列名映射

根据javabean自动生成insert,select语句,完成字段列名映射

当初开发时,一看到这么多字段映射我烦躁不安,然后花了半天用反射把代码重新编写了下,后面有新的表要进行同步时,用一个工具类生成javabean的java文件,然后直接就在下面模板代码中替换javabean类就完成了数据同步,整个操作10分钟搞定,是不是很爽。

当然你可以引入orm框架,但是除了hibernate框架,mybatis框架虽然免去了select和insert的映射,但是还是要编写前缀列名,而且我就一个小工程,我再引入ORM框架,麻不麻烦啊,有这时间还不如自己写一写。

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使用

    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方法,用于根据映射字段列名

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;
}
}

jdbc操作根据bean类自动组装sql,天啦,我感觉我实现了hibernate的更多相关文章

  1. spring Bean类自动装载实现

    先贴spring的开发文档,有助于大家学习http://shouce.jb51.net/spring/beans.html#beans-factory-class 一直想研究一下spring bean ...

  2. 如何通过注解Bean类来封装SQL插入语句

    整体思路是酱紫的: 给bean上注解说明该bean对应着数据库中哪张表,给每个bean的属性都注解说明各自对应着这张表的哪个字段. 通过类反射获取表名,通过逐个反射每个属性的getter方法,获取注解 ...

  3. JDBC操作数据库工具类(使用阿里Druid原生API创建数据源)

    1.数据库配置类 package com.zdlt.auth.api.common.druid; import java.util.Properties; import static com.alib ...

  4. Java使用Jdbc操作MySql数据库(一)

    这个示例是Java操作MySql的基本方法. 在这个示例之前,要安装好MySql,并且配置好账户密码,创建一个logininfo数据库,在数据库中创建userinfo数据表.并且在表中添加示例数据. ...

  5. Java基础之原生JDBC操作数据库

    前言 日常开发中,我们都习惯了使用ORM框架来帮我们操作数据库,本文复习.记录Java如何使用原生JDBC操作数据库 代码编写 封装几个简单方法 find查询方法 findOne查询方法 update ...

  6. JDBC操作MySQL数据库案例

    JDBC操作MySQL数据库案例 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Prepared ...

  7. 玩转Spring全家桶笔记 03 Spring的JDBC操作以及SQL批处理的实现

    1 spring-jdbc core JdbcTemplate 等相关核心接口和类(核心) datesource 数据源相关的辅助类(内嵌数据源的初始化) object 将基本的JDBC操作封装成对象 ...

  8. jdbc mysql crud dao模型 sql注入漏洞 jdbc 操作大文件

    day17总结 今日内容 l JDBC 1.1 上次课内容总结 SQL语句: 1.外键约束:foreign key * 维护多个表关系! * 用来保证数据完整性! 2.三种关系: * 一对多: * 一 ...

  9. 用于JDBC操作数据库的公共类

    /* * @(#)CommonSql.java 2011-9-5 * * Copyright 2011 Bianjing,All rights reserved. */ import java.sql ...

随机推荐

  1. 在 Azure Resource Manager 模板中使用托管磁盘

    本文介绍使用 Azure Resource Manager 模板预配虚拟机时托管与非托管磁盘之间的差异. 这有助于将现有模板从使用非托管磁盘更新为使用托管磁盘. 我们将使用 101-vm-simple ...

  2. python3 邮件发送

    这是搜罗网络上的文章总结的一份文档, 参考: https://www.jb51.net/article/140604.htm https://www.jb51.net/article/140604.h ...

  3. 洗礼灵魂,修炼python(52)--爬虫篇—【转载】爬虫工具列表

    与爬虫相关的常用模块列表. 原文出处:传送门链接 网络 通用 urllib -网络库(stdlib). requests -网络库. grab – 网络库(基于pycurl). pycurl – 网络 ...

  4. Web的攻击技术笔记

    HTTP不具备必要的安全功能,就是一个通用的单纯协议机制,比如远程登录时会用到的SSH协议来说,SSH具备协议级别的认证及回话管理等功能,HTTP协议则没有.另外在架设SSH服务方面,任何人都可以轻易 ...

  5. 4.1Python数据处理篇之Matplotlib系列(一)---初识Matplotlib

    目录 目录 前言 (一)matplotlib的介绍 (二)画一个简单的画布 ==1.源代码== ==2.展示效果== (三)画布按键的功能介绍 ==1.对于画布功能键的排序== ==(1)主页== = ...

  6. Alpha冲刺! Day7 - 砍柴

    Alpha冲刺! Day7 - 砍柴 今日已完成 晨瑶:列了各模块目前的进度情况:确定了纯多媒体流星预览页的显示方式:给工具包函数列表新增了与服务器端的交互:玩华为软件云发现刚好可以试试它的测试,于是 ...

  7. java集合类List

    1.List Vector:线程安全的. ArrayList:适合查找与顺序添加. LinkedList:适合随机插入与删除. 1.1ArrayList与LinkedList的add添加 1.1.1A ...

  8. PyQt5--QComboBox

    # -*- coding:utf-8 -*- ''' Created on Sep 20, 2018 @author: SaShuangYiBing Comment: ''' import sys f ...

  9. css理论

    1css语法 2css的四种引入方式 3css选择器 4css四种属性操作 5float属性操作 6盒子模型 1 css语法 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明. '' se ...

  10. python 之 递归

    终于来到了这里,这是一座山,山那边都是神仙 定义:在一个函数里调用函数本身 最好的例子就是,求阶乘 def factorial(n): if n == 1: return 1 elif n > ...