当前位置: 首页 > 面试题库 >

Spring-JDBC中的隔离级别SERIALIZABLE

景星光
2023-03-14
问题内容

也许有人可以帮助我解决Spring(3.1)/ Postgresql(8.4.11)中的事务性问题

我的交易服务如下:

@Transactional(isolation = Isolation.SERIALIZABLE, readOnly = false)
@Override
public Foo insertObject(Bar bar) {

            // these methods are just examples
            int x = firstDao.getMaxNumberOfAllowedObjects(bar)
            int y = secondDao.getNumerOfExistingObjects(bar)
            // comparison
            if (x - y > 0){
                  secondDao.insertNewObject(...) 
            }
            ....
}

Spring配置Webapp包含:

@Configuration 
@EnableTransactionManagement 
public class ....{
    @Bean
    public DataSource dataSource() {
        org.apache.tomcat.jdbc.pool.DataSource ds = new DataSource();

        ....configuration details

        return ds;
    }

    @Bean
    public DataSourceTransactionManager txManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

让我们说一个请求“ x”和一个请求“ y”同时执行并到达注释“比较”(方法insertObject)。然后,允许他们两个都插入一个新对象,并提交他们的事务。

为什么我没有RollbackException?据我所知,这就是可序列化等值线的用途。回到前面的场景,如果x设法插入一个新对象并提交其事务,则由于存在未读的新对象,因此不应允许“
y”的事务提交。

也就是说,如果“ y”可以再次读取secondDao.getNumerOfExistingObjects(bar)的值,则它将意识到还有一个新对象。幻影?

事务配置似乎运行良好:

  • 对于每个请求,我可以看到firstDao和secondDao的连接相同
  • 每次调用insertObject时都会创建一个事务

第一个和第二个DAO如下:

@Autowired
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

@Override
public Object daoMethod(Object param) {

        //uses jdbcTemplate

}

我确定我缺少什么。任何想法?

谢谢你的时间,

哈维尔


问题答案:

TL; DR:可序列化冲突的检测在Pg 9.1中得到了显着改进,因此请升级。

从您的描述中找出什么是实际的SQL以及为什么希望获得回滚是很棘手的。看来您已经严重误解了可序列化的隔离,也许是认为它完美地测试了所有谓词,而事实并非如此,尤其是在Pg
8.4中。

SERIALIZABLE不能完全保证事务按顺序执行一样执行-
从性能的角度来看,如果这样做是完全可能的,那将是非常昂贵的。它仅提供有限的检查。正是要检查的内容以及数据库与数据库之间以及版本与版本之间的差异,因此您需要阅读数据库版本的文档。

异常是可能的,在这种情况下,以SERIALIZABLE模式执行的两个事务产生的结果与如果真正以串行方式执行的事务不同。

阅读有关Pg中事务隔离的文档以了解更多信息。请注意,SERIALIZABLEPg
9.1中的行为发生了很大变化,因此请确保阅读适用于您的Pg版本的手册版本。这是8.4版本。特别要阅读13.2.2.1。可序列化隔离与真正可序列化。现在,将其与Pg
9.1文档中描述的大大改进的基于谓词锁定的序列化支持进行比较。

看来您正在尝试执行类似此伪代码的逻辑:

count = query("SELECT count(*) FROM the_table");
if (count < threshold):
    query("INSERT INTO the_table (...) VALUES (...)");

如果是这样的话,在并发执行时在Pg 8.4中将无法正常工作-与上面链接的文档中使用的异常示例几乎相同。令人惊讶的是,它实际上适用于Pg
9.1。我什至没想到9.1的谓词锁定会捕获聚合的使用。

您写道:

回到前面的场景,如果x设法插入一个新对象并提交其事务,则由于存在未读的新对象,因此不应允许“ y”的事务提交。

但是8.4不会检测到这两个事务是相互依赖的,您可以通过使用两个psql会话对其进行测试来轻松证明这一点。只有在9.1中引入了true-
serializability才可以正常工作-坦率地说,我很惊讶它在9.1中可以工作。

如果要执行第8.4页中的强制最大行数之类的操作,则需要对LOCK表进行阻止以防止并发INSERTs,可以手动或通过触发函数进行锁定。在触发器中执行此操作本质上需要提升锁,因此经常会死锁,但会成功完成此工作。最好在应用程序中完成,在该应用程序中您可以LOCK TABLE my_table IN EXCLUSIVE MODESELECT从表获得偶数之前发出,因此它已经具有在表上需要的最高锁定模式,因此不需要死锁倾向的锁升级。的EXCLUSIVE,因为它允许锁定模式是合适SELECT秒,但没有别的。

以下是在两个psql会话中对其进行测试的方法:

SESSION 1                               SESSION 2

create table ser_test( x text );

BEGIN TRANSACTION 
ISOLATION LEVEL SERIALIZABLE;


                                        BEGIN TRANSACTION 
                                        ISOLATION LEVEL SERIALIZABLE;

SELECT count(*) FROM ser_test ;

                                        SELECT count(*) FROM ser_test ;

INSERT INTO ser_test(x) VALUES ('bob');


                                        INSERT INTO ser_test(x) VALUES ('bob');

 COMMIT;

                                        COMMIT;

在Pg 9.1上运行时,st commits succeeds then the secondCOMMIT`失败并显示:

regress=# COMMIT;
ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

但是在8.4上运行时,两次提交都会成功提交,因为8.4并没有在9.1中添加所有可序列化的谓词锁定代码。



 类似资料:
  • 我想使用eclipse链接设置隔离级别,我尝试了以下两种方法: > java.sql.连接 Database aseLogin setTransationIsolation方法 如您所见,getTransactionSolation()方法的返回值之间存在一些不一致。我的问题是,在这两种情况下真正设置了哪种事务隔离?我知道eclipse链接在默认情况下使用不同的连接进行读写操作,即Database

  • 问题内容: 我想将隔离级别设置为。如何使用gorm orm for postgres实现此目的。 示例代码: 问题答案: 我在这里有完全一样的问题: 和pg完全一样。

  • 本文向大家介绍事务的隔离级别有哪些?相关面试题,主要包含被问及事务的隔离级别有哪些?时的应答技巧和注意事项,需要的朋友参考一下 SQL 标准定义了四个隔离级别: READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重

  • < b >想改进这个问题?通过编辑此帖子更新问题,使其只关注一个问题。 我想知道关于提交的不同隔离级别,也想知道行级和表级锁。

  • 本文向大家介绍浅析MYSQL REPEATABLE-READ隔离级别,包括了浅析MYSQL REPEATABLE-READ隔离级别的使用技巧和注意事项,需要的朋友参考一下 REPEATABLE-READ 即可重复读,set autocommit= 0或者START TRANSACTION状态下select表的内容不会改变。这种隔离级别可能导致读到的东西是已经修改过的。 比如: 回话一中读取一个字段

  • 我有一个对具有 SQL API 的 Cosmos 容器的长期运行查询,该查询需要 10 分钟以上才能完成。有没有办法将数据库的隔离级别设置为“可重复读取”或“可序列化”,以避免幻像读取,如这里所定义的那样? 我知道我们可以为 Cosmos DB 设置一致性级别,但它仅适用于地质副本之间的读/写一致性,而不适用于事务隔离。