Java 在Spring事务中休眠实体生命周期和会话生命周期
我在理解spring处理hibernate实体的方式以及延迟加载过程方面遇到了一些困难 所以在这种情况下,我们必须考虑实体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
@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 {