HibernateTemplate在事务、非事务、配置OpenSessionInViewFilter等不同情况获取Session,总结如下:
1、事务在Controller处配置即可,一般情况无需在业务类中配置事务,除非业务类有不同的事务传播行为或隔离级别。
2、从定义了事务的方法为入口,方法里树形调用的方法(无论是否配置了事务)都在同一事务里。
3、同一事务下的方法使用同一Session。
4、在同一session下,相同Id的对象只有一个实例。
5、对象的持久态只在同一的session中有效。
6、配置了OpenSessionInViewFilter,同一连接使用同一Session,如果无事务,此Session为readonly,需手动设置session.setFlushMode(FlushMode.AUTO); 才能进行增删改。
具体实例应用了业务类SpringHibernateEmployeeScroll和Controller类EmployeeManageController,具体代码如下
@Named("springHibernateEmployeeScroll")
<a>@Transactional</a> ①
public class SpringHibernateEmployeeScroll implements EmployeeScroll {
@Resource(name="hibernateTemplate")
HibernateTemplate hibernateTemplate;
@Override
public void enroll(Employee employee) {
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
System.out.print("enroll:session"+session.toString());
hibernateTemplate.save(employee);
}
@Override
public Employee get(Object id) {
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
Employee employee = (Employee) session.get(Employee.class, (Serializable) id);
System.out.print("get:session"+session.toString());
return employee;
}
@Override
public Object getIdentifier(Employee employee) {
Object id=null;
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
id=session.getIdentifier(employee);
System.out.print("getIdentifier:session"+session.toString());
return id;
}
}
@Controller
<a>@Transactional</a> ②
@RequestMapping("/hr")
public class EmployeeManageController {
@Resource(name="springHibernateEmployeeScroll")
EmployeeScroll employeeScroll;
@RequestMapping("/employeeeditshow")
public String employeeEdit(Model model){
int code=(int) Math.round(Math.random() * (999999 - 100000) + 100000);
model.addAttribute("employeeCode", code);
model.addAttribute("employeeId","");
return "hr/employeeEdit";
}
@RequestMapping("/employeeeditSave")
public String employeeSave(Model model,Employee employee){
employeeScroll.enroll(employee); ③
Employee employeeMessage=employeeScroll.get(1); ④
employeeMessage=employeeScroll.get(1); ⑤
employeeMessage=employeeScroll.get(2); ⑥
id=employeeScroll.getIdentifier(employee); ⑦
employeeMessage=employeeScroll.get(id); ⑧
model.addAttribute("employeeId", id);
model.addAttribute("employee", employeeMessage);
return "hr/employeeDetail";
}
}
OpenSessionInViewFilter在web.xml的配置:
<filter>
<filter-name>hibernateSessionFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateSessionFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
具体验证过程与结果(通过单点调试模式,查看对象的内存地址,断点在每个方法的返回操作处):
1、在事务下,同时在web.xml不配置OpenSessionInViewFilter
前置条件:1)①②不注释掉 ; 2) Web.xml不配置OpenSessionInViewFilter
步骤 | Employee/(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | Employee(id=132) | SessionImpl(id=133) | |
④get(1) | Employee(id=134) | SessionImpl(id=133) | |
⑤get(1) | Employee(id=134) | SessionImpl(id=133) | |
⑥get(2) | Employee(id=137) | SessionImpl(id=133) | |
⑦getIdentifier | Employee(id=132) | SessionImpl(id=133) | |
⑧get(id) | Employee(id=132) | SessionImpl(id=133) |
2、业务类对象在事务下,Controller(Action)类对象不在事务下,在web.xml不配置OpenSessionInViewFilter
前置条件:1)①不注释掉,②注释掉 ; 2) Web.xml不配置OpenSessionInViewFilter
步骤 | Employee(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | Employee(id=80) | SessionImpl(id=82) | |
④get(1) | Employee(id=106) | SessionImpl(id=105) | |
⑤get(1) | Employee(id=112) | SessionImpl(id=111) | |
⑥get(2) | Employee(id=116) | SessionImpl(id=115) | |
⑦getIdentifier | 报错:org.hibernate.TransientObjectException: The instance was not associated with this session | ||
⑧get(id) |
3、业务类对象不在事务下,Controller(Action)类对象在事务下,在web.xml不配置OpenSessionInViewFilter
前置条件:1)①注释掉,②不注释掉 ; 2) Web.xml不配置OpenSessionInViewFilter
步骤 | Employee(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | Employee(id=82) | SessionImpl(id=87) | |
④get(1) | Employee(id=107) | SessionImpl(id=87) | |
⑤get(1) | Employee(id=107) | SessionImpl(id=87) | |
⑥get(2) | Employee(id=109) | SessionImpl(id=87) | |
⑦getIdentifier | Employee(id=82) | SessionImpl(id=87) | |
⑧get(id) | Employee(id=82) | SessionImpl(id=87) |
4、业务类对象在事务下,Controller(Action)类对象不在事务下,在web.xml配置OpenSessionInViewFilter
前置条件:1)①不注释掉,②注释掉 ; 2) Web.xml配置OpenSessionInViewFilter
步骤 | Employee(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | Employee(id=82) | SessionImpl(id=84) | |
④get(1) | Employee(id=109) | SessionImpl(id=84) | |
⑤get(1) | Employee(id=109) | SessionImpl(id=84) | |
⑥get(2) | Employee(id=116) | SessionImpl(id=84) | |
⑦getIdentifier | Employee(id=82) | SessionImpl(id=84) | |
⑧get(id) | Employee(id=82) | SessionImpl(id=84) |
5、在非事务下,同时在Web.xml不配置OpenSessionInViewFilter
前置条件:1) ①②都注释掉 ; 2) Web.xml不配置OpenSessionInViewFilter
步骤 | Employee(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | 执行getCurrentSession报错误:org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here | ||
④get(1) | |||
⑤get(1) | |||
⑥get(2) | |||
⑦getIdentifier | |||
⑧get(id) |
6、在非事务下,同时在web.xml配置OpenSessionInViewFilter
前置条件:1)①②都注释掉 ; 2) Web.xml配置OpenSessionInViewFilter
步骤 | Employee(内存地址) | SessionImpl(内存地址) | 说明 |
③enroll | 执行save报错误:org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): | ||
④get(1) | |||
⑤get(1) | |||
⑥get(2) | |||
⑦getIdentifier | |||
⑧get(id) |
session.setFlushMode(FlushMode.AUTO);