首页 > 解决方案 > Spring JPA 事务 ID

问题描述

我为我的所有实体添加了一个属性 - 事务 id - 这是一个序列生成的值,我在每个事务中增加一次。

我还将事务 ID 与用户和开始/结束时间一起存储,因此我对数据库中的每个更改都有一个审计跟踪。

处理存储完整图形的最佳方法是什么,我基本上只想将事务 id 应用于那些实际脏的实体?

我可以在事务 id 列上放置 @PrePersist 和 @PreUpdate,但是如何检索当前事务 id 的值?有没有办法在事务对象或其他 JPA 控制器上存储和检索值?我需要使用 ThreadLocal 解决方案吗?

标签: spring-bootspring-data-jpa

解决方案


好的,这就是我所做的。它似乎适用于所有用例,尽管我没有进行任何性能测试等。如果有人看到任何可能不是最佳的或在某些情况下可能失败的东西,请指出。

这是所有 @Service 实现必须扩展的基础服务类:

public class BaseService
{

    private final ActivityService activityService;
    private final ApplicationEventPublisher applicationEventPublisher;

    public static ThreadLocal<Activity> transaction = new ThreadLocal<>();

    public BaseService(ActivityService activityService, ApplicationEventPublisher applicationEventPublisher)
    {
        this.activityService = activityService;
        this.applicationEventPublisher = applicationEventPublisher;
    }

    Object executeWithinActivity(Updater updater)
    {
        boolean startedLocally = false;
        try
        {
            if (transaction.get() == null)
            {
                startedLocally = true;
                Activity activity = activityService.startTransaction();
                transaction.set(activity);
            }
            return updater.execute(transaction.get());
        }
        finally
        {
            if (startedLocally)
            {
                applicationEventPublisher.publishEvent(new TransactionEvent());
                Activity activity = transaction.get();
                activityService.endTransaction(activity);
            }
        }
    }

    protected interface Updater
    {
        Object execute (Activity activity);
    }

    static class TransactionEvent
    {
    }
}

Activity 是表示存储的事务 id 的实体:

@Entity
@Getter @Setter
@Table(name = "transactions", schema = "public", catalog = "euamdb")
public class Activity
{
    @Id
    @Column(name = "transaction_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tx_generator")
    @SequenceGenerator(name = "tx_generator", sequenceName = "transaction_seq", allocationSize = 1)
    private long transactionId;

    @Basic
    @Column(name = "user_id", length = 24)
    private String userId;

    @Basic
    @Column(name = "transaction_start")
    @CreationTimestamp
    private Date transactionStart;

    @Basic
    @Column(name = "transaction_end")
    @UpdateTimestamp
    private Date transactionEnd;

    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (!(o instanceof Activity)) return false;
        Activity that = (Activity) o;
        return transactionId == that.transactionId;
    }

    @Override
    public int hashCode()
    {
        return Long.hashCode(transactionId);
    }
}

ActivityService(不扩展 BaseService):

@Service
public class ActivityService
{
    private final ActivityRepository activityRepository;
    private final AuthUserService authService;

    @Autowired
    public ActivityService(ActivityRepository activityRepository, AuthUserService authService)
    {
        this.activityRepository = activityRepository;
        this.authService = authService;
    }

    @Transactional
    public Activity startTransaction()
    {
        Activity activity = new Activity();
        activity.setTransactionStart(new Date());
        activity.setUserId(authService.getAuthenticatedUserId());
        activityRepository.save(activity);
        return activity;
    }

    @Transactional
    public void endTransaction(Activity activity)
    {
        activity.setTransactionEnd(new Date());
        activityRepository.save(activity);
    }
}

所有实体的基实体类(Activity 除外):

@MappedSuperclass
@Getter @Setter
public class BaseEntity
{
    @Basic
    @Column(name = "transaction_id")
    private Long transactionId;

    @PrePersist
    @PreUpdate
    public void setupTransaction ()
    {
        ThreadLocal<Activity> transaction = BaseService.transaction;
        Activity activity = transaction.get();
        long transactionId = activity.getTransactionId();
        setTransactionId(transactionId);
    }
}

服务示例:

@Service
public class OrganizationService extends BaseService
{
    private final OrgUserRepository orgUserRepository;
    private final UserService userService;

    @Autowired
    public OrganizationService(ActivityService activityService,
                               OrgUserRepository orgUserRepository,
                               UserService userService,
                               ApplicationEventPublisher applicationEventPublisher)
    {
        super(activityService, applicationEventPublisher);
        this.orgUserRepository = orgUserRepository;
        this.userService = userService;
    }

    @Transactional
    public OrgUser save(User user, OrgUser orgUser)
    {
        return (OrgUser) executeWithinActivity(activity ->
                              {
                                  orgUser.setUser(userService.save(user));
                                  return orgUserRepository.save(orgUser);
                              });
    }
}

UserService 也将扩展 BaseService 并且 save(OrgUser) 方法也将执行WithinActivity。

最后,提交侦听器:

@Component
public class AfterCommitListener
{
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
    public void doAfterTxComplete(BaseService.TransactionEvent event)
    {
        BaseService.transaction.remove();
    }
}

推荐阅读