我是Spring的新手并且有一些基本的问题。在下面给出的一个Spring示例中,我注意到EmployeeManager是Autowired。
问题:
EmployeeManager是Servlet的一部分,可以被多个线程访问。 假设,"删除"方法由多个线程同时使用值" 1" " 2" &安培; " 3"并且为每个线程生成了相同的EmployeeManager实例(因为它的SINGLETON),将执行删除值。春天如何处理这个条件?
@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;
}
}
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;
}
}
答案 0 :(得分:0)
我同意上述答案。只是想强调,对竞争条件的唯一保护是“@Transactional”位,这意味着spring用一个在每个方法的开头/结尾处查询transactionManager的实例替换你的EmployeeManagerImpl。滔滔不绝地说:
public void addEmployee(EmployeeEntity employee) {
transactionManager.startTransaction();
employeeDAO.addEmployee(employee);
transactionManager.endTransaction();
// Just a rough outline; more accurately there should be 'finally' and rollback
}
...
现在,如果2个线程同时访问数据,它们的行为取决于您的transactoinManager,事务隔离级别以及DataSource与之交互的方式。在简单的情况下,你的线程将被迫等待;在其他情况下,数据库可以容忍一些并发访问。这种魔力归结为交易,而不是春天。 在到达事务之前,线程也无法控制。如果3个不同的线程要求删除1,2和3,则无法确定哪个线程将首先进入“startTransaction”。但这应该不重要 - 你可能也有这样的情况,有人要求在星期日删除“2”,其他人要求在星期一删除“3”,而其他人要求在星期二删除“1”。你只需要一个合理的一致的最终结果。
答案 1 :(得分:0)
Spring范围单例与线程安全无关,这是两个不同的概念。
singleton
和prototype
bean之间的区别在于,我们如何要求管理bean生命周期的spring容器返回bean:
可以通过@autowirde
或AppContext.getBean("beanName")
来触发调用bean
总之,如果它不是线程安全的,那么一切都取决于注入bean的对象,显然,它不是线程安全的。
要了解更多Spring Bean Scopes
答案 2 :(得分:-1)
是的,你的假设是正确的:如果你没有在Spring中为你的bean声明一个范围,它就是Singleton by default,这意味着它不是线程安全的。
由于上面的假设是正确的,对你的问题的简短回答是Spring没有做任何事情来处理单例bean的多线程,因此由你来处理线程安全和并发问题那个豆子。好消息是基于你的EmployeeManager
bean的作用以及&#34; 1,2,3&#34;你概述的情况,它实际上并不重要,你也不必做任何事情。
以下是为什么会出现这种情况的长期答案。与常见的误解相反,没有多个线程同时真正执行的事情。当然,它们似乎可能同时执行,但真正发生的事情是JVM采用其中一个线程,执行其中的一部分,然后以最有效的方式执行(您希望)开始处理另一个线程,然后另一个线程,然后可能是第一个,等等。
这对你来说并不重要的原因是因为你的bean 没有任何状态。换句话说,您只是传递客户ID,而您并不关心哪些会被删除。
现在,如果您实际在这些线程中传递了SAME客户对象,那么您可能会遇到问题。最重要的是,一般的经验法则是任何没有状态的bean都可以是单身。您可以阅读关于Spring单例和线程安全的this article,其中详细解释了这一点。
希望这有帮助。