NC65数据库操作全攻略:前后台查询与增删改实战(附防SQL注入技巧)
NC65数据库操作全攻略:前后台查询与增删改实战(附防SQL注入技巧)
在NC65企业级应用开发中,数据库操作是最基础也是最重要的技能之一。不同于常规的JDBC或ORM框架,NC65平台提供了自己独特的数据库访问机制,涵盖了从前台UI层到后台服务层的完整解决方案。本文将深入剖析这些技术细节,帮助开发者快速掌握核心要领。
1. 前台数据库操作精要
前台操作通常指运行在客户端(如浏览器)的代码逻辑,NC65通过IUAPQueryBS服务提供标准化的查询能力。这个设计巧妙地将复杂的SQL执行过程封装成简单的API调用,同时支持多种结果处理方式。
基础查询示例:
IUAPQueryBS queryBS = NCLocator.getInstance().lookup(IUAPQueryBS.class); String sql = "SELECT * FROM bd_material WHERE nvl(dr,0)=0"; List<Map<String,Object>> result = queryBS.executeQuery(sql, new MapListProcessor());常用的结果处理器包括:
MapListProcessor:返回List<Map>结构,适合动态字段场景BeanListProcessor:自动映射到VO对象集合ColumnProcessor:提取单列数据ArrayListProcessor:原始Object[]数组格式
提示:前台查询应避免大结果集,建议通过WHERE条件精确控制数据量
对于单据类操作,推荐使用封装好的高阶API:
// 通过主键获取单据AGGVO SalesOrderVO billVO = HYPubBO_Client.queryBillVOByPrimaryKey( SalesOrderVO.class, "1001A110000000000ABC" );2. 后台数据库操作深度解析
后台操作通常指服务端私有方法,具有更高的灵活性和性能优势。BaseDAO是核心工具类,支持完整的CRUD操作。
2.1 查询操作模式对比
| 方法 | 返回类型 | 适用场景 | 示例 |
|---|---|---|---|
| executeQuery+ArrayListProcessor | List<Object[]> | 原始数据查询 | 多表联合查询 |
| executeQuery+MapProcessor | Map<String,Object> | 单行记录 | 主键精确查询 |
| executeQuery+BeanListProcessor | List | 业务对象集合 | 单据列表查询 |
| executeQuery+自定义Processor | 任意类型 | 特殊数据处理 | 树形结构构建 |
典型查询示例:
// 获取单行记录 String sql = "SELECT * FROM bd_supplier WHERE pk_supplier=?"; SQLParameter param = new SQLParameter(); param.addParam("1001A110000000000XYZ"); Map<String,Object> supplier = (Map<String,Object>)baseDAO.executeQuery( sql, param, new MapProcessor() ); // 获取VO对象集合 String hql = "FROM MaterialVO WHERE materialType=?"; List<MaterialVO> materials = (List<MaterialVO>)baseDAO.executeQuery( hql, new SQLParameter("RAW"), new BeanListProcessor(MaterialVO.class) );2.2 增删改操作要点
更新操作需要特别注意事务管理:
try { baseDAO.startTransaction(); // 插入操作 String insertSQL = "INSERT INTO bd_department(pk_dept,dept_code) VALUES(?,?)"; SQLParameter insertParam = new SQLParameter(); insertParam.addParam(UUID.randomUUID().toString()); insertParam.addParam("DEPT_001"); baseDAO.executeUpdate(insertSQL, insertParam); // 更新操作 String updateSQL = "UPDATE bd_department SET dept_name=? WHERE pk_dept=?"; SQLParameter updateParam = new SQLParameter(); updateParam.addParam("研发中心"); updateParam.addParam("1001A110000000000KKK"); baseDAO.executeUpdate(updateSQL, updateParam); baseDAO.commit(); } catch(Exception e) { baseDAO.rollback(); throw e; }3. 前后台通用操作方案
对于需要前后台复用的数据库逻辑,NC65提供了中间层服务抽象。IBillQueryService是最常用的接口之一:
// 获取服务实例 IBillQueryService queryService = NCLocator.getInstance().lookup(IBillQueryService.class); // 执行分页查询 PageCond page = new PageCond(1, 20); String countSQL = "SELECT COUNT(*) FROM bd_customer"; String dataSQL = "SELECT * FROM bd_customer"; SQLParameter param = new SQLParameter(); param.addParam("ACTIVE"); QueryResult result = queryService.queryWithPage( countSQL, dataSQL, param, page, new MapListProcessor() );性能优化建议:
- 对于大数据量查询,务必使用分页机制
- 频繁访问的数据考虑使用平台缓存
- 复杂查询建议在后台实现
4. SQL注入防御实战
安全是数据库操作的重中之重,NC65提供了多重防护机制:
4.1 参数化查询标准写法
StringBuilder sql = new StringBuilder(); sql.append("SELECT * FROM bd_user "); sql.append("WHERE user_code=? "); sql.append("AND nvl(dr,0)=?"); SQLParameter param = new SQLParameter(); param.addParam("admin"); // 用户输入参数 param.addParam(0); // 系统参数 List<UserVO> users = (List<UserVO>)baseDAO.executeQuery( sql.toString(), param, new BeanListProcessor(UserVO.class) );4.2 动态SQL安全构建
对于条件不固定的查询,推荐使用安全拼接方式:
SQLBuilder builder = new SQLBuilder("SELECT * FROM bd_warehouse WHERE 1=1"); if(StringUtils.isNotEmpty(warehouseCode)){ builder.append(" AND warehouse_code=:code"); builder.setParameter("code", warehouseCode); } if(StringUtils.isNotEmpty(warehouseType)){ builder.append(" AND warehouse_type=:type"); builder.setParameter("type", warehouseType); } List<WarehouseVO> warehouses = (List<WarehouseVO>)baseDAO.executeQuery( builder.toString(), builder.getParameters(), new BeanListProcessor(WarehouseVO.class) );4.3 输入验证策略
白名单校验:对编码类字段使用正则验证
if(!Pattern.matches("[A-Z0-9_]{1,20}", userInput)){ throw new BusinessException("输入格式不符合要求"); }类型强制转换:数字型参数必须转换
try { Integer.parseInt(inputQty); } catch(NumberFormatException e) { // 异常处理 }长度限制:防止超长字符串攻击
if(inputString.length() > 100){ inputString = inputString.substring(0,100); }
5. 高级技巧与最佳实践
5.1 批量操作优化
对于大批量数据操作,建议使用批处理模式:
baseDAO.startTransaction(); try { String sql = "UPDATE bd_inventory SET qty=qty+? WHERE pk_material=?"; BatchSQLParameter batchParam = new BatchSQLParameter(); for(InventoryUpdate item : updateList){ SQLParameter param = new SQLParameter(); param.addParam(item.getDeltaQty()); param.addParam(item.getMaterialId()); batchParam.addBatch(param); } int[] results = baseDAO.executeBatch(sql, batchParam); baseDAO.commit(); } catch(Exception e) { baseDAO.rollback(); throw e; }5.2 存储过程调用
NC65平台支持存储过程的标准调用方式:
String callSQL = "{call pkg_business.proc_calculate(?,?,?)}"; SQLParameter param = new SQLParameter(); param.addParam("202301"); param.addParam("FACTORY_001"); param.addParam(0); // 输出参数注册 Object result = baseDAO.executeQuery(callSQL, param, new ColumnProcessor());5.3 元数据查询技巧
获取表结构信息:
String metaSQL = "SELECT column_name,data_type FROM user_tab_columns WHERE table_name=?"; List<Map<String,Object>> columns = (List<Map<String,Object>>)baseDAO.executeQuery( metaSQL, new SQLParameter("BD_MATERIAL"), new MapListProcessor() );在实际项目中,我们发现将常用查询封装成工具方法可以显著提升开发效率。比如创建一个DBUtil类,包含各种标准的单条查询、列表查询、分页查询等方法。这样既保证了代码规范,又减少了重复劳动。
