tiangong-doc tiangong-doc
首页
  • 天宫体系

    • 前端架构
    • 后端架构
    • 扩展功能
    • 打包部署
    • 更新日志
    • 辅助开发平台 (opens new window)
    • 权限平台部署包下载 (opens new window)
  • 基础组件

    • 工作流引擎(待整理)
    • 跨境加签客户端(待整理)
    • 权限平台(待整理)
  • 数字化工具

    • 数字魔方
    • 数据采集
    • 智能导入
    • 数字员工
    • 规则引擎(开发中)
    • 消息引擎(待开发)
    • 智能导出(待开发)
  • 业务算法

    • 南京业务体检(待整理)
    • 智慧长江(待整理)
  • 识别模型

    • 空箱识别(待整理)
    • 智能客服(待整理)
    • OCR识别(待整理)
    • 车牌识别(待整理)
    • 超市停留识别(待整理)
    • 危险品识别(待开发)
    • 超长车识别(待开发)
    • 车辆靠台(待开发)
    • 车辆占用(待开发)
  • 算法模型(待整理)
  • 风控模型(待整理)
  • 海关规则(待整理)
  • 危险品知识(待整理)
  • 组件设计文档(待整理)
  • 数据服务

    • 商品归类服务(待开发)
    • RECP贸易服务(待开发)
    • 商品价格服务(待开发)
    • 业务申报解答(待开发)
    • 报关单状态查询(待开发)
  • 常用开发工具

    • BASE64编解码工具 (opens new window)
    • MD5编码工具 (opens new window)
    • AES/DES加解密 (opens new window)
    • JWT解码工具 (opens new window)
    • ASCII编解码工具 (opens new window)
    • Unicode编解码工具 (opens new window)
    • UTF-8编解码工具 (opens new window)
    • 字符串编解码工具 (opens new window)
    • 通用进制转换工具 (opens new window)
    • 浮点数十进制转换 (opens new window)
    • 在线JSON解析 (opens new window)
    • 在线JS代码格式化工具 (opens new window)
    • CSS可视化工具 (opens new window)
    • XML格式化工具
    • SQL压缩/格式化工具 (opens new window)
    • JSON/XML在线转换 (opens new window)
    • JSON/YAML在线转换 (opens new window)
    • IP地址查询 (opens new window)
    • HTTP在线接口测试 (opens new window)
    • UUID在线生成器 (opens new window)
    • 随机数生成器 (opens new window)
    • 在线文本比对 (opens new window)
  • 研发标准规范(待整理)
  • 国产化适配
首页
  • 天宫体系

    • 前端架构
    • 后端架构
    • 扩展功能
    • 打包部署
    • 更新日志
    • 辅助开发平台 (opens new window)
    • 权限平台部署包下载 (opens new window)
  • 基础组件

    • 工作流引擎(待整理)
    • 跨境加签客户端(待整理)
    • 权限平台(待整理)
  • 数字化工具

    • 数字魔方
    • 数据采集
    • 智能导入
    • 数字员工
    • 规则引擎(开发中)
    • 消息引擎(待开发)
    • 智能导出(待开发)
  • 业务算法

    • 南京业务体检(待整理)
    • 智慧长江(待整理)
  • 识别模型

    • 空箱识别(待整理)
    • 智能客服(待整理)
    • OCR识别(待整理)
    • 车牌识别(待整理)
    • 超市停留识别(待整理)
    • 危险品识别(待开发)
    • 超长车识别(待开发)
    • 车辆靠台(待开发)
    • 车辆占用(待开发)
  • 算法模型(待整理)
  • 风控模型(待整理)
  • 海关规则(待整理)
  • 危险品知识(待整理)
  • 组件设计文档(待整理)
  • 数据服务

    • 商品归类服务(待开发)
    • RECP贸易服务(待开发)
    • 商品价格服务(待开发)
    • 业务申报解答(待开发)
    • 报关单状态查询(待开发)
  • 常用开发工具

    • BASE64编解码工具 (opens new window)
    • MD5编码工具 (opens new window)
    • AES/DES加解密 (opens new window)
    • JWT解码工具 (opens new window)
    • ASCII编解码工具 (opens new window)
    • Unicode编解码工具 (opens new window)
    • UTF-8编解码工具 (opens new window)
    • 字符串编解码工具 (opens new window)
    • 通用进制转换工具 (opens new window)
    • 浮点数十进制转换 (opens new window)
    • 在线JSON解析 (opens new window)
    • 在线JS代码格式化工具 (opens new window)
    • CSS可视化工具 (opens new window)
    • XML格式化工具
    • SQL压缩/格式化工具 (opens new window)
    • JSON/XML在线转换 (opens new window)
    • JSON/YAML在线转换 (opens new window)
    • IP地址查询 (opens new window)
    • HTTP在线接口测试 (opens new window)
    • UUID在线生成器 (opens new window)
    • 随机数生成器 (opens new window)
    • 在线文本比对 (opens new window)
  • 研发标准规范(待整理)
  • 国产化适配
  • 天宫架构

    • 前端架构

    • 后端架构

      • 后端基础功能

        • 天宫框架简介
        • 用户相关
        • 使用文档
        • 增删改查
          • 查看sql
          • 新增
          • 删除
          • 更新
          • 查询
            • 查询一个列表
            • 分页查询
            • outSql
            • 查一条记录
            • 查找个数
            • 是否存在
            • 分组查询
            • 多表关联查询
            • 表结构展示
            • 实体类 entity
            • 数据访问层 dao
            • mybatis xml
            • 业务层 service
            • 访问层 controller
            • 请求参数JSON
          • DBHelper
            • 查询
            • 增删改
            • 切换数据源
      • 开发脚本

    • 打包部署

    • 扩展功能

    • 业务组件

    • 国际化

    • 迁移助手

    • 历史版本

    • 更新日志

    • 开发手册

    • 权限平台

  • 基础架构
  • 天宫架构
  • 后端架构
  • 后端基础功能
