MySQL JPA从不同的表中删除多条记录

w8rqjzmb  于 2023-02-28  发布在  Mysql
关注(0)|答案(3)|浏览(109)

有两个表:

User table `user`
        +----+----------------------------+-------------+
        | id | date_created_user          | email       |
        +----+----------------------------+-------------+
        |  7 | 2023-02-23 13:23:09.085897 | www@www.www |
        | 16 | 2023-02-25 14:23:31.691560 | qqq@qqq.qqq |
        | 17 | 2023-02-25 14:24:02.089010 | aaa@aaa.aaa |
        | 18 | 2023-02-25 14:24:24.708500 | xxx@xxx.xxx |
        | 19 | 2023-02-25 14:25:19.253770 | ooo@ooo.ooo |
        +----+----------------------------+-------------+

        Deletion table `deletion`
        +----+----------------+----------------------------+---------+
        | id | active         | date                       | user_id |
        +----+----------------+----------------------------+---------+
        | 10 | false          | 2023-02-25 14:23:31.691560 |      16 |
        | 11 | false          | 2023-02-25 14:24:02.089010 |      17 |
        | 12 | true           | 2023-02-25 14:24:24.708500 |      18 |
        | 13 | true           | 2023-02-25 14:25:19.253770 |      19 |
        +----+----------------+----------------------------+---------+



        Relationship table `user_role`
        +---------+---------------+
        | user_id | role_id       |
        +---------+---------------+
        |       7 |            1  |
        |      16 |            2  |
        |      17 |            2  |
        |      18 |            2  |
        |      19 |            2  |
        +---------+---------------+


    DESCRIBE User `user`
    +-------------------------+-------------+------+-----+---------+----------------+
    | Field                   | Type        | Null | Key | Default | Extra          |
    +-------------------------+-------------+------+-----+---------+----------------+
    | id                      | bigint      | NO   | PRI | NULL    | auto_increment |
    | email                   | varchar(58) | NO   | UNI | NULL    |                |
    | enabled                 | bit(1)      | NO   |     | NULL    |                |
    | password                | varchar(65) | NO   |     | NULL    |                |
    | token                   | varchar(45) | YES  | UNI | NULL    |                |
    +-------------------------+-------------+------+-----+---------+----------------+


    DESCRIBE Deletion `deletion`
    +--------------------+-------------+------+-----+---------+----------------+
    | Field              | Type        | Null | Key | Default | Extra          |
    +--------------------+-------------+------+-----+---------+----------------+
    | id                 | bigint      | NO   | PRI | NULL    | auto_increment |
    | active             | bit(1)      | NO   |     | NULL    |                |
    | date               | datetime(6) | NO   |     | NULL    |                |
    | user_id            | bigint      | YES  | MUL | NULL    |                |
    +--------------------+-------------+------+-----+---------+----------------+

    DESCRIBE  `user_role`
    +---------------+--------+------+-----+---------+-------+
    | Field         | Type   | Null | Key | Default | Extra |
    +---------------+--------+------+-----+---------+-------+
    | user_id       | bigint | NO   | PRI | NULL    |       |
    | role_id       | bigint | NO   | PRI | NULL    |       |
    +---------------+--------+------+-----+---------+-------+

有必要从这些表中删除某些记录。
具体情况如下:
如果在**Deletiontable中,active字段包含值false,并且在date字段中已超过24小时,则需要删除此记录,并从User**table中删除此记录。

    • Deletiontable中的user_id**键。

另外还有一个关系表**user_role**,这是用户和角色的表,如果有关系的话就不能删除用户了,所以也需要去掉这个关系。

我的存储库

@Transactional(readOnly = true)
    @Repository
    public interface DeletionRepository extends JpaRepository<Deletion, Long> {


        @Transactional
        @Modifying
        @Query("DELETE FROM Deletion as a WHERE a.active = false AND a.date <= :date")
        void deleteDeletionByActiveAndDate(@Param("date") String date);

    }
zy1mlcev

zy1mlcev1#

考虑到您需要在删除查询中执行一些日期时间操作,而这些操作往往是高度特定于数据库的,我建议使用以下原生MySQL查询:

DELETE
FROM User u
WHERE EXISTS (
    SELECT 1
    FROM Deletion d
    WHERE d.user_id = u.id AND
          d.active = false AND
          d.date < NOW() - INTERVAL 1 DAY
);

如果还想从Deleted表中删除记录,则在user_id上设置一个级联外键,这样从User表中删除父记录也会删除从属记录。
如果你 * 不能 * 设置级联删除,在MySQL上你也可以使用下面的delete join:

DELETE u, d
FROM User u
INNER JOIN Deleted d
    ON d.user_id = u.id
WHERE d.active = false AND
      d.date < NOW() - INTERVAL 1 DAY;
hwazgwia

hwazgwia2#

根据您提供的存储库接口,您似乎已经走上了正确的道路,可以使用JPQL查询根据给定条件从Deletion表中删除记录。但是,您还需要从User表中删除相应的记录。要完成此操作,您可以修改JPQL查询,以便也从Deletion表中检索要删除的记录的user_id。然后执行另一个查询以从User表中删除相应的记录。
下面是包含附加查询的存储库界面的修改版本:

@Transactional(readOnly = true)
@Repository
public interface DeletionRepository extends JpaRepository<Deletion, Long> {

