- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
基本上,我试图了解在使用 Jax-RS 和 Spring 开发 REST 服务时如何编写正确(或“正确编写”?)事务代码。此外,我们正在使用 JOOQ 进行数据访问。但这应该不是很相关......
考虑一个简单的模型,我们有一些组织,它们有这些字段:“id”、“name”、“code”
。所有这些都必须是唯一的。还有一个 status
字段。
组织可能会在某个时候被删除。但我们不想完全删除数据,因为我们想保存它以用于分析/维护目的。所以我们只需将组织的“状态”字段设置为'REMOVED'
。
因为我们没有从表中删除组织行,所以我们不能简单地将唯一约束放在“名称”列上,因为,我们可能会删除组织,然后创建一个具有相同名称的新组织。但是我们假设代码必须在全局范围内是唯一的,所以我们在 code
列上有一个唯一的约束。
因此,让我们看看这个创建组织的简单示例,并在此过程中执行一些检查。
资源:
@Component
@Path("/api/organizations/{organizationId: [0-9]+}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaTypeEx.APPLICATION_JSON_UTF_8)
public class OrganizationResource {
@Autowired
private OrganizationService organizationService;
@Autowired
private DtoConverter dtoConverter;
@POST
public OrganizationResponse createOrganization(@Auth Person person, CreateOrganizationRequest request) {
if (organizationService.checkOrganizationWithNameExists(request.name())) {
// this throws special Exception which is intercepted and translated to response with 409 status code
throw Responses.abortConflict("organization.nameExist", ImmutableMap.of("name", request.name()));
}
if (organizationService.checkOrganizationWithCodeExists(request.code())) {
throw Responses.abortConflict("organization.codeExists", ImmutableMap.of("code", request.code()));
}
long organizationId = organizationService.create(person.user().id(), request.name(), request.code());
return dtoConverter.from(organization.findById(organizationId));
}
}
DAO 服务看起来像这样:
@Transactional(DBConstants.SOME_TRANSACTION_MANAGER)
public class OrganizationServiceImpl implements OrganizationService {
@Autowired
@Qualifier(DBConstants.SOME_DSL)
protected DSLContext context;
@Override
public long create(long userId, String name, String code) {
Organization organization = new Organization(null, userId, name, code, OrganizationStatus.ACTIVE);
OrganizationRecord organizationRecord = JooqUtil.insert(context, organization, ORGANIZATION);
return organizationRecord.getId();
}
@Override
public boolean checkOrganizationWithNameExists(String name) {
return checkOrganizationExists(Tables.ORGANIZATION.NAME, name);
}
@Override
public boolean checkOrganizationWithCodeExists(String code) {
return checkOrganizationExists(Tables.ORGANIZATION.CODE, code);
}
private boolean checkOrganizationExists(TableField<OrganizationRecord, String> checkField, String checkValue) {
return context.selectCount()
.from(Tables.ORGANIZATION)
.where(checkField.eq(checkValue))
.and(Tables.ORGANIZATION.ORGANIZATION_STATUS.ne(OrganizationStatus.REMOVED))
.fetchOne(DSL.count()) > 0;
}
}
这带来了一些问题:
createOrganization
方法上添加 @Transactional
注释吗?或者我应该再创建一个与 DAO 对话的服务并将 @Transactional 注释添加到它的方法中吗?还有别的吗?"code"
字段发送请求会发生什么。在提交第一个事务之前,检查已成功通过,因此不会发送 409 响应。第一个事务将被正确提交,但第二个事务将违反数据库约束。这将抛出 SQLException。如何优雅地处理它?我的意思是我仍然想在客户端显示不错的错误消息,说该名称已被使用。但我不能真正解析 SQLException 或 smth.. 可以吗? 更新:我知道隔离级别和通常的 error/isolation matrix (脏读等)。我遇到的问题是找到一些“生产就绪”的样本来学习。或者一本关于某个主题的好书。我仍然不明白如何正确处理所有错误。我想我需要重试几次,如果交易失败......而不是抛出一些一般性错误并实现客户端,处理那个......但是做每当我使用范围查询时,我真的必须使用 SERIALIZABLE 模式吗?因为它会极大地影响性能。但否则我怎么能保证交易会失败..
无论如何,我决定现在我需要更多时间来学习一般的事务和数据库管理来解决这个问题......
最佳答案
一般而言,不谈事务性,端点应该只从请求中获取参数并调用服务。它不应该执行业务逻辑。
您的 checkXXX 方法似乎是业务逻辑的一部分,因为它们会抛出有关特定于域的冲突的错误。为什么不将它们放入服务中,成为一种方法,顺便说一句,这是事务性的?
//service code
public Organization createOrganization(String userId, String name, String code) {
if (this.checkOrganizationWithNameExists(request.name())) {
throw ...
}
if (this.checkOrganizationWithCodeExists(code)) {
throw ...
}
long organizationId = this.create(userId, name, code);
return dao.findById(organizationId);
}
我认为你的参数是字符串,但它们可以是任何东西。我不确定你想在服务层抛出 Responses.abortConflict 因为它似乎是一个 REST 概念,但如果你愿意,你可以为它定义自己的异常类型。
端点代码应该看起来像这样,但是,它可能包含额外的 try-catch block ,它将抛出的异常转换为错误响应:
//endpoint code
@POST
public OrganizationResponse createOrganization(@Auth Person person, CreateOrganizationRequest request) {
String code = request.code();
String name = request.name();
String userId = person.user().id();
return dtoConverter.from(organizationService.createOrganization(userId, name, code));
}
关于问题2和3,transaction isolation levels是你的 friend 。将隔离级别设置得足够高。我认为“可重复读取”适合您的情况。您的 checkXXX 方法将检测是否有其他事务提交了具有相同名称或代码的实体,并保证这种情况在执行“创建”方法时保持不变。再来一个useful read关于 Spring 和事务隔离级别。
关于java - 如何使用 JAX-RS 和 Spring 编写正确/可靠的事务代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39044269/
我只想从客户端向服务器发送数组 adc_array=[w, x, y, z]。下面是客户端代码,而我的服务器是在只接受 json 的 python 中。编译代码时我没有收到任何错误,但收到 2 条警告
我是 lua 和 Node js 的新手,我正在尝试将我正在开发的移动应用程序连接到服务器。问题是它连接到服务器,但我尝试传递的数据丢失或无法到达服务器。对我正在做的事情有什么问题有什么想法吗? th
我在这个页面上工作 http://www.haskell.org/haskellwiki/99_questions/Solutions/4 我理解每个函数的含义,看到一个函数可以像这样以多种方式定义,
我目前正在尝试将数据写入 excel 以生成报告。我可以将数据写入 csv 文件,但它不会按照我想要的顺序出现在 excel 中。我需要数据在每列的最佳和最差适应性下打印,而不是全部打印在平均值下。这
所以,我正在做一个项目,现在我有一个问题,所以我想得到你的帮助:) 首先,我已经知道如何编写和读取 .txt 文件,但我想要的不仅仅是 x.hasNext()。 我想知道如何像 .ini 那样编写、读
我正在尝试编写一个函数,该函数将返回作为输入给出的任何数字的阶乘。现在,我的代码绝对是一团糟。请帮忙。 function factorialize(num) { for (var i=num, i
这个问题已经有答案了: Check variable equality against a list of values (16 个回答) 已关闭 4 年前。 有没有一种简洁或更好的方法来编写这个条件
我对 VR 完全陌生,正在 AFrame 中为一个类(class)项目开发 VR 太空射击游戏,并且想知道 AFrame 中是否有 TDD 的任何文档/标准。有人能指出我正确的方向吗? 最佳答案 几乎
我正在尝试创建一个 for 循环,它将重现以下功能代码块,但以一种更具吸引力的方式。这是与 Soundcould 小部件 API 实现一起使用的 here on stackoverflow $(doc
我有一个非常令人困惑的问题。我正在尝试更改属性文件中的属性,但它只是没有更改... 这是代码: package config; import java.io.FileNotFoundException
我对 VR 完全陌生,正在 AFrame 中为一个类(class)项目开发 VR 太空射击游戏,并且想知道 AFrame 中是否有 TDD 的任何文档/标准。有人能指出我正确的方向吗? 最佳答案 几乎
我正在开发一个用户模式(Ring3)代码级调试器。它还应支持.NET可执行文件的本机(x86)调试。基本上,我需要执行以下操作: 1).NET在隐身模式下加载某些模块,而没有LOAD_DLL_DEBU
我有一个列表,我知道有些项目是不必要打印的,我正在尝试通过 if 语句来做到这一点...但是它变得非常复杂,所以有没有什么方法可以在 if 语句中包含多个索引而无需打印重写整个声明。 看起来像这样的东
我很好奇以不同方式编写 if 语句是否会影响程序的速度和效率。所以,例如写一个这样的: bool isActive = true; bool isResponding = false; if (isA
我在搜索网站的源代码时找到了一种以另一种方式(我认为)编写 if 语句的方法。 代替: if(a)b; 或: a?b:''; 我读了: !a||b; 第三种方式和前两种方式一样吗?如果是,为什么我们要
我的数据采用以下格式(HashMap的列表) {TeamName=India, Name=Sachin, Score=170} {TeamName=India, Name=Sehwag, Score=
我目前正在完成 More JOIN operations sqlzoo 的教程,遇到了下面的代码作为#12 的答案: SELECT yr,COUNT(title) FROM movie JOIN ca
我正试图找到一种更好的方法来编写这段代码: def down_up(array, player) 7.downto(3).each do |row| 8.times do |col
出于某种原因,我的缓冲区中充满了乱码,我不确定为什么。我什至用十六进制编辑器检查了我的文件,以验证我的字符是否以 2 字节的 unicode 格式保存。我不确定出了什么问题。 [打开文件] fseek
阅读编码恐怖片时,我刚刚又遇到了 FizzBuzz。 原帖在这里:Coding Horror: Why Can't Programmers.. Program? 对于那些不知道的人:FizzBu
我是一名优秀的程序员,十分优秀!