【问题标题】:JpaRepository findBy query (SELECT) is updating records in the DBJpaRepository findBy 查询 (SELECT) 正在更新数据库中的记录
【发布时间】:2021-04-24 22:36:32
【问题描述】:

最近我们遇到了一个问题,即数据库中的记录正在更新,而我们只通过 java api 进行读取操作。下面是我们springboot应用的代码sn-p

public List<ResultDto> getSomethingByColumnA(String arg1, String arg2, String arg3)
   return myRepo.findSomethingByColumnA(param1, param2, param3, ResultDto.class)
                    .stream().map(v -> {
                String varErrRec = v.getErrorRecByerl();
                varErrRec = (varErrRec == null) ? "" : varErrRec;
                String erlTotalRec = v.getTotalRecByerl();
                erlTotalRec = (erlTotalRec == null) ? "" : erlTotalRec;
                String varErrRecByRule = v.getErrCountByerlRule();
                varErrRecByRule = (varErrRecByRule == null) ? "" : varErrRecByRule;
                Pattern glPattern = Pattern.compile(glName + ":(.*?),");
                Pattern glerlRulePattern = Pattern.compile(glName + "\\|(.*?)\\$");
                Matcher erlErrMatcher = glPattern.matcher(varErrRec);
                Matcher erlTotalMatcher = glPattern.matcher(erlTotalRec);
                Matcher errByRuleMatcher = glerlRulePattern.matcher(varErrRecByRule + "$");
                v.setTotalRec(0L);
                v.setErrorRec(0L);
                v.setErrByRule(null);
                while (erlErrMatcher.find()) {
                    v.setErrorRec(Long.valueOf(erlErrMatcher.group(1)));
                    break;
                }
                while (erlTotalMatcher.find()) {
                    v.setTotalRec(Long.valueOf(erlTotalMatcher.group(1)));
                    break;
                }
                while (errByRuleMatcher.find()) {
                    System.out.println(errByRuleMatcher.group(1));
                    v.setErrByRule(errByRuleMatcher.group(1));
                    break;
                }

                return v;
            }).collect(Collectors.toList());
}

findBy 方法的 myRepo 代码 sn-p

@Query("select s from tableA s, tableB t  where someCondition order by aColumn ASC")
    <T> Collection<T> findSomethingByColumnA(@Param("param1") String param1, @Param("param2")Date param2, @Param("param3")Date param3, Class<T> ctype);


@Projection(name="proj1", types= MyTable.class)
public interface ResultDto{
    
    Long getRunId();
    
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="dd MMM yyyy")
    Date getValidateDt();
    
    ..some more getters and setters
}

@Entity
@Table(name = "MY_TABLE_NAME")
@Data
public class MyTable implements Serializable {

@Id
    @Column(name="ID")
    private long id;
    
    .. some more fields
}

我添加了以下属性以启用日志以进行调试

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

在下面记录sn-p:

    2021-01-19 10:22:39.455 DEBUG 57901 --- [nio-9000-exec-4] org.hibernate.SQL                        : select ..query
    2021-01-19 10:22:39.455 TRACE 57901 --- [nio-9000-exec-4] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [CLOB] - [%textA%]
    2021-01-19 10:22:39.456 TRACE 57901 --- [nio-9000-exec-4] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [TIMESTAMP] - [Wed Jan 01 00:00:00 EST 2020]
    2021-01-19 10:22:39.457 TRACE 57901 --- [nio-9000-exec-4] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [TIMESTAMP] - [Tue Jan 19 00:00:00 EST 2021]
    2021-01-19 10:22:39.552 DEBUG 57901 --- [nio-9000-exec-4] org.hibernate.SQL                        : update MY_TABLE_NAME set ...query
    2021-01-19 10:22:39.553 TRACE 57901 --- [nio-9000-exec-4] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [0]
    2021-01-19 10:22:39.553 TRACE 57901 --- [nio-9000-exec-4] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [6901]
.
.
binding parameter [16]

如您所见,UPDATE 语句在 SELECT 语句之后立即执行!奇怪的是它发生在服务器上(开发、阶段和产品)。但是,当我在 STS(eclipse)中使用相同的代码将其指向 dev/stage/prod 属性(弹簧配置文件)并在我的系统中进行测试时,这个问题没有发生!什么可能导致执行更新语句?

UPDATE : SELECT statemnt 获取 MY_TABLE_NAME 的 16 列,所有这些列都使用 UPDATE 查询进行更新

UPDATE 查询的执行次数与 SELECT 查询的结果一样多。假设 SELECT 查询返回 10 行,UPDATE 查询将执行 10 次以更新所有这 10 行!

是不是因为 .stream().map(v) 中修改了实体?

v.setTotalRec(Long.valueOf(0));
v.setErrorRec(Long.valueOf(0));
v.setErrByRule(null);

【问题讨论】:

  • 用 0 和 6901 更新的那两个字段是什么?
  • @Antoniossss 共有 16 个字段正在更新(包括上面的 0 和 6901)。这些是 SELECT 语句中的 MY_TABLE_NAME 的 16 列
  • 您是在类级别添加@Transactional 还是从另一个@Transactional 注释方法调用此方法?
  • No.. 在类级别不使用@Transactional 并且调用方法/类也不是事务性的

标签: java oracle spring-boot jpa spring-data-jpa


【解决方案1】:

是不是因为.stream().map(v)中的实体被修改了?

是的,这可以说是 JPA 的定义特性:您加载实体,修改它们,并在事务结束时(实际上是会话,但几乎相同)JPA 收集来自托管实体的所有修改并更新它们的状态数据库。

【讨论】:

  • 哦,我不知道。因此,与其修改 Projection 类 ResultDto 对象(上述代码中的 v),我应该使用 ResultDto 创建新对象并显式设置值并返回该新列表,还是有其他方法来处理这种情况?因为我希望在返回列表之前执行那些 setter 方法
  • 而且我们没有使用@Transactional
  • 如果您想修改实体而不是将其存储在数据库中,您应该将它们复制到 DTO 或从 EntityManager 中删除它们。
  • 抱歉,我不明白什么是“从 EntityManager 中删除它们”。怎么办?
猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多