我为所有实体添加了一个属性-交易ID-这是一个序列生成的值,我在每次交易中都会碰到一次。
我还将交易ID与用户以及开始/结束时间一起存储,因此我对数据库中的每个更改都有审核跟踪。
处理存储完整图形的最佳方法是什么,我基本上只想将事务ID应用于那些实际上是脏的实体?
我可以在交易ID列上放置@PrePersist和@PreUpdate,但是如何检索当前交易ID的值?有没有办法在事务对象或其他JPA控制器上存储和检索值?我是否需要使用ThreadLocal解决方案?
答案 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();
}
}