JPA數據懶加載LAZY配合事務@Transactional使用(三)
上篇博文《JPA數據懶加載LAZY和實時加載EAGER(二)》講到,如果使用懶加載來調用關聯數據,必須要保證主查詢session(數據庫連接會話)的生命周期沒有結束,否則,你是無法抽取到數據的。那麽如果保證自己想要獲取關聯數據時,數據庫會話session還存在呢?今天講解一種方法,借助Spring提供的@Transactional註解來實現方法內部的操作在同一次數據庫連接中執行。需要註意的是,使用@Transactional註解,必須要保證方法通過Spring組件解析方式處理,spring代理會為方法註入事務攔截邏輯。
關於spring的事務實現原理,可以參考《Spring @Transactional工作原理
一、為實體類ProcessBlock和Node添加一對多的關聯關系。Set<Node>屬性使用懶加載方式。下面給出代碼。
@Entity(name = "nbpm_processblock") @NamedQuery(name = "ProcessBlock.findByName", query = "select p from nbpm_processblock p where p.name=?1") public class ProcessBlock implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") long id; @Column(name = "name") String name; @Column(name = "description") String description; String subClass; @OneToMany(mappedBy = "processblock", cascade = CascadeType.ALL,fetch=FetchType.LAZY) // @JoinColumn(name="processblock_id")Set<Node> nodeSet = new HashSet<Node>();
二、為查詢方法添加事務註解
@Transactional @RequestMapping(value = "/list", method = RequestMethod.GET) public String list(ModelMap model,HttpSession session) { //ProcessBlockRepository processBlock = ApplicationContextUtil.instance.getBean(ProcessBlockRepository.class); //List<ProcessBlock> list = processBlock.findByName1("主幹流程"); Map<String, Object> params = new HashMap<>(); params.put("name", "主幹流程"); List<ProcessBlock> list = ApplicationContextUtil.instance.getJpaUtil().list( "select u from simm.spring.entity.ProcessBlock u where u.name=:name", params, ProcessBlock.class); System.out.println("準備獲取懶加載數據"); Set<Node> nodes = list.get(0).getNodeSet();
三、調試一下,查看調用情況
1、測試代碼先執行List<ProcessBlock>查詢,之後輸出"準備獲取懶加載數據",最後查詢第一條ProcessBlock對應的節點集合。通過執行日誌很容易看出,懶加載的數據只有在後續的代碼邏輯中被調用後,才會生成sql查詢,在數據庫中執行獲取數據。
2、先獲取List<ProcessBlock>列表後,在來獲取第一個ProcessBlock對象對應的節點集合。調試顯示已經成功獲取到數據。
至此,測試完畢。用法很簡單,但是關於spring事務的實現這塊還是很有意思的,一次數據庫連接在線程中通過ThreadLocal變量傳遞,其生命周期靠事務攔截器來控制。這個過程在ORM框架中應該是一種比較通用的思路,在Hibernate中如此,其他框架應該也是相差無幾。感謝你的閱讀,歡迎留言討論交流!
JPA數據懶加載LAZY配合事務@Transactional使用(三)