在Hibernate中选择查询时阻止插入

时间:2010-10-10 17:42:32

标签: hibernate select insert one-to-one

我是Hibernate的新手。我有一个问题,当我尝试运行选择查询说

"from Foo where Foo.some_id=2"

(使用Hibernate模板)然后Hibernate也尝试将记录插入到表'Foo2'中,该表与Foo表具有一对二的关联

Bean Foo

class Foo{
int id;
....
Foo2 foo2;
}

Foo.hbm.xml

...
<one-to-one name="foo2" class="Foo2" property-ref="foo"
  constrained="false" cascade="save-update"></one-to-one>
...

Bean Foo2

Class Foo2{
...
private int foo;
...
}

Foo2.hbm.xml

...
<property name="foo" column="foo_id"/>
...

用法

 DetachedCriteria criteria = createDetachedCriteria();
  criteria.add(Restrictions.eq("some_id", value));
  return getHibernateTemplate().findByCriteria(criteria);

    public List<SnsUser> getAllSnsUsersByProperty(String prop, Object val){
            String query = "from SnsUser su where su." + prop + " =:" + prop;
            return executeQuery(query, new String[]{prop}, new Object[]{val});
    }

    public static void main(String[] args) { //WORKING
    String query = "from SnsUser su where su.blessUserId=1";
    Session session = Utility.getSessionFactory().openSession();
    List l = new SnsUserDaoImpl().getQRes(query);
    System.out.println(l);
    session.close();
    }
public List<E> executeQuery(String queryString, String []param, Object [] val){
//NOT WORKING
        return getHibernateTemplate().findByNamedParam(queryString, param, val);
    }   

这就是我得到的......

Hibernate: select * from bless_aggregation.sns_user this_ left outer join bless_aggregation.sns_authenticator snsauthent2_ on this_.sns_uid=snsauthent2_.sns_uid 
where this_.bless_uid=?
Hibernate: select * from bless_aggregation.bless_user blessuser0_ where blessuser0_.bless_uid=?
Hibernate: select * from bless_aggregation.sns_user snsuser0_ left outer join bless_aggregation.sns_authenticator snsauthent1_ on 
snsuser0_.sns_uid=snsauthent1_.sns_uid where snsuser0_.bless_uid=?

Hibernate: insert into bless_aggregation.sns_authenticator (key, value, sns_uid) values (?, ?, ?)
1079 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
1079 [main] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, value, sns_uid) values (null, null, 1)' at line 1

1 个答案:

答案 0 :(得分:5)

我的猜测是你在会话中有待更改(某些Foo2实例等待插入),默认情况下,Hibernate会在运行查询之前刷新会话,以便为您提供非陈旧的结果。这在文档的以下部分中进行了解释:

  

10.10. Flushing the Session

     

有时会话会执行   需要同步的SQL语句   JDBC连接的状态与   内存中保存的对象状态。这个   进程,称为刷新,发生   默认为以下几点:

     
      在某些查询执行之前
  •   
  • 来自org.hibernate.Transaction.commit()
  •   
  • 来自Session.flush()
  •   
     

SQL语句发布于   以下顺序:

     
      
  1. 所有实体插入的顺序与相应的对象相同   使用Session.save()
  2. 保存   
  3. 所有实体更新
  4.   
  5. 所有集合删除
  6.   
  7. 所有集合元素删除,更新和插入
  8.   
  9. 所有收集插入
  10.   
  11. 所有实体删除的顺序与对应的对象相同   已使用Session.delete()
  12. 删除         

    一个例外是对象使用   插入本机ID时生成   他们得救了。

         

    除非您明确flush(),   绝对没有保证   关于Session何时执行   JDBC调用,只有其中的顺序   他们被处决了。 然而,Hibernate   确保保证   Query.list(..)永远不会回来   陈旧或不正确的数据

         

    可以更改默认值   行为使得冲洗发生得更少   频繁即可。 FlushMode课程   定义了三种不同的模式:仅   在提交时刷新   使用Hibernate Transaction API ,   使用自动冲洗   解释常规,或从不冲洗   除非明确调用flush()。   最后一种模式很有用   运行工作单元,其中一个会话   保持打开状态并断开连接   很长时间(见第11.3.2节,   “扩展会话和自动   版本”)。

    sess = sf.openSession();
    Transaction tx = sess.beginTransaction();
    sess.setFlushMode(FlushMode.COMMIT);
    
         

    //允许查询返回陈旧状态

    Cat izi = (Cat) sess.load(Cat.class, id);
    izi.setName(iznizi);
    
    // might return stale data
    sess.find("from Cat as cat left outer join cat.kittens kitten");
    
    // change to izi is not flushed!
    ...
    tx.commit(); // flush occurs
    sess.close();
    
         

    在刷新期间,可能会发生异常   (例如,如果DML操作违反了   约束)。自处理异常以来   涉及到一些了解   Hibernate的事务行为,我们   在第11章,交易中讨论它   和并发。

因此,如上所述并在代码段中显示,请尝试使用FlushMode.COMMIT

请注意,如果您使用identity生成器,这将无济于事,Hibernate将在save时写入数据库。

另请注意,FlushMode的{​​{1}}只是提示,但行为并未得到严格保证。