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中如此,其他框架应该也是相差无几。感谢你的阅读,欢迎留言讨论交流!

posted @ 2017-12-22 17:42  Mr.Simm  阅读(1770)  评论(0编辑  收藏  举报