春季JPA交易ID

时间:2020-03-25 17:51:17

标签: spring-boot spring-data-jpa

我为所有实体添加了一个属性-交易ID-这是一个序列生成的值,我在每次交易中都会碰到一次。

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

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

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

1 个答案:

答案 0 :(得分:0)

好的,这就是我所做的。尽管我没有进行任何性能测试,但它似乎可以在所有用例中使用。如果有人发现某些情况下可能不是最佳选择或可能失败,请指出。

这是所有@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
    {
    }
}

活动是代表存储的交易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);
    }
}

所有实体(活动除外)的基本实体类:

@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)方法还将执行executeWithinActivity。

最后,提交侦听器:

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