2023-06-01
目录

增删改查

# 天宫框架方法

以下方法框架core需要升级到 2.2.1_release

# 查看sql

天宫框架的sql都是参数化的, 为了方便开发, 经常需要拿到完整的sql

这里推荐一款插件 MyBatis Log Free

image-20240403094245099

底部工具栏展示sql

image-20240403094413622

image-20240403094436988

里面就有项目运行过程中的sql了

image-20240403094454822

# 新增

image-20240403091947444

  • 插入一条 insert / insertOne
  • 插入一组集合 insertList

这里批量插入的方式比较简单, 直接采用的是mybatis的 BATCH方式, 性能不是很高, 好在比较通用

如果批量插入的数据量非常非常大, 并且对性能要求很高的, 建议采用原生JDBC来操作

# 删除

框架已有的方法

image-20240403092959168

  • 删除by主键
  • 批量删除by主键字符串, 例如: id1,id2,id3
  • 删除by实体, 前提也是实体的主键得有值
  • 删除by数据库列名, 例如: (I_E_FLAG, "I")
  • 批量删除by主键, 传入一个集合

开发人员可扩展的方法

appGenDao.delete()
         .eq(AppGenEntity::getId,9527)
         .eq(AppGenEntity::getName,"1hello10")
         .execute();

//sql如下:
//DELETE FROM app_gen WHERE (id = 9527 AND name = '1hello10')
1
2
3
4
5
6
7

使用lambda的方式, 可以构造各种各样的删除语句, 属于自由发挥了, 基本都够用了

建议删除还是要根据主键id来删

批量删除建议分两步走, 先查出来要删除的id集合, 然后根据id集合批量删

# 更新

更新主要还是根据主键id来更新, 更新涉及到nul值需不需要更新的问题

// 更新方法
appGenDao.updateByEntityId(entity);
1
2

框架提供了6种更新策略, 枚举类UpdateStrategy

public enum UpdateStrategy {

    /**
     * 整个对象全量更新
     */
    FULL,

    /**
     * 指定字段全量更新, 其他字段不更新
     */
    FULL_OF_SPECIFIED_FIELDS,

    /**
     * 整个对象非null更新 (默认)
     */
    NONULL,

    /**
     * 指定字段非null的才更新, 其他字段不更新
     */
    NONULL_OF_SPECIFIED_FIELDS,

    /**
     * 指定全量, 其余非null
     */
    SPECIFIED_FULL_OTHER_NONULL,

