Java 表被指定两次,既作为“更新”的目标,也作为数据的单独源

Java 表被指定两次,既作为“更新”的目标,也作为数据的单独源,java,mysql,hibernate,jpa,mariadb,Java,Mysql,Hibernate,Jpa,Mariadb,我使用SpringJPA和hibernate实现。我使用mariadb并尝试执行更新子查询 我的对象结构 @Entity public class Room { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long roomId; @ManyToOne @JoinColumn(name = "appartment_id") private Appartment appartment; }

我使用SpringJPA和hibernate实现。我使用mariadb并尝试执行更新子查询

我的对象结构

@Entity
public class Room {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long roomId;

  @ManyToOne  
  @JoinColumn(name = "appartment_id")
  private Appartment appartment;
}

@Entity
public class Appartment {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long appartmentId;

  @OneToMany
  @JoinColumn(name="appartment_id")
  private Set<Room> roomList;
}

update Room r1
set r1.available = :availability
where r1.roomId in
( select r2.roomId from Room r2 JOIN r2.appartment a1 WHERE a1.appartmentId = :appartmentId )
我得到这个错误


java.sql.SQLException:表“room”被指定了两次,既作为“更新”的目标,也作为数据的单独来源

这是MySQL中的一个限制:-

不能更新表并在子查询中从同一表中进行选择

有时,您可以做一个捏造的操作,将子查询隐藏在可能有效的进一步子查询级别中。像这样的东西没有经过测试:-

UPDATE Room r1
SET r1.available = :availability
WHERE r1.roomId IN
    SELECT roomId
    FROM
    ( 
        SELECT r2.roomId 
        FROM Room r2 
        JOIN r2.appartment a1 
        WHERE a1.appartmentId = :appartmentId 
    )
请注意,您的查询可能有错误。在子查询中,您正在将别名为r2的表室连接到名为r2的数据库中名为appartment的表。此外,您的子查询在没有连接条件的情况下进行连接

但是,您完全可以在UPDATE语句中执行join,而不需要子查询:-

UPDATE Room 
INNER JOIN r2.appartment a1
ON Room.roomId = a1.roomId
SET r1.available = :availability
WHERE a1.appartmentId = :appartmentId 

解决方案是单独选择Roomid并将其作为参数传递

选择id列表


jpa两者都不喜欢。在这种情况下,您似乎正在遭受使用限制性框架的痛苦,该框架阻止您使用数据库提供的设施。@Kickstart我们如何在更新连接查询中使用限制?@hmjha-取决于查询。在一个简单的更新中,您可以轻松地使用orderby/LIMIT。我认为,对于多个表,您需要在子查询中使用带限制的SELECT,然后针对该子查询进行连接,以进行实际更新。@roberttrudel-请尝试我的答案,并使用hibernate进行测试。
List<Long> roomIdList = entityManager.createQuery(
                    """SELECT r2.roomId 
                    FROM Room r2 
                    JOIN r2.appartment a1 
                    WHERE a1.appartmentId = :appartmentId""", Long.class)
                    .setParameter("appartmentId", appartmentId)
                    .getResultList();
int updated = entityManager.createQuery(
                    """UPDATE Room r1
                    SET r1.available = :availability
                    WHERE r1.roomId IN :roomIds""")
                    .setParameter("availability", availability)
                    .setParameter("roomIds", roomIdList)
                    .executeUpdate();