【发布时间】:2020-09-12 20:18:38
【问题描述】:
这里的问题是两个线程同时执行第一个SELECT。考虑到saveUser 是@Transactional 方法,第二个线程不应该等到第一个线程提交/回滚吗?
代码:
@SpringBootApplication
public class TestApp
{
public static void main(String[] args)
{
ConfigurableApplicationContext app = SpringApplication.run(TestApp.class, args);
UserService us = (UserService) app.getBean("userService");
Thread t1 = new Thread(() -> us.saveUser("email@email.com"));
t1.setName("Thread #1");
t1.start();
Thread t2 = new Thread(() -> us.saveUser("email@email.com"));
t2.setName("Thread #2");
t2.start();
}
}
@Repository
public interface UserRepository extends CrudRepository<UserService.User, Long>
{
public UserService.User getByEmail(String email);
}
@AllArgsConstructor
@Service
public class UserService
{
private final UserRepository userRepository;
@Transactional
public boolean saveUser(String email)
{
if (userRepository.getByEmail(email) != null)
{
System.out.println("User already exists");
return false;
}
System.out.println(Thread.currentThread().getName() + ": User doesn't exists, sleeping..");
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
User user = new User();
user.email = email;
System.out.println(Thread.currentThread().getName() + ": Saving user..");
user = userRepository.save(user);
return user.id > 0;
}
@Table("user")
public static class User
{
@Id
public long id;
public String email;
}
}
输出:
Thread #1: User doesn't exists, sleeping..
Thread #2: User doesn't exists, sleeping..
Thread #1: Saving user..
Thread #2: Saving user..
Exception in thread "Thread #2" org.springframework.data.relational.core.conversion.DbActionExecutionException: Failed to execute DbAction.InsertRoot(entity=testapp.UserService$User@3ce548a)
[...]
Caused by: org.springframework.dao.DuplicateKeyException: PreparedStatementCallback;
[...]
表格:
create table user (`id` int primary key auto_increment, `email` varchar(50) unique);
【问题讨论】:
-
没有,为什么要呢?它们只是 2 个单独的交易。为什么数据库应该只允许单个事务?仅当您使用悲观锁定(如果您的数据库支持它)和/或序列化事务时,才会出现这种情况。然而,两者都是性能杀手,因为它只允许对数据库进行串行访问。
标签: spring spring-boot spring-data-jpa spring-data spring-transactions