    /**
     * 指定非null, 其余全量
     */
    SPECIFIED_NONULL_OTHER_FULL
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
策略名称 更新字段 更新值策略 说明
FULL 实体所有字段 不管值是什么包括null均更新 对整个对象更新
FULL_OF_SPECIFIED_FIELDS 实体类指定的字段 不管值是什么包括null均更新 指定字段全量更新, 其他字段不更新
NONULL 实体所有字段 不为null的才更新 整个对象非null字段更新 (框架默认)
NONULL_OF_SPECIFIED_FIELDS 实体类指定的字段 不为null的才更新, 其他字段不更新 指定字段非null的才更新, 其他字段不更新
SPECIFIED_FULL_OTHER_NONULL 实体类指定的字段 指定字段的包括null均更新, 其他非null更新 指定全量, 其余非null
SPECIFIED_NONULL_OTHER_FULL 实体类指定的字段 指定字段的非null更新, 其他字段全部更新 指定非null, 其余全量

如果需要指定策略

// 1. 指定策略SPECIFIED_NONULL_OTHER_FULL
entity.setUpdateStrategy(UpdateStrategy.SPECIFIED_NONULL_OTHER_FULL);

// 2. 指定哪些字段是非null更新的, 这里使用驼峰,不是下划线
entity.setEffectFields("name,custCode,gNo");

// 3. 将对象丢给方法
appGenDao.updateByEntityId(entity);
1
2
3
4
5
6
7
8

# 查询

# 查询一个列表

List<AppGenEntity> list = appGenDao
                .select()
                //.select("id", "g_no")
                //.select(AppGenEntity::getId, AppGenEntity::getiEFlag)
                .eq(AppGenEntity::getiEFlag, "E")
                .eq("id", 212)
                .gt(AppGenEntity::getPrice, 2)
                .between("create_time", new Date(), new Date())
                .likeLeft(AppGenEntity::getName, "hello")
                .orderByAsc(AppGenEntity::getId)
                .and(item -> {
                    item.eq(AppGenEntity::getCustCode, "1").or().
                            eq(AppGenEntity::getCustCode, "2");
                })
                .list();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 实际sql语句
SELECT id,name,cust_code,used_flag,price,i_e_flag,g_no,create_time,detail 
FROM app_gen A 
WHERE (
    i_e_flag = 'E' 
    AND id = 212 AND price > 2 
    AND create_time BETWEEN '2024-04-03 10:31:34.177' AND '2024-04-03 10:31:34.177' 
    AND name LIKE '%hello' 
    AND (cust_code = '1' OR cust_code = '2')) 
ORDER BY id ASC
1
2
3
4
5
6
7
8
9
10

select() 可以指定查哪些列, 不写就是查全部的列

.and 实际上是开了一个括号, 将 or的条件放在了里面

符号 文字描述
eq 等于
ne 不等于
gt 大于
lt 小于
ge 大于等于
le 小于等于
like %模糊%
notLike 不包含
leftLike %左模糊
rightLike 右模糊%
isNull 字段为空
isNotNull 字段不为空
between 范围
in 数据库in
notIn 数据库not in
inSql in (一段sql)
orderByAsc 正序
orderByDesc 倒叙
groupBy 分组
exists 存在
notExists 不存在
appendSql 拼接字符串sql

参数说明:

可以传lambda表达式 如: AppGenEntity::getiEFlag

可以传数据库字段字符串, 如: create_time, 这里是数据库的字段

# 分页查询

// 分页参数为: 前端上下文中的分页参数
TgPageInfo<AppGenEntity> page = appGenDao
                .select("id", "g_no")
                .eq(AppGenEntity::getiEFlag, "E")
                .eq("id", 212)
                .page();

// 自己指定分页参数, 第1页, 取50条
TgPageInfo<AppGenEntity> page = appGenDao
                .select("id", "g_no")
                .eq(AppGenEntity::getiEFlag, "E")
                .eq("id", 212)
                .page(1,50);
1
2
3
4
5
6
7
8
9
10
11
12
13

说明:

如果是自定义的语句, 并没有.page()方法, 仍然需要分页, 则需要手动调一次 startPage() 方法

# outSql

有个需求, 就是我们希望用分页后的结果再去关联别的表, 形成一个结果集

public TgPageInfo queryPageList(AppGenEntity entity) {
    // 指定 outSql 的sql语句
    DBHelper.setOutSql("(SELECT PARA_NAME FROM sys_parameters WHERE PARA_CODE = A.used_flag and para_type ='g2_sck_modf_markcd') para_name ");

    // 之前通用的方法
    EciQuery<AppGenEntity> eciQuery = EciQuery.buildQuery(entity);
    List<AppGenEntity> entities = appGenDao.queryPageList(eciQuery);
    return EciQuery.getPageInfo(entities);
}
1
2
3
4
5
6
7
8
9

最终的sql语句

SELECT
	A.*,
	( SELECT PARA_NAME FROM sys_parameters WHERE PARA_CODE = A.used_flag AND para_type = 'g2_sck_modf_markcd' ) para_name 
FROM
	(
	SELECT
		id,
		NAME,
		cust_code,
		used_flag,
		price,
		i_e_flag,
		g_no,
		create_time,
		detail 
	FROM
		app_gen A 
	WHERE
		( A.NAME LIKE '%hello%' AND A.CREATE_TIME BETWEEN '2022-02-15 00:00:00.0' AND '2024-05-15 23:59:59.0' ) 
	ORDER BY
		A.price ASC,
		A.cust_code DESC 
	LIMIT 10 
	) A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

说明:

有个约定: A特指原表的结果集别名

这个种方案我本人并不推荐使用

