为什么我不能在我的测试中影响 READ_UNCOMMITTED 隔离
Why I can't effect READ_UNCOMMITTED Isolation in my test
我只是想用spring data jpa 和spring boot 测试spring 对Transactional 注释的支持。
这是我的控制器方法。
@GetMapping(path = "testreaduncommit")
public void testReadUnCommit()
{
new Thread(new Runnable() {
@Override
public void run() {
testService.testReadUncommitted1();
}
}).start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
testService.testReadUncommitted2();
}
还有我的服务工具
@Override
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void testReadUncommitted1() {
log.info("testUncommit1 begin");
User u=userRepository.findOne(1L);
u.setUserPwd("654321");
userRepository.save(u);
log.info("testUncommit1 sleep");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testUncommit1 will be commit");
}
@Override
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void testReadUncommitted2() {
log.info("testUncommit2 begin");
User u=userRepository.findOne(1L);
log.info(u);
}
结果是:
testUncommit1 开始;
testUncommit1 睡眠;
testUncommit2 开始;
User(userId=1, userName=testuser, userPhone=15888888888, userStatus=2, userPwd=123456);
testUncommit1 将被提交;
所以我想知道为什么注释@Transactional 的 属性 'isolation = Isolation.READ_UNCOMMITTED' 不生效,我认为结果应该是 userPwd=654321 因为 READ_UNCOMMITTED 应该出现 'dirty read'。
而且我尝试添加userRepository.flush();
,它起作用了但是在我将隔离级别更改为SERIALIZABLE之后,脏读也发生了,为什么?
我的数据库是 Mysql.
所以当我添加 flush();
我更改了方法的隔离;
@Override
@Transactional(isolation = Isolation.SERIALIZABLE)
public void testReadCommit1() {
log.info("testReadCommit1 begin");
User u=userRepository.findOne(1L);
u.setUserPwd("654321");
userRepository.save(u);
userRepository.flush();
log.info("testReadCommit1 sleep");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testReadCommit1 will be commit");
}
@Override
@Transactional(isolation = Isolation.SERIALIZABLE)
public void testReadCommit2() {
log.info("testUncommit2 begin");
User u=userRepository.findOne(1L);
log.info(u);
}
结果是:
User(userId=1, userName=testuser, userPhone=15888888888, userStatus=2, userPwd=654321)
为什么 SERIALIZABLE 不能防止脏读?
以下 API 文档说调用 flush() 会将所有待处理的更改刷新到数据库。因此,当您的 testReadCommit2() 方法在 3 秒后运行时,它不会读取脏记录。
我只是想用spring data jpa 和spring boot 测试spring 对Transactional 注释的支持。
这是我的控制器方法。
@GetMapping(path = "testreaduncommit")
public void testReadUnCommit()
{
new Thread(new Runnable() {
@Override
public void run() {
testService.testReadUncommitted1();
}
}).start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
testService.testReadUncommitted2();
}
还有我的服务工具
@Override
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void testReadUncommitted1() {
log.info("testUncommit1 begin");
User u=userRepository.findOne(1L);
u.setUserPwd("654321");
userRepository.save(u);
log.info("testUncommit1 sleep");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testUncommit1 will be commit");
}
@Override
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void testReadUncommitted2() {
log.info("testUncommit2 begin");
User u=userRepository.findOne(1L);
log.info(u);
}
结果是:
testUncommit1 开始;
testUncommit1 睡眠;
testUncommit2 开始;
User(userId=1, userName=testuser, userPhone=15888888888, userStatus=2, userPwd=123456);
testUncommit1 将被提交;
所以我想知道为什么注释@Transactional 的 属性 'isolation = Isolation.READ_UNCOMMITTED' 不生效,我认为结果应该是 userPwd=654321 因为 READ_UNCOMMITTED 应该出现 'dirty read'。
而且我尝试添加userRepository.flush();
,它起作用了但是在我将隔离级别更改为SERIALIZABLE之后,脏读也发生了,为什么?
我的数据库是 Mysql.
所以当我添加 flush(); 我更改了方法的隔离;
@Override
@Transactional(isolation = Isolation.SERIALIZABLE)
public void testReadCommit1() {
log.info("testReadCommit1 begin");
User u=userRepository.findOne(1L);
u.setUserPwd("654321");
userRepository.save(u);
userRepository.flush();
log.info("testReadCommit1 sleep");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testReadCommit1 will be commit");
}
@Override
@Transactional(isolation = Isolation.SERIALIZABLE)
public void testReadCommit2() {
log.info("testUncommit2 begin");
User u=userRepository.findOne(1L);
log.info(u);
}
结果是:
User(userId=1, userName=testuser, userPhone=15888888888, userStatus=2, userPwd=654321)
为什么 SERIALIZABLE 不能防止脏读?
以下 API 文档说调用 flush() 会将所有待处理的更改刷新到数据库。因此,当您的 testReadCommit2() 方法在 3 秒后运行时,它不会读取脏记录。