2014-10-09 170 views
1

Im在理解Spring处理hibernate实体的方式方面存在一些麻烦,并且执行了延迟加载过程。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>(); 

和agregated实体

@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(); 
    } 

什么IM guessin应该发生的是:1。 被GenericTestBean实例 2. testQuery从代理外界称为启动事务 2 loadData被调用时,代理看到活动的事务,并采取存在资源 3.数据retrieived 4. transacion关闭...

但是,这并不发生,似乎是在每个方法调用不同的事务,而实体被分离的呼叫之间,发行一个懒惰的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一个新的查询发送查询得到对象,我真的不喜欢)。

IM希望保存一个额外的查询只是为了有延迟加载,还是必须是这个样子?也许我有一些配置错了吗?

PDTA:我想查看过滤选项比重新安装选项,即使最坏的情况,就可能导致在高并发严重的性能问题。

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

的TransactionIndicatingUtil实现从这里http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1

采取和通用DA​​O是这个想法后建立 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> 
+0

显示我不太清楚,如果你正在谈论的XML代码(注释掉)从testQuery()到loadData()的内部调用,但如果你是然后:http://stackoverflow.com/a/8233459/1356423 – 2014-10-09 15:31:48

+0

Nop,实际上,当我取消注释它的作品,就像我期望它可以:它可以一些弹簧错过配置问题? – 2014-10-09 15:40:21

回答

0

测试类应该是事务太

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

我假设你applicationContext.xml文件是在您的文章

+0

它的其他选项类似的评论,如果我有的第一层是一个xhtml,而不是一个类本身,我是如何做到这一点?我的意思是,通过各种呼叫保持跨国管理(例如网络向导) – 2014-10-09 17:43:55

+0

请纠正我如果我错了。春季代理本身不是transacctional权利?它只是为每个方法调用创建并保存事务。在我们通过整个类传播事务的情况下,会话将保持数据库连接打开,这会导致明显的问题。 (也许这是愚蠢的)......这是一种重新映射到现有实体的新连接而不再执行查询的方法吗?我可以100%确定分离的实体完全不会被并发会话修改,这是否可能不知何故? – 2014-10-10 14:19:10

+0

** 1 **:任何具有'@ Transactional'的Bean都被代理包装为**添加**事务支持(方法必须是公共的,不确定是否也适用于受保护的方法)。 **两**:当你运行一个Spring App时,一个'ApplicationContext'被创建并管理所有的bean。考虑测试一个特殊的场景,你必须向Spring指出**运行**这些具有Transaction支持的'@ Test'方法,这就是为什么类有'@Transactional',其中在测试环境中,而不是在生产/运行环境中。 – 2014-10-10 15:32:08

0

JUnit测试本身不是事务性的。您的GenericTestBean bean的每种方法都是事务性的。因此,每次非事务性测试调用事务性bean的方法时,都会启动事务,执行bean方法并提交事务。由于您先后调用两个事务性方法,因此将启动两个单独的事务。

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

+0

huuuum我明白了,但在最后一个元素是jsp的情况下,我怎样才能保持事务和连接活着,以便为许多操作创建单个事务? (也是懒惰的工作) – 2014-10-09 16:35:13