Jakarta ee 在数据库中原子读写字段的最佳实践
我来自Java桌面应用程序背景。我想知道J2EE中的最佳实践是什么,在数据库中读写一个字段。现在,以下是我所做的Jakarta ee 在数据库中原子读写字段的最佳实践,jakarta-ee,Jakarta Ee,我来自Java桌面应用程序背景。我想知道J2EE中的最佳实践是什么,在数据库中读写一个字段。现在,以下是我所做的 // In Servlet. synchronized(private_static_final_object) { int counter = read_counter_from_database(); counter = some_calculation_that_shall_be_done_outside_database(counter); write
// In Servlet.
synchronized(private_static_final_object)
{
int counter = read_counter_from_database();
counter = some_calculation_that_shall_be_done_outside_database(counter);
write_counter_back_to_database(counter);
}
然而,我怀疑上述方法将一直有效
根据我的观察,如果我同时有多个web请求,我将使用不同的线程在servlet的单个实例中执行代码。当不同的线程web请求都引用相同的“私有\静态\最终\对象”时,上述方法应能正常工作
然而,我的猜测是“servlet的单个实例”并不能保证。与一段时间之后一样,servlet的前一个实例可能会被破坏,并创建另一个新的servlet实例
我在JDO也遇到过。我不确定他们是否能解决这个问题
// In Servlet.
Transaction tx = pm.currentTransaction();
tx.begin();
int counter = read_counter_from_database(); // Line 1
counter = some_calculation_that_shall_be_done_outside_database(counter);// Line 2
write_counter_back_to_database(counter); // Line 3
tx.commit();
只有当线程A以原子方式执行第1行到第3行时,代码才能保证,只有线程B才能继续以原子方式执行第1行到第3行吗
因为我不希望发生以下情况
谢谢。为什么不把你的两个想法简单地结合起来呢
synchronized(private_static_final_object)
{
Transaction tx = pm.currentTransaction();
tx.begin();
int counter = read_counter_from_database();
counter++;
write_counter_back_to_database(counter);
tx.commit();
}
您可以通过代码中的关键部分和db事务中的原子性实现线程同步
单独使用synchronized关键字不会“保护”db事务原子性
另一个选项:
对于您来说,最安全的方法是在db引擎中的存储过程中的事务中执行此操作,尽管根据rexem的观察,它仍然不完美。拉取数据,增加数据量,然后将其保存回去,会导致错误数据的可能性过大。这:
Transaction tx = pm.currentTransaction();
tx.begin();
int counter = read_counter_from_database(); // Line 1
counter++; // Line 2
write_counter_back_to_database(counter); // Line 3
tx.commit();
…不安全
数据库采用所谓的隔离级别,在这种级别上,可以在提交插入/更新时读取数据。它使读取速度更快,但有可能获取过时的数据。当您的计数器变量递增时,我可以提交我的insert-您最多可能会遇到主键或唯一键验证错误,最坏可能是坏数据
我的建议是让相应的数据库实用程序处理这些情况,因为它们是安全的。对于甲骨文来说,这是一个序列。sqlserver称之为IDENTITY;MySQL称之为autoincrement…不确定这是否适用于您的用例,但以下情况在数据库级别都是可能的:
1. begin transaction
2. update counter = counter+1
3. read value
4. commit
当一个线程执行2时,其他线程将在2之前阻塞,直到第一个线程执行提交
编辑:如果无法在数据库上进行更新,则必须使用select for update语句样式来锁定其他语句的执行:
1. begin transaction
2. select counter for update
3. calculate new counter value in application layer
4. update counter on database
5. commit
现在,当另一个线程位于2和5之间时,线程将始终在步骤2阻塞。整个操作将是原子的。MySQL InnoDB的更新语法选择可以在以下位置找到:这很有意义,但我不确定Yan所追求的是什么身份。缺少详细信息,但重点仍然是列出的设置本身存在缺陷。计数器++只是一个例子。然而,大多数情况下,计算不能由数据库本身完成。请参考我精炼的问题。