  1. sql较原先相比, 更加复杂, 不易于阅读
  2. 关联查询影响sql的执行效率, 存在性能问题

优化建议:

  1. 如果关联表数据基本不变, 使用框架提供的代码名称转换去解决
  2. 将分页的结果集取出, 在程序层面使用 select xxx from 子表 where key in (xx), 后台对结果做一次组装, 然后返回给前端

# 查一条记录

AppGenEntity one = appGenDao
                .select("id", "g_no")
                .one();
1
2
3

# 查找个数

Long count = appGenDao
                .select("id")
                .eq(AppGenEntity::getiEFlag, "E")
                .count();
1
2
3
4

# 是否存在

boolean exists = appGenDao
                .select( "g_no")
                .eq(AppGenEntity::getiEFlag, "E")
                .eq("id", 214)
                .exists();
1
2
3
4
5

# 分组查询

List<AppGenEntity> list = appGenDao
                .select("i_e_flag", "sum(price) as price")
                .eq(AppGenEntity::getUsedFlag,entity.getUsedFlag())
                .groupBy(AppGenEntity::getiEFlag)
                .list();
1
2
3
4
5
// 执行的sql
SELECT i_e_flag,sum(price) as price FROM app_gen A WHERE (used_flag =  '1' ) GROUP BY i_e_flag
1
2

注意事项:

  1. select里面的字段得写成sql里面的片段, 结果需要使用实体类中存在的字段去接受
  2. 其他条件正常拼接
  3. 语义满足sql规范

# 多表关联查询

场景说明:

  1. 表头关联表体
  2. 还想使用__queryField动态拼接查询参数
  3. 列表展示, 查询条件 同时存在表头和表体的字段

# 表结构展示

表头: app_gen

image-20240226170449522

表体: app_gen_list

app_gen_id 为表头的id

image-20240226170533956

# 实体类 entity

这里我建了一个实体类AppGenFull, 里面包含了表头和表体以及后面可能查询或展示的时候会用到的字段

public class AppGenFull extends EciBaseEntity {

    /**
     * 主键
     */
    @ApiModelProperty("主键(19)")
    @TableId("id")
    private Long id;

    /**
     * 名字
     */
    @ApiModelProperty("名字(1,020)")
    @TableField("name")
    private String name;

    /**
     * 代码
     */
    @ApiModelProperty("代码(1,020)")
    @TableField("cust_code")
    private String custCode;

    /**
     * 标记
     */
    @ApiModelProperty("标记(1,020)")
    @TableField("used_flag")
    private String usedFlag;

    /**
     * 价格
     */
    @ApiModelProperty("价格(12)")
    @TableField("price")
    private BigDecimal price;

    /**
     * 进出口|I=进口,E=出口,IE=进出口
     */
    @ApiModelProperty("进出口|I=进口,E=出口,IE=进出口(20)")
    @TableField("i_e_flag")
    private String iEFlag;

    /**
     * 商品编号
     */
    @ApiModelProperty("商品编号(40)")
    @TableField("g_no")
    private String gNo;

    /**
     * 创建时间
     */
    @ApiModelProperty("创建时间(0)")
    @TableField("create_time")
    private Date createTime;

    @ApiModelProperty("创建时间开始")
    @TableField(exist=false)
    private Date createTimeStart;

    @ApiModelProperty("创建时间结束")
    @TableField(exist=false)
    private Date createTimeEnd;


    /**
     * 监管方式
     */
    @ApiModelProperty("监管方式(8)")
    @TableField("trade_mode")
    private String tradeMode;

    /**
     * 商品编码
     */
    @ApiModelProperty("商品编码(10)")
    @TableField("code_ts")
    private String codeTs;

    /**
     * 贸易国别
     */
    @ApiModelProperty("贸易国别(10)")
    @TableField("country")
    private String country;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

# 数据访问层 dao

这里自定义一个方法selectHeadBodyList

public interface AppGenDao extends EciBaseDao<AppGenEntity> {
	
    // 自定义sql: 用户列表展示的查询方法
    List<AppGenFull> selectHeadBodyList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
}
1
2
3
4
5

说明:

参数: queryWrapper是封装查询条件的对象, 直接照着写就行了

返回: 就是一个全量的查询对象集合

# mybatis xml

<select id="selectHeadBodyList" parameterType="com.baomidou.mybatisplus.core.conditions.Wrapper"
        resultType="com.eci.project.appGen.entity.AppGenFull">
    select 
    	h.id,h.name,h.cust_code, h.used_flag,h.price, h.i_e_flag, h.g_no, h.create_time,
    	b.trade_mode,b.country,b.code_ts
    from  
    	app_gen h
    left join app_gen_list b on h.id = b.app_gen_id
    ${ew.customSqlSegment}
</select>
1
2
3
4
5
6
7
8
9
10

说明:

h: 表头 b: 表体

select标签为查询标签

id: 就是dao层的查询方法

parameterType: 参数类型, 就是dao传进来的参数

resultType: 返回类型, 就是上面定义的一个比较全的实体类

${ew.sqlSegment}: 参数占位, 这里面有前端发送的__queryField参数, 照着写就行

# 业务层 service

@Override
public TgPageInfo selectPageListFull(AppGenFull entity) {
    
    // 获取eciQuery对象
    EciQuery<AppGenEntity> eciQuery = EciQuery.buildQuery(entity);
    
    // 开始分页, 自定义的方法, 自己决定是否要分页
    startPage();
    
    // 调用自定义的dao查询方法
    List<AppGenFull> appGenFulls = appGenDao.selectHeadBodyList(eciQuery);
    
    // 将返回参数用分页器封装一下
    return EciQuery.getPageInfo(appGenFulls);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 访问层 controller

@ApiOperation("测试代码生成:分页查询列表")
@EciLog(title = "测试代码生成:分页查询列表", businessType = BusinessType.SELECT)
@PostMapping("/selectPageListFull")
public ResponseMsg selectPageListFull(@RequestBody AppGenFull entity){
    return ResponseMsgUtil.successPlus(10001,appGenService.selectPageListFull(entity));
}
1
2
3
4
5
6

说明:

我这里是重新命名了一个方法, 当然, 也可以直接覆盖selectPageList方法

# 请求参数JSON

{
    "type": "1",
    "paging": {
        "pageSize": 10,
        "pageNum": 1,
        "sortFields": [
            {
                "sortField": "h.price",
                "asc": true
            },
            {
                "sortField": "h.custCode",
                "asc": false
            }
        ]
    },
    "entity": {
        "name": "hello",
        "createTimeStart": "2023-02-15",
        "createTimeEnd": "2024-03-15",
        "__queryField": "name|h.NAME|s|l|and,createTime|b.CREATE_TIME|d|between|and"
    },
    "query": {
        "totalColumn": "",
        "selectColumns": ""
    },
    "tgTime": 13213123,
    "businessType": "SELECT"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

说明:

"__queryField": "name|h.NAME|s|l|and,createTime|b.CREATE_TIME|d|between|and"

由于是多表, 别名位置不能写错, 一定要写sql中自己取的那个别名

# DBHelper

这里提供了直接操作数据库的方法

# 查询

List<AppGenEntity> appGenEntities = DBHelper.selectList(
            "select id,name,cust_code,used_flag,price,i_e_flag,g_no,create_time from app_gen where name like ? and g_no = ?",
            AppGenEntity.class,
            "%hello%", "1");
1
2
3
4

参数说明:

1 sql语句, 变量写 ?

2 将数据封装到一个实体类中, 实体类的class

3 可变参数列表

# 增删改

DBHelper.execute("update app_gen set used_flag = '1' where id = 2");
1

# 切换数据源

// 切换ds
public void changeDs(String dsName);

// 会话级切换数据源
public void changeSessionDs(String dsName);

// 全局切换数据源
public void changeGlobalDs(String dsName);

// 是否有该数据源
public boolean hasDs(String dsName);
1
2
3
4
5
6
7
8
9
10
11

多数据源切换, 需要加入天宫多数据源模块, tiangong-dynamicds

上次更新: 2024/6/12 11:34:10
使用文档
MySQL初始化

← 使用文档 MySQL初始化→

最近更新
01
EciReport模板导出_Core
09-10
02
EciReport模板导出
09-09
03
Core权限平台接口
07-25
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式