我是Spring的新手,有一些基本的问题。在下面给出的一个Spring示例中,我注意到EmployeeManager是自动连接的。
问题:
1.没有给出EmployeeManager作用域,所以我假设默认作用域是Singleton,而SpringBean不是线程安全的。这一假设是正确的吗?
1.EmployeeManager定义为Servlet的一部分,可由多个线程访问。假设“Delete”方法被多个线程同时调用,值为“1”、“2”和“3”,并且为每个线程生成相同的EmployeeManager示例(因为它是单例的),将执行哪个Delete值。Spring如何处理这种情况?
@Controller
public class EditEmployeeController
{
@Autowired
private EmployeeManager employeeManager;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String listEmployees(ModelMap map)
{
map.addAttribute("employee", new EmployeeEntity());
map.addAttribute("employeeList", employeeManager.getAllEmployees());
return "editEmployeeList";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addEmployee(@ModelAttribute(value="employee") EmployeeEntity employee, BindingResult result)
{
employeeManager.addEmployee(employee);
return "redirect:/";
}
@RequestMapping("/delete/{employeeId}")
public String deleteEmplyee(@PathVariable("employeeId") Integer employeeId)
{
employeeManager.deleteEmployee(employeeId);
return "redirect:/";
}
public void setEmployeeManager(EmployeeManager employeeManager) {
this.employeeManager = employeeManager;
}
}
员工经理-
public interface EmployeeManager {
public void addEmployee(EmployeeEntity employee);
public List<EmployeeEntity> getAllEmployees();
public void deleteEmployee(Integer employeeId);
}
@Service
public class EmployeeManagerImpl implements EmployeeManager
{
@Autowired
private EmployeeDAO employeeDAO;
@Override
@Transactional
public void addEmployee(EmployeeEntity employee) {
employeeDAO.addEmployee(employee);
}
@Override
@Transactional
public List<EmployeeEntity> getAllEmployees() {
return employeeDAO.getAllEmployees();
}
@Override
@Transactional
public void deleteEmployee(Integer employeeId) {
employeeDAO.deleteEmployee(employeeId);
}
public void setEmployeeDAO(EmployeeDAO employeeDAO) {
this.employeeDAO = employeeDAO;
}
}
3条答案
按热度按时间cnjp1d6j1#
我同意上面的回答。我只想强调一点,避免争用条件的唯一方法是“@Transaction”位,这意味着Spring用一个在每个方法开始/结束时咨询TransactionManager的示例替换您的EmployeeManagerImpl。粗略地说:
现在,如果两个线程同时访问数据,它们的行为取决于您的TransactoinManager、事务隔离级别以及您的数据源与其交互的方式。在简单的情况下,您的线程将被迫等待;在其他情况下,数据库可以容忍一些并发访问。这种魔力归根结底是交易,而不是Spring。此外,在线程到达事务之前,也没有对它们的控制。如果3个不同的线程请求删除1、2和3,你不知道哪个线程会首先到达“startTransaction”。但这不应该真的有什么关系--你不妨遇到这样一种情况:周日有人要求删除“2”,周一有人要求删除“3”,周二有人要求删除“1”。你只需要一个合理一致的最终结果。
0qx6xfy62#
Spring作用域单例与线程安全无关,这是两个不同的概念。
singleton
和prototype
Bean的区别在于我们如何要求管理Bean生命周期的Spring容器返回Bean:调用Bean可以由
@autowirde
或AppContext.getBean("beanName")
触发总而言之,这完全取决于注入Bean的对象,如果它不是线程安全的,那么显然它就不是线程安全的。
要了解更多信息,请参阅Spring Bean Scopes
yws3nbqq3#
1.是的,您的假设是正确的:如果您没有在Spring中为您的Bean声明一个作用域,那么它是一个Singleton by default,这意味着它不是线程安全的。
1.由于上面的假设是正确的,对您的问题的简短回答是,Spring不做任何处理单例Bean的多线程的事情,而是由您来处理该Bean的线程安全和并发性问题。好消息是,基于
EmployeeManager
Bean的功能和您概述的“1、2、3”场景,它实际上并不重要,您实际上不需要做任何事情。对于为什么会出现这种情况,以下是一个长长的答案。与常见的误解相反,并不存在真正同时执行多个线程的情况。当然,它们可能看起来是同时执行的,但在幕后真正发生的是,JVM获取其中一个线程,执行其中的一部分,然后以最有效的方式(您会希望)开始在另一个线程上工作,然后是另一个线程,然后可能是第一个线程,等等。
这对您来说无关紧要的原因是,您的Bean没有任何状态。换句话说,您只是传递客户ID,并不关心哪个首先被删除。
现在,如果您实际上是在这些线程中传递相同的Customer对象,那么您可能会遇到问题。底线是,一般的经验法则是任何没有状态的Bean都可以是单例的。您可以阅读this article关于Spring Singletons和线程安全性的说明,以及更详细的内容。
希望这能帮上忙。