场景:加哥最近在做项目时,苦于系统自身并未提供数据批量导入的功能还不能自行添加上该功能,且自身不想手动一条一条将数据录入系统。随后,自己使用JDBC连接数据库、使用EasyExcel插件读取表格并将数据按照业务逻辑批量插入数据库完成数据的初始化。接下来就看看加哥是怎么做的呢?
第一步:创建一个maven项目并导入依赖。
结合项目需要,只需要数据库和easyexcel的依赖包(在这里加哥使用的是mysql数据库,引入的就是mysql的数据库驱动,如果你想用sqlServer等数据库自行更换依赖就行)。
mysql mysql-connector-java 8.0.21 com.alibaba easyexcel 3.1.3
第二步:手写或者准备好JDBC连接、操作数据库的工具类。
在这里加哥是把JDBC连接数据库、操作数据库、关闭数据库封装成了工具类并用static修饰作为静态方法,方便后面使用时候直接使用类型.方法调用。
以下是数据库的驱动、url、用户名、密码定义
//驱动 private static String driver = "com.mysql.jdbc.Driver"; //URL private static String url = "jdbc:mysql://127.0.0.1:3306/mytestcharacterEncoding=utf-8&serverTimezone=Asia/Shanghai"; //用户名 private static String username = "root"; // 密码 private static String pwd = "123456";
连接数据库的方法,由于使用比较频繁将其抽取为一个独立的方法,该方法主要是加载驱动、创建连接。自己可以定义好后,在main方法中直接调用若执行通过则和数据库建立连接成功,否则失败。
/** * 创建连接 * @return */ public static Connection getConnection(){ Connection connection=null; //加载驱动 try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } //建立连接获取Connection对象 try { connection= DriverManager.getConnection(url,username,pwd); } catch (SQLException e) { e.printStackTrace(); } return connection; }
关闭连接,由于每次创建连接、都会有一个新的连接打开,如果一直不关闭就会出现连接建立满了的情况,也容易造成资源浪费,因为每次都必须关闭则也将其抽取成一个独立的方法。
/** * 关闭链接 * @param connection * @param statement * @param resultSet */ public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){ try { if(resultSet!=null){ resultSet.close(); } if(statement!=null){ statement.close(); } if (connection!=null){ connection.close(); } } catch (SQLException e) { e.printStackTrace(); } }
封装增删改方法,由于增删改调用的方法一致,则可以将其抽取成一个公用方法,在后面需要的时候直接调用该方法即可。查询方法由于每次处理的数据不一致,不适合做成公用方法。
/** * 执行增、删、改的方法 * @param sql * @return */ public static int execute(String sql){ //获取链接 Connection connection=getConnection(); int flag=0; try { //创建Statement对象 Statement statement=connection.createStatement(); //执行sql语句 flag=statement.executeUpdate(sql); //关闭链接 closeAll(connection,statement,null); } catch (SQLException e) { e.printStackTrace(); } return flag; }
最后,为了保证我们写的方法可以正常建立连接、关闭连接、完成对应操作,需要大家创建一个main方法完成测试,下面是加哥给大家提供的。但是你在测试过程中,必须保证自己的数据库及其表、表字段都存在。
/* 测试 */ public static void main(String[] args) { String sql = "SELECT * FROM bs_structure WHERE id = 1688350472671"; Connection connection = getConnection(); Statement statement = null; try { statement= connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); while(resultSet.next()){ String typename = resultSet.getString(3); System.out.println("类别名称:"+typename); } } catch (SQLException e) { e.printStackTrace(); } }
第三步、创建实体类
实体类的属性必须和excel表格的列数一致,一般有多少列就会定义多少个属性,这里的实体类就是为了后面读取表格时映射处理使用的。以下是加哥的表格式,由于模版有12列则加哥定义了12个属性。大家可以结合自己excel表格的实际情况去完成。
实体类
public class Structure { @ExcelProperty(value = "序号", index = 0) private String param1; @ExcelProperty(value = "水厂", index = 1) private String param2; @ExcelProperty(value = "工艺", index = 2) private String param3; @ExcelProperty(value = "设备", index = 3) private String param4; @ExcelProperty(value = "测点", index = 4) private String param5; @ExcelProperty(value = "点长名", index = 6) private String param6; @ExcelProperty(value = "点描述", index = 7) private String param7; @ExcelProperty(value = "设备类型名称", index = 11) private String param8; @ExcelProperty(value = "数据类型", index = 8) private String param9; @ExcelProperty(value = "小数位数", index = 9) private String param10; @ExcelProperty(value = "单位", index = 10) private String param11; @ExcelProperty(value = "测点名称", index = 5) private String param12; public String getParam1() { return param1; } public void setParam1(String param1) { this.param1 = param1; } public String getParam2() { return param2; } public void setParam2(String param2) { this.param2 = param2; } public String getParam3() { return param3; } public void setParam3(String param3) { this.param3 = param3; } public String getParam4() { return param4; } public void setParam4(String param4) { this.param4 = param4; } public String getParam5() { return param5; } public void setParam5(String param5) { this.param5 = param5; } public String getParam6() { return param6; } public void setParam6(String param6) { this.param6 = param6; } public String getParam7() { return param7; } public void setParam7(String param7) { this.param7 = param7; } public String getParam8() { return param8; } public void setParam8(String param8) { this.param8 = param8; } public String getParam9() { return param9; } public void setParam9(String param9) { this.param9 = param9; } public String getParam10() { return param10; } public void setParam10(String param10) { this.param10 = param10; } public String getParam11() { return param11; } public void setParam11(String param11) { this.param11 = param11; } public String getParam12() { return param12; } public void setParam12(String param12) { this.param12 = param12; } }
第四步、定义DAO层
在DAO层定义并实现自己需要操作数据库表的方法,加哥在这里直接在DAO层实现并区分接口和实现类,大家可以区分开来做。
public String selectParentId(String param) throws SQLException { String sql = "select id from bs_structure where structure_name='" + param + "'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } public String selectParentId1(String param,String param1) throws SQLException { String sql = "select id from bs_structure where structure_name='" + param + "' and parent_uuid= '"+param1+"'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } public String selectCedianId1(String param,String param1) throws SQLException { String sql = "select id from bs_monitor_attr where structure_uuid='" + param + "' and tag_long_name= '"+param1+"'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } public String selectObjectId(String objectType, String typename) throws SQLException { String sql = "SELECT id FROM `bs_object` where object_type='" + objectType + "' and type_name='" + typename + "'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } public String selectObjectId1(String typename) throws SQLException { String sql = "SELECT id FROM `bs_object` where type_name='" + typename + "'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } /** * 基本信息表数据填充 * * @param id * @param structureUuid * @param structureInfoCode * @param structureinfovalue * @return */ public int insertStructure(String id, String structureUuid, String structureInfoCode, String structureinfovalue) { String sql = "insert into bs_structure_info (id,structure_uuid,structure_info_code,structure_info_value) values ('" + id + "','" + structureUuid + "','" + structureInfoCode + "','" + structureinfovalue + "')"; return BaseDao.execute(sql); } public int insertSbtype(Structure structure) { Calendar cal = Calendar.getInstance(); String utcTime=String.valueOf(cal.getTimeInMillis()); String sql = "insert into bs_object (id,object_type,type_name,type_code) values ('" + utcTime + "','" + structure.getParam2() + "','" + structure.getParam3() + "','" + structure.getParam4() + "')"; Calendar cal1 = Calendar.getInstance(); String utcTime1=String.valueOf(cal1.getTimeInMillis()); String sql1 = "insert into bs_object_param (id,object_uuid,param_uuid,param_val) values ('" + utcTime1 + "','" + utcTime + "','f4ae866d-937a-11ec-9c0b-00ff8dea45f7','')"; BaseDao.execute(sql); return BaseDao.execute(sql1); } /** * 根据名称查询类型 * * @param name * @return * @throws SQLException */ public String selectSbtypeByName(String name) throws SQLException { String sql = "select id from bs_object where type_name='" + name + "'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } /** * 保存设备实例数据 * @param id * @param object_uuid * @param structure_name * @param parent_uuid * @param if_scrap * @param if_logic_delete * @param if_restrain * @param object_type * @param structure_code * @param type_name * @param if_issued * @return */ public int saveStructure(String id, String object_uuid, String structure_name, String parent_uuid, String if_scrap, String if_logic_delete, String if_restrain, String object_type, String structure_code, String type_name, String if_issued) { String sql = "INSERT INTO `bs_structure` \n" + "\t(`id`, \n" + "\t`object_uuid`, \n" + "\t`structure_name`, \n" + "\t`parent_uuid`, \n" + "\t`if_scrap`, \n" + "\t`object_type`, \n" + "\t`structure_code`, \n" + "\t`type_name`, \n" + "\t`if_issued`\n" + "\t)\n" + "\tVALUES\n" + "\t('"+id+"', \n" + "\t'"+object_uuid+"', \n" + "\t'"+structure_name+"', \n" + "\t'"+parent_uuid+"', \n" + "\t'"+if_scrap+"', \n" + "\t'"+object_type+"', \n" + "\t'"+structure_code+"', \n" + "\t'"+type_name+"', \n" + "\t'"+if_issued+"'\n" + "\t);\n"; return BaseDao.execute(sql); } /** * 插入数据 * * @param id * @param objectId * @param pointName * @param tagDescribe * @param dataType * @param readOrWrite * @param decimal * @param unit * @param inShow * @param ifshow3d * @param ifrange * @return */ public int insertObjectMonitor(String id, String objectId, String pointName, String tagDescribe, String pointType, String dataType, String readOrWrite, String decimal, String unit, String inShow, String ifshow3d, String ifrange) { String sql = "insert into bs_object_monitor_attr (id,object_id,point_name,tag_describe,point_type,data_type,read_or_write,decimal_digit,unit,if_show,if_show_3d,if_ranging) values ('" + id + "','" + objectId + "','" + pointName + "','" + tagDescribe + "','" + pointType + "','" + dataType + "','" + readOrWrite + "','" + decimal + "','" + unit + "','" + inShow + "','" + ifshow3d + "','" + ifrange + "')"; return BaseDao.execute(sql); } /** * 根据对象类型id获取测点信息数据 * * @param name * @return * @throws SQLException */ public String selectCedianInfoByobjid(String name,String name1) throws SQLException { String sql = "select id from bs_object_monitor_attr where point_name='" + name + "' and object_id='"+name1+"'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; } /** * 根据单位名称获取单位的id * @param name * @return * @throws SQLException */ public String selectUnitIdByName(String name) throws SQLException { String sql="SELECT id FROM `bs_unit` where unit_name='"+name+"'"; Connection connection = BaseDao.getConnection(); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql); String id = ""; while (resultSet.next()) { id = resultSet.getString(1); } BaseDao.closeAll(connection,statement,resultSet); return id; }
第五步、定义Service层
在Service层定义数据的保存方法,便于处理时候调用。
/** * 上一行数据的存储 */ public Structure afterData; /** * 数据持久化 * @param cachedDataList * @throws SQLException */ public void saveStructure(ListcachedDataList) throws SQLException, InterruptedException { System.out.println(cachedDataList); StructureDao structureDao =new StructureDao(); for(int i=1;i
第六步,使用EasyExcel批量读取并保存数据
大家可以打开easyexcel官网选择自己适合的读取方法,下面展示出来的仅是一种,读取数据并保存数据,在保存数据里面替换成自己的service层的保存方法即可。
String fileName = "D:\\实例表.xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 EasyExcel.read(fileName, Structure.class, new ReadListener() { /** * 单次缓存的数据量 */ public static final int BATCH_COUNT = 1000; /** *临时存储的数据 */ private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); @Override public void invoke(Structure data, AnalysisContext context) { cachedDataList.add(data); if (cachedDataList.size() >= BATCH_COUNT) { try { saveData(); } catch (SQLException | InterruptedException e) { e.printStackTrace(); }finally { // 存储完成清理 list cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } } } @Override public void doAfterAllAnalysed(AnalysisContext context) { try { saveData(); } catch (SQLException | InterruptedException e) { e.printStackTrace(); } } /** * 加上存储数据库 */ private void saveData() throws SQLException, InterruptedException { StructureService structureService=new StructureService(); structureService.saveStructure(cachedDataList); } }).sheet().doRead();
第七步,去数据库查看是否存储成功并检查数据是否正确。