Java 在Spring事务中休眠实体生命周期和会话生命周期

Java 在Spring事务中休眠实体生命周期和会话生命周期,java,spring,hibernate,jpa-2.0,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}) pr

我在理解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>();
和一个简单的测试类

@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时,代理会看到活动事务,并获取现有资源 3.检索数据 4.交易已关闭

但这并没有发生,每个方法调用中似乎有两个不同的事务,实体在调用之间分离,发出一个lazy init异常

实际输出日志如下所示:

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:我认为视图过滤器选项甚至比重新连接选项更糟糕,它可能会在高并发性下导致严重的性能问题

有谁能澄清方法调用之间事务上下文的行为,以及它如何与会话和实体状态相关

TransactionIndicatingUtil实现从此处开始

通用dao就是根据这个想法构建的

更新

为了便于使用,下面是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>

com.xx.xx.xx.xx
更新
org.hibernate.dialogue.mysqldialogue
真的
文件系统
C:/DEVELOPMENT/lucene/index

JUnit测试本身不是事务性的。GenericTestBean的每个方法都是事务性的。因此,每次非事务性测试调用事务bean的方法时,都会启动事务,执行bean方法,并提交事务。因为您连续调用了两个事务方法,所以启动了两个单独的事务


如果测试方法本身是事务性的,那么将为测试方法启动一个事务,并且(默认情况下),这两个bean方法将在由测试启动的现有事务的上下文中执行。事务将在测试方法返回后提交。

测试类也应该是事务类

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

@事务性//我不太确定您是否在谈论从testQuery()到loadData()的(注释掉的)内部调用,但如果您是这样的话:不,实际上,当我取消注释它时,它会像我预期的那样工作:可能是某个spring未命中配置问题吗?嗯,我明白了,但在这种情况下,我拥有的最后一个元素是jsp,如何使事务和连接保持活动状态,以便在多个操作中使用单个事务?(也是懒惰的工作)它的注释与另一个选项类似,如果我的第一层是一个xhtml,而不是一个类本身,我是如何做到这一点的?我的意思是,要通过各种调用(例如web向导)保持跨国管理,请纠正我的错误。spring代理本身不是跨国家的吗?它只是为每个方法调用创建并保存事务。在我们通过整个类传播事务的情况下,会话将保持数据库连接打开,这会导致明显的问题。(可能这很愚蠢)…有一种方法可以将新连接重新映射到现有实体,而无需再次执行查询吗?我可以100%确定分离的实体根本不会被并发会话修改,这有可能吗?第一:任何具有
@Transactional
的bean都使用代理进行包装,以添加事务支持(方法必须是公共的,不确定是否也适用于受保护的对象)二:当运行一个Spring应用程序时,创建一个“代码>应用程序上下文< /代码>并管理所有的bean。考虑测试一个特殊的场景,在这里你必须用Spring来运行Spring运行这些代码> @测试< /COD>方法,这就是为什么这个类有<代码> @事务性< /代码>,在测试环境中,而不是在生产/R中。运行环境。三个用
@Transactional
注释的bean都不知道它们是否在测试或生产环境中工作。四个:Spring处理数据源的资源管理,打开、关闭连接,因此不存在泄漏风险。五个:阅读Spring关于Transaction的参考文档离子。
<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 {