java - Spring 事务内的 Hibernate 实体生命周期和 session 生命周期

标签 java spring hibernate jpa-2.0

我在理解 spring 处理 hibernate 实体和延迟加载过程的方式时遇到一些困难。

因此,对于这种情况,我们必须实体

@Entity
public class EntityA{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;


    @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.REFRESH})
    private Collection<EntityB> bss= new ArrayList<EntityB>();

和聚合实体

@Entity
public class EntityB{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;


    @ManyToMany(mappedBy="bss")
    private Collection<EntityA> ass= new ArrayList<EntityA>();

然后我有一个简单的业务类标记为事务性:

@Component
@Scope("session")
@Transactional(propagation=Propagation.TRIED_EVERY_SINGLE_ONE)
public class GenericTestBean {

    private EntityA entityA;

    @Autowired
    private IGenericDAO genericDAO;


    public GenericTestBean() {
        System.out.println("bean creado!");
    }

    public void testQuery() {
        entityA= genericDAO.get(EntityA.class, 1l);
        System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
        System.out.println("is element atached? :" + genericDAO.isAtached(entityA));
        //this.loadData();

    }

    public void loadData(){

        System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
        System.out.println("is element atached? :" + genericDAO.isAtached(currentCompany));

        System.out.println(entityA.getBss.size());
    }

}

和一个简单的测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "applicationContext.xml" })
@WebAppConfiguration
public class EntityQueryTest {

//  @Autowired
//  private SessionFactory sessionFactory;

    @Autowired
    GenericTestBean genericTestBean;


    @Test
    public void consultarCompania(){

        genericTestBean.testQuery();
        genericTestBean.loadData();
    }

我猜应该发生的是: 1. GenericTestBean被实例化 2. 从代理外部调用 testQuery 启动事务 2. loadData 被调用,代理看到 Activity 事务,并获取现有资源 3. 数据检索 4. 交易已结束...

但这并没有发生,每个方法调用中似乎有两个不同的事务,并且实体在调用之间分离,发出惰性初始化异常。

实际输出日志是这样的:

bean creado!  --here the object get created
Hibernate: select company0_.companyId as ..... --here the first query get executed
[com.pe.controlLines.data.dao.GenericTestBean.testQuery] --here we check the name for the transaction
is element atached? :true --and see if the element is attached to the session
[com.pe.controlLines.data.dao.GenericTestBean.loadData]  --this is in the second method call (with a different transaction name :O )
is element atached? :false --both now, the same element get detached

我尝试重新附加实体,但这给了我一个对数据库的新查询(发送了对表 EntityA 的新查询以及获取对象的查询,我真的不喜欢)。

我希望保存一个额外的查询只是为了延迟加载,还是必须这样?或者我可能有一些配置错误?

Pdta:我认为 View 过滤选项比重新附加选项更糟糕,它可能会在高并发下导致严重的性能问题。

任何人都可以澄清方法调用之间的事务上下文的行为,以及它如何与 session 和实体状态相关吗?

TransactionIndicatingUtil 实现取自此处 http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1

通用的 dao 是按照这个想法构建的 General or specific DAO to record delivery with information from multiple tables?

更新

如果有一些用处,这里是 spring 配置文件

<context:component-scan base-package="xxxxxx" />

    <context:annotation-config />
    <context:spring-configured />

    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <!-- Data Source Declaration -->
    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />

        <property name="url" value="jdbc:mysql://localhost:3306/xxxx" />

        <property name="username" value="xxxxx" />
        <property name="password" value="xxxxx" />
        <property name="initialSize" value="2" />
        <property name="minIdle" value="0" />
        <property name="minEvictableIdleTimeMillis" value="120000" />
        <property name="maxActive" value="20" />
        <property name="maxWait" value="5000" />
    </bean>

    <!-- Session Factory Declaration <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> -->
    <!-- Session Factory Declaration -->
    <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.xx.xx.xx.xx</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.search.default.directory_provider">filesystem</prop>
                <prop key="hibernate.search.default.indexBase">C:/DEVELOPMENT/lucene/indexes</prop>


            </props>
        </property>
    </bean>

    <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager"/>

    <!-- Transaction Manager is defined -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="SessionFactory"/>
    </bean>

最佳答案

测试类也应该是事务性的

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "applicationContext.xml" })
@Transactional // <--- add
public class EntityQueryTest {

我假设您的 applicationContext.xml 文件是您帖子中显示的 XML 代码

关于java - Spring 事务内的 Hibernate 实体生命周期和 session 生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26282012/

相关文章:

java - Spring Security 自定义身份验证提供程序总是导致错误的客户端凭据

java - 使用 basicauth 的 Ajax CORS 请求在浏览器上给出 401 错误

java - oracle模式下h2数据库jar升级后select语句失败

java - ImageView.setImageDrawable 在 LANDSCAPE 模式下不起作用

java - Spring getBeanNamesForType 工作不正常

java - 如何防止在Spring Boot单元测试中执行import.sql

java - 如何使用hibernate查询语言查找两个时间戳之间的差异

java - 在 API below 11 中移除 ActionBar

java - 在 Java 中克隆迭代器?

java - Errors/BindingResult 参数应在模型属性、@RequestBody 或 @RequestPart 参数之后立即声明