    @Transactional
    @Modifying
    @Query("SELECT a.user_id FROM Deletion a WHERE a.active = false AND a.date <= :date")
    List<Long> findUserIdsToDelete(@Param("date") Date date);

    @Transactional
    @Modifying
    @Query("DELETE FROM Deletion a WHERE a.active = false AND a.date <= :date")
    void deleteDeletionByActiveAndDate(@Param("date") Date date);

    @Transactional
    @Modifying
    @Query("DELETE FROM User u WHERE u.id IN :userIds")
    void deleteUserByIds(@Param("userIds") List<Long> userIds);

    default void deleteInactiveDeletionsAndRelatedUsers(Date date) {
        List<Long> userIdsToDelete = findUserIdsToDelete(date);
        deleteDeletionByActiveAndDate(date);
        deleteUserByIds(userIdsToDelete);
    }
}

在此修改版本中,findUserIdsToDelete方法从Deletion表中检索要删除的记录的user_id,并将其作为列表返回。deleteUserByIds方法获取此user_id列表,并从User表中删除相应的记录。
最后,deleteInactiveDeletationsAndRelatedUsers方法结合了上述方法,提供了一种更方便的方式来删除非活动删除及其相关用户。可以从服务层调用此方法,传入适当的日期值。注意,我将参数类型从String更改为Date,这是更适合日期值的类型。

nhaq1z21

nhaq1z213#

  • 注意:我在GitHub Copilot的帮助下完成了部分回答。*

TL; DR:在Deletion实体上使用适当的CascadeType,例如REMOVEALL
如果按如下方式定义UserDeletion图元:

package org.behrang.stackoverflow.q75563217.entity;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Entity
@Table(name = "Users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private Date createdAt;

    private String email;

    @OneToMany(cascade = CascadeType.PERSIST)
    private List<Deletion> deletions = new ArrayList<>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public List<Deletion> getDeletions() {
        return deletions;
    }

    public void setDeletions(List<Deletion> deletions) {
        this.deletions = deletions;
    }

    public void addDeletion(Deletion deletion) {
        this.deletions.add(deletion);
    }
}

package org.behrang.stackoverflow.q75563217.entity;

import jakarta.persistence.*;

import java.util.Date;

@Entity
@Table(name = "Deletions")
public class Deletion {

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

    private boolean active;

    private Date date;

    @ManyToOne(cascade = CascadeType.REMOVE)
    @JoinColumn(name = "user_id")
    private User user;

    public void setId(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

并使用以下persistence.xml文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">
    <persistence-unit name="default">
        <class>org.behrang.stackoverflow.q75563217.entity.User</class>
        <class>org.behrang.stackoverflow.q75563217.entity.Deletion</class>
        <properties>
            <property name="jakarta.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:32773/example"/>
            <property name="jakarta.persistence.jdbc.user" value="root"/>
            <property name="jakarta.persistence.jdbc.password" value="password"/>
            <property name="jakarta.persistence.schema-generation.database.action" value="create"/>
        </properties>
    </persistence-unit>
</persistence>

并使用以下模式(由Hibernate自动生成):

create table if not exists Deletions_SEQ
(
    next_val bigint null
);

create table if not exists Users
(
    id        int          not null primary key,
    createdAt datetime(6)  null,
    email     varchar(255) null
);

create table if not exists Deletions
(
    id      bigint      not null primary key,
    active  bit         not null,
    date    datetime(6) null,
    user_id int         null,
    constraint FK2bq97txm7h2eirrkbv84xpv2y foreign key (user_id) references Users (id)
);

create table if not exists Users_Deletions
(
    User_id      int    not null,
    deletions_id bigint not null,
    constraint UK_jhg9je4j0jwu07wpjw2yvm9ve unique (deletions_id),
    constraint FK98pxufvij990xbgyihq7lxn2a foreign key (User_id) references Users (id),
    constraint FKg1q9bnqdsn40gecsagv32b16q foreign key (deletions_id) references Deletions (id)
);

create table if not exists Users_SEQ
(
    next_val bigint null
);

下面的演示代码显示了级联效果的工作原理:

package org.behrang.stackoverflow.q75563217;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
import org.behrang.stackoverflow.q75563217.entity.Deletion;
import org.behrang.stackoverflow.q75563217.entity.User;

import java.sql.Date;
import java.time.Duration;
import java.time.Instant;

public class Demo {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("default");
        EntityManager entityManager = factory.createEntityManager();
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();

        Instant i1 = Instant.now().minus(Duration.ofHours(25));
        User u1 = new User();
        u1.setEmail("1@example.com");
        u1.setCreatedAt(Date.from(i1));

        Deletion d01 = new Deletion();
        d01.setDate(Date.from(Instant.now()));
        d01.setUser(u1);
        u1.addDeletion(d01);

        entityManager.persist(u1);

        tx.commit();
        entityManager.close();

        entityManager = factory.createEntityManager();
        tx = entityManager.getTransaction();
        tx.begin();

        Deletion d11 = entityManager.find(Deletion.class, 1L);
        entityManager.remove(d11);

        tx.commit();
        entityManager.close();

        factory.close();
    }
}

演示视频:https://www.youtube.com/watch?v=PCZcJdi9wf8
样本代码:https://github.com/behrangsa/so-75563217
对于年龄比较,可以将日期/时间逻辑添加到JPQL查询中。

